molnos 1.2.1 → 1.2.2

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/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.1
1
+ 1.2.2
@@ -1,11 +1,11 @@
1
1
  // MolnOS Core - See LICENSE file for copyright and license details.
2
- import re,{createHash as Ro,createHmac as jo,scryptSync as vs,randomBytes as ws,createCipheriv as Ss,createDecipheriv as bs}from"crypto";import{URL as xs}from"url";var Ye=class extends Error{constructor(t){super(t),this.name="ValidationError",this.message=t||"Validation did not pass",this.cause={statusCode:400}}};import{existsSync as us,readFileSync as ds}from"node:fs";var ee=class{config={};options=[];validators=[];autoValidate=!0;constructor(t){let e=t?.configFilePath,r=t?.args||[],s=t?.config||{};this.options=t?.options||[],this.validators=t?.validators||[],t?.autoValidate!==void 0&&(this.autoValidate=t.autoValidate),this.config=this.createConfig(e,r,s)}deepMerge(t,e){let r={...t};for(let s in e)e[s]!==void 0&&(e[s]!==null&&typeof e[s]=="object"&&!Array.isArray(e[s])&&s in t&&t[s]!==null&&typeof t[s]=="object"&&!Array.isArray(t[s])?r[s]=this.deepMerge(t[s],e[s]):e[s]!==void 0&&(r[s]=e[s]));return r}setValueAtPath(t,e,r){let s=e.split("."),i=t;for(let n=0;n<s.length-1;n++){let a=s[n];!(a in i)||i[a]===null?i[a]={}:typeof i[a]!="object"&&(i[a]={}),i=i[a]}let o=s[s.length-1];i[o]=r}getValueAtPath(t,e){let r=e.split("."),s=t;for(let i of r){if(s==null)return;s=s[i]}return s}createConfig(t,e=[],r={}){let s={};for(let a of this.options)a.defaultValue!==void 0&&this.setValueAtPath(s,a.path,a.defaultValue);let i={};if(t&&us(t))try{let a=ds(t,"utf8");i=JSON.parse(a),console.log(`Loaded configuration from ${t}`)}catch(a){console.error(`Error reading config file: ${a instanceof Error?a.message:String(a)}`)}let o=this.parseCliArgs(e),n=this.deepMerge({},s);return n=this.deepMerge(n,i),n=this.deepMerge(n,r),n=this.deepMerge(n,o),n}parseCliArgs(t){let e={},r=t[0]?.endsWith("node")||t[0]?.endsWith("node.exe")?2:0;for(;r<t.length;){let s=t[r++],i=this.options.find(o=>o.flag===s);if(i)if(i.isFlag)this.setValueAtPath(e,i.path,!0);else if(r<t.length&&!t[r].startsWith("-")){let o=t[r++];if(i.parser)try{o=i.parser(o)}catch(n){console.error(`Error parsing value for ${i.flag}: ${n instanceof Error?n.message:String(n)}`);continue}if(i.validator){let n=i.validator(o);if(n!==!0&&typeof n=="string"){console.error(`Invalid value for ${i.flag}: ${n}`);continue}if(n===!1){console.error(`Invalid value for ${i.flag}`);continue}}this.setValueAtPath(e,i.path,o)}else console.error(`Missing value for option ${s}`)}return e}validate(){for(let t of this.validators){let e=this.getValueAtPath(this.config,t.path),r=t.validator(e,this.config);if(r===!1)throw new Ye(t.message);if(typeof r=="string")throw new Ye(r)}}get(){return this.autoValidate&&this.validate(),this.config}getValue(t,e){let r=this.getValueAtPath(this.config,t);return r!==void 0?r:e}setValue(t,e){if(typeof e=="object"&&e!==null&&!Array.isArray(e)){let r=this.getValueAtPath(this.config,t)||{};if(typeof r=="object"&&!Array.isArray(r)){let s=this.deepMerge(r,e);this.setValueAtPath(this.config,t,s);return}}this.setValueAtPath(this.config,t,e)}getHelpText(){let t=`Available configuration options:
2
+ import re,{createHash as jo,createHmac as $o,scryptSync as ws,randomBytes as Ss,createCipheriv as bs,createDecipheriv as xs}from"crypto";import{URL as Cs}from"url";var Ye=class extends Error{constructor(t){super(t),this.name="ValidationError",this.message=t||"Validation did not pass",this.cause={statusCode:400}}};import{existsSync as ds,readFileSync as ps}from"node:fs";var ee=class{config={};options=[];validators=[];autoValidate=!0;constructor(t){let e=t?.configFilePath,r=t?.args||[],s=t?.config||{};this.options=t?.options||[],this.validators=t?.validators||[],t?.autoValidate!==void 0&&(this.autoValidate=t.autoValidate),this.config=this.createConfig(e,r,s)}deepMerge(t,e){let r={...t};for(let s in e)e[s]!==void 0&&(e[s]!==null&&typeof e[s]=="object"&&!Array.isArray(e[s])&&s in t&&t[s]!==null&&typeof t[s]=="object"&&!Array.isArray(t[s])?r[s]=this.deepMerge(t[s],e[s]):e[s]!==void 0&&(r[s]=e[s]));return r}setValueAtPath(t,e,r){let s=e.split("."),i=t;for(let n=0;n<s.length-1;n++){let a=s[n];!(a in i)||i[a]===null?i[a]={}:typeof i[a]!="object"&&(i[a]={}),i=i[a]}let o=s[s.length-1];i[o]=r}getValueAtPath(t,e){let r=e.split("."),s=t;for(let i of r){if(s==null)return;s=s[i]}return s}createConfig(t,e=[],r={}){let s={};for(let a of this.options)a.defaultValue!==void 0&&this.setValueAtPath(s,a.path,a.defaultValue);let i={};if(t&&ds(t))try{let a=ps(t,"utf8");i=JSON.parse(a),console.log(`Loaded configuration from ${t}`)}catch(a){console.error(`Error reading config file: ${a instanceof Error?a.message:String(a)}`)}let o=this.parseCliArgs(e),n=this.deepMerge({},s);return n=this.deepMerge(n,i),n=this.deepMerge(n,r),n=this.deepMerge(n,o),n}parseCliArgs(t){let e={},r=t[0]?.endsWith("node")||t[0]?.endsWith("node.exe")?2:0;for(;r<t.length;){let s=t[r++],i=this.options.find(o=>o.flag===s);if(i)if(i.isFlag)this.setValueAtPath(e,i.path,!0);else if(r<t.length&&!t[r].startsWith("-")){let o=t[r++];if(i.parser)try{o=i.parser(o)}catch(n){console.error(`Error parsing value for ${i.flag}: ${n instanceof Error?n.message:String(n)}`);continue}if(i.validator){let n=i.validator(o);if(n!==!0&&typeof n=="string"){console.error(`Invalid value for ${i.flag}: ${n}`);continue}if(n===!1){console.error(`Invalid value for ${i.flag}`);continue}}this.setValueAtPath(e,i.path,o)}else console.error(`Missing value for option ${s}`)}return e}validate(){for(let t of this.validators){let e=this.getValueAtPath(this.config,t.path),r=t.validator(e,this.config);if(r===!1)throw new Ye(t.message);if(typeof r=="string")throw new Ye(r)}}get(){return this.autoValidate&&this.validate(),this.config}getValue(t,e){let r=this.getValueAtPath(this.config,t);return r!==void 0?r:e}setValue(t,e){if(typeof e=="object"&&e!==null&&!Array.isArray(e)){let r=this.getValueAtPath(this.config,t)||{};if(typeof r=="object"&&!Array.isArray(r)){let s=this.deepMerge(r,e);this.setValueAtPath(this.config,t,s);return}}this.setValueAtPath(this.config,t,e)}getHelpText(){let t=`Available configuration options:
3
3
 
4
4
  `;for(let e of this.options)t+=`${e.flag}${e.isFlag?"":" <value>"}
5
5
  `,e.description&&(t+=` ${e.description}
6
6
  `),e.defaultValue!==void 0&&(t+=` Default: ${JSON.stringify(e.defaultValue)}
7
7
  `),t+=`
8
- `;return t}};var te={int:t=>{let e=t.trim();if(!/^[+-]?\d+$/.test(e))throw new Error(`Cannot parse "${t}" as an integer`);let r=Number.parseInt(e,10);if(Number.isNaN(r))throw new Error(`Cannot parse "${t}" as an integer`);return r},float:t=>{let e=t.trim();if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(e)){if(e==="Infinity"||e==="-Infinity")return e==="Infinity"?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY;throw new Error(`Cannot parse "${t}" as a number`)}let r=Number.parseFloat(e);if(Number.isNaN(r))throw new Error(`Cannot parse "${t}" as a number`);return r},boolean:t=>{let e=t.trim().toLowerCase();if(["true","yes","1","y"].includes(e))return!0;if(["false","no","0","n"].includes(e))return!1;throw new Error(`Cannot parse "${t}" as a boolean`)},array:t=>t.split(",").map(e=>e.trim()),json:t=>{try{return JSON.parse(t)}catch{throw new Error(`Cannot parse "${t}" as JSON`)}}};import{EventEmitter as Cs}from"events";var Ct=class extends Error{constructor(t){super(),this.name="ValidationError",this.message=t,this.cause={statusCode:400}}};import{existsSync as ps,readFileSync as hs}from"fs";var kt=class{config;defaults={configFilePath:"mikromail.config.json",args:[]};constructor(t){let e=t?.config||{},r=t?.configFilePath||this.defaults.configFilePath,s=t?.args||this.defaults.args;this.config=this.create(r,s,e)}create(t,e,r){let s={host:"",user:"",password:"",port:465,secure:!0,debug:!1,maxRetries:2,skipEmailValidation:!1,skipMXRecordCheck:!1},i={};if(ps(t))try{let n=hs(t,"utf8");i=JSON.parse(n),console.log(`Loaded configuration from ${t}`)}catch(n){console.error(`Error reading config file: ${n instanceof Error?n.message:String(n)}`)}let o=this.parseCliArgs(e);return{...s,...r,...i,...o}}parseCliArgs(t){let e={};for(let r=2;r<t.length;r++)switch(t[r]){case"--host":r+1<t.length&&(e.host=t[++r]);break;case"--user":r+1<t.length&&(e.user=t[++r]);break;case"--password":r+1<t.length&&(e.password=t[++r]);break;case"--port":if(r+1<t.length){let i=Number.parseInt(t[++r],10);Number.isNaN(i)||(e.port=i)}break;case"--secure":e.secure=!0;break;case"--debug":e.debug=!0;break;case"--retries":if(r+1<t.length){let i=Number.parseInt(t[++r],10);Number.isNaN(i)||(e.maxRetries=i)}break}return e}validate(){if(!this.config.host)throw new Ct("Host value not found")}get(){return this.validate(),this.config}};import{promises as ms}from"dns";function ye(t){try{let[e,r]=t.split("@");if(!e||e.length>64||e.startsWith(".")||e.endsWith(".")||e.includes("..")||!/^[a-zA-Z0-9!#$%&'*+\-/=?^_`{|}~.]+$/.test(e)||!r||r.length>255)return!1;if(r.startsWith("[")&&r.endsWith("]")){let i=r.slice(1,-1);return i.startsWith("IPv6:")?!0:/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/.test(i)}if(r.startsWith(".")||r.endsWith(".")||r.includes(".."))return!1;let s=r.split(".");if(s.length<2||s[s.length-1].length<2)return!1;for(let i of s)if(!i||i.length>63||!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(i))return!1;return!0}catch{return!1}}async function fs(t){try{let e=await ms.resolveMx(t);return!!e&&e.length>0}catch{return!1}}async function At(t){try{let e=t.split("@")[1];return e?await fs(e):!1}catch{return!1}}import{Buffer as ve}from"buffer";import Ze from"crypto";import gs from"net";import ys from"os";import It from"tls";var Et=class{config;socket;connected;lastCommand;serverCapabilities;secureMode;retryCount;maxEmailSize=10485760;constructor(t){this.config={host:t.host,user:t.user,password:t.password,port:t.port??(t.secure?465:587),secure:t.secure??!0,debug:t.debug??!1,timeout:t.timeout??1e4,clientName:t.clientName??ys.hostname(),maxRetries:t.maxRetries??3,retryDelay:t.retryDelay??1e3,skipAuthentication:t.skipAuthentication||!1,skipEmailValidation:t.skipEmailValidation||!1,skipMXRecordCheck:t.skipMXRecordCheck||!1},this.socket=null,this.connected=!1,this.lastCommand="",this.serverCapabilities=[],this.secureMode=this.config.secure,this.retryCount=0}log(t,e=!1){this.config.debug&&console.log(`${e?"SMTP ERROR: ":"SMTP: "}${t}`)}async connect(){return new Promise((t,e)=>{let r=setTimeout(()=>{e(new Error(`Connection timeout after ${this.config.timeout}ms`)),this.socket?.destroy()},this.config.timeout);try{this.config.secure?this.createTLSConnection(r,t,e):this.createPlainConnection(r,t,e)}catch(s){clearTimeout(r),this.log(`Failed to create socket: ${s.message}`,!0),e(s)}})}createTLSConnection(t,e,r){this.socket=It.connect({host:this.config.host,port:this.config.port,rejectUnauthorized:!0,minVersion:"TLSv1.2",ciphers:"HIGH:!aNULL:!MD5:!RC4"}),this.setupSocketEventHandlers(t,e,r)}createPlainConnection(t,e,r){this.socket=gs.createConnection({host:this.config.host,port:this.config.port}),this.setupSocketEventHandlers(t,e,r)}setupSocketEventHandlers(t,e,r){this.socket&&(this.socket.once("error",s=>{clearTimeout(t),this.log(`Connection error: ${s.message}`,!0),r(new Error(`SMTP connection error: ${s.message}`))}),this.socket.once("connect",()=>{this.log("Connected to SMTP server"),clearTimeout(t),this.socket.once("data",s=>{let i=s.toString().trim();this.log(`Server greeting: ${i}`),i.startsWith("220")?(this.connected=!0,this.secureMode=this.config.secure,e()):(r(new Error(`Unexpected server greeting: ${i}`)),this.socket.destroy())})}),this.socket.once("close",s=>{this.connected?this.log(`Connection closed${s?" with error":""}`):(clearTimeout(t),r(new Error("Connection closed before initialization completed"))),this.connected=!1}))}async upgradeToTLS(){if(!(!this.socket||this.secureMode))return new Promise((t,e)=>{let s={socket:this.socket,host:this.config.host,rejectUnauthorized:!0,minVersion:"TLSv1.2",ciphers:"HIGH:!aNULL:!MD5:!RC4"},i=It.connect(s);i.once("error",o=>{this.log(`TLS upgrade error: ${o.message}`,!0),e(new Error(`STARTTLS error: ${o.message}`))}),i.once("secureConnect",()=>{this.log("Connection upgraded to TLS"),i.authorized?(this.socket=i,this.secureMode=!0,t()):e(new Error(`TLS certificate verification failed: ${i.authorizationError}`))})})}async sendCommand(t,e,r=this.config.timeout){if(!this.socket||!this.connected)throw new Error("Not connected to SMTP server");return new Promise((s,i)=>{let o=setTimeout(()=>{this.socket?.removeListener("data",a),i(new Error(`Command timeout after ${r}ms: ${t}`))},r),n="",a=c=>{n+=c.toString();let l=n.split(`\r
8
+ `;return t}};var te={int:t=>{let e=t.trim();if(!/^[+-]?\d+$/.test(e))throw new Error(`Cannot parse "${t}" as an integer`);let r=Number.parseInt(e,10);if(Number.isNaN(r))throw new Error(`Cannot parse "${t}" as an integer`);return r},float:t=>{let e=t.trim();if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(e)){if(e==="Infinity"||e==="-Infinity")return e==="Infinity"?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY;throw new Error(`Cannot parse "${t}" as a number`)}let r=Number.parseFloat(e);if(Number.isNaN(r))throw new Error(`Cannot parse "${t}" as a number`);return r},boolean:t=>{let e=t.trim().toLowerCase();if(["true","yes","1","y"].includes(e))return!0;if(["false","no","0","n"].includes(e))return!1;throw new Error(`Cannot parse "${t}" as a boolean`)},array:t=>t.split(",").map(e=>e.trim()),json:t=>{try{return JSON.parse(t)}catch{throw new Error(`Cannot parse "${t}" as JSON`)}}};import{EventEmitter as ks}from"events";var kt=class extends Error{constructor(t){super(),this.name="ValidationError",this.message=t,this.cause={statusCode:400}}};import{existsSync as hs,readFileSync as ms}from"fs";var At=class{config;defaults={configFilePath:"mikromail.config.json",args:[]};constructor(t){let e=t?.config||{},r=t?.configFilePath||this.defaults.configFilePath,s=t?.args||this.defaults.args;this.config=this.create(r,s,e)}create(t,e,r){let s={host:"",user:"",password:"",port:465,secure:!0,debug:!1,maxRetries:2,skipEmailValidation:!1,skipMXRecordCheck:!1},i={};if(hs(t))try{let n=ms(t,"utf8");i=JSON.parse(n),console.log(`Loaded configuration from ${t}`)}catch(n){console.error(`Error reading config file: ${n instanceof Error?n.message:String(n)}`)}let o=this.parseCliArgs(e);return{...s,...r,...i,...o}}parseCliArgs(t){let e={};for(let r=2;r<t.length;r++)switch(t[r]){case"--host":r+1<t.length&&(e.host=t[++r]);break;case"--user":r+1<t.length&&(e.user=t[++r]);break;case"--password":r+1<t.length&&(e.password=t[++r]);break;case"--port":if(r+1<t.length){let i=Number.parseInt(t[++r],10);Number.isNaN(i)||(e.port=i)}break;case"--secure":e.secure=!0;break;case"--debug":e.debug=!0;break;case"--retries":if(r+1<t.length){let i=Number.parseInt(t[++r],10);Number.isNaN(i)||(e.maxRetries=i)}break}return e}validate(){if(!this.config.host)throw new kt("Host value not found")}get(){return this.validate(),this.config}};import{promises as fs}from"dns";function ye(t){try{let[e,r]=t.split("@");if(!e||e.length>64||e.startsWith(".")||e.endsWith(".")||e.includes("..")||!/^[a-zA-Z0-9!#$%&'*+\-/=?^_`{|}~.]+$/.test(e)||!r||r.length>255)return!1;if(r.startsWith("[")&&r.endsWith("]")){let i=r.slice(1,-1);return i.startsWith("IPv6:")?!0:/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/.test(i)}if(r.startsWith(".")||r.endsWith(".")||r.includes(".."))return!1;let s=r.split(".");if(s.length<2||s[s.length-1].length<2)return!1;for(let i of s)if(!i||i.length>63||!/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(i))return!1;return!0}catch{return!1}}async function gs(t){try{let e=await fs.resolveMx(t);return!!e&&e.length>0}catch{return!1}}async function It(t){try{let e=t.split("@")[1];return e?await gs(e):!1}catch{return!1}}import{Buffer as ve}from"buffer";import Ze from"crypto";import ys from"net";import vs from"os";import Et from"tls";var Pt=class{config;socket;connected;lastCommand;serverCapabilities;secureMode;retryCount;maxEmailSize=10485760;constructor(t){this.config={host:t.host,user:t.user,password:t.password,port:t.port??(t.secure?465:587),secure:t.secure??!0,debug:t.debug??!1,timeout:t.timeout??1e4,clientName:t.clientName??vs.hostname(),maxRetries:t.maxRetries??3,retryDelay:t.retryDelay??1e3,skipAuthentication:t.skipAuthentication||!1,skipEmailValidation:t.skipEmailValidation||!1,skipMXRecordCheck:t.skipMXRecordCheck||!1},this.socket=null,this.connected=!1,this.lastCommand="",this.serverCapabilities=[],this.secureMode=this.config.secure,this.retryCount=0}log(t,e=!1){this.config.debug&&console.log(`${e?"SMTP ERROR: ":"SMTP: "}${t}`)}async connect(){return new Promise((t,e)=>{let r=setTimeout(()=>{e(new Error(`Connection timeout after ${this.config.timeout}ms`)),this.socket?.destroy()},this.config.timeout);try{this.config.secure?this.createTLSConnection(r,t,e):this.createPlainConnection(r,t,e)}catch(s){clearTimeout(r),this.log(`Failed to create socket: ${s.message}`,!0),e(s)}})}createTLSConnection(t,e,r){this.socket=Et.connect({host:this.config.host,port:this.config.port,rejectUnauthorized:!0,minVersion:"TLSv1.2",ciphers:"HIGH:!aNULL:!MD5:!RC4"}),this.setupSocketEventHandlers(t,e,r)}createPlainConnection(t,e,r){this.socket=ys.createConnection({host:this.config.host,port:this.config.port}),this.setupSocketEventHandlers(t,e,r)}setupSocketEventHandlers(t,e,r){this.socket&&(this.socket.once("error",s=>{clearTimeout(t),this.log(`Connection error: ${s.message}`,!0),r(new Error(`SMTP connection error: ${s.message}`))}),this.socket.once("connect",()=>{this.log("Connected to SMTP server"),clearTimeout(t),this.socket.once("data",s=>{let i=s.toString().trim();this.log(`Server greeting: ${i}`),i.startsWith("220")?(this.connected=!0,this.secureMode=this.config.secure,e()):(r(new Error(`Unexpected server greeting: ${i}`)),this.socket.destroy())})}),this.socket.once("close",s=>{this.connected?this.log(`Connection closed${s?" with error":""}`):(clearTimeout(t),r(new Error("Connection closed before initialization completed"))),this.connected=!1}))}async upgradeToTLS(){if(!(!this.socket||this.secureMode))return new Promise((t,e)=>{let s={socket:this.socket,host:this.config.host,rejectUnauthorized:!0,minVersion:"TLSv1.2",ciphers:"HIGH:!aNULL:!MD5:!RC4"},i=Et.connect(s);i.once("error",o=>{this.log(`TLS upgrade error: ${o.message}`,!0),e(new Error(`STARTTLS error: ${o.message}`))}),i.once("secureConnect",()=>{this.log("Connection upgraded to TLS"),i.authorized?(this.socket=i,this.secureMode=!0,t()):e(new Error(`TLS certificate verification failed: ${i.authorizationError}`))})})}async sendCommand(t,e,r=this.config.timeout){if(!this.socket||!this.connected)throw new Error("Not connected to SMTP server");return new Promise((s,i)=>{let o=setTimeout(()=>{this.socket?.removeListener("data",a),i(new Error(`Command timeout after ${r}ms: ${t}`))},r),n="",a=c=>{n+=c.toString();let l=n.split(`\r
9
9
  `);if(l.length>0&&l[l.length-1]===""){let p=l[l.length-2]||"",u=/^(\d{3})(.?)/.exec(p);u?.[1]&&u[2]!=="-"&&(this.socket?.removeListener("data",a),clearTimeout(o),this.log(`SMTP Response: ${n.trim()}`),u[1]===e.toString()?s(n.trim()):i(new Error(`SMTP Error: ${n.trim()}`)))}};this.socket.on("data",a),t.startsWith("AUTH PLAIN")||t.startsWith("AUTH LOGIN")||this.lastCommand==="AUTH LOGIN"&&!t.startsWith("AUTH")?this.log("SMTP Command: [Credentials hidden]"):this.log(`SMTP Command: ${t}`),this.lastCommand=t,this.socket.write(`${t}\r
10
10
  `)})}parseCapabilities(t){let e=t.split(`\r
11
11
  `);this.serverCapabilities=[];for(let r=1;r<e.length;r++){let s=e[r];if(s.match(/^\d{3}/)&&s.charAt(3)===" "){let i=s.substr(4).toUpperCase();this.serverCapabilities.push(i)}}this.log(`Server capabilities: ${this.serverCapabilities.join(", ")}`)}getBestAuthMethod(){if(this.serverCapabilities.map(e=>e.split(" ")[0]).includes("AUTH")){let e=this.serverCapabilities.find(r=>r.startsWith("AUTH "));if(e){let r=e.split(" ").slice(1);if(r.includes("CRAM-MD5"))return"CRAM-MD5";if(r.includes("LOGIN"))return"LOGIN";if(r.includes("PLAIN"))return"PLAIN"}}return"PLAIN"}async authenticate(){switch(this.getBestAuthMethod()){case"CRAM-MD5":await this.authenticateCramMD5();break;case"LOGIN":await this.authenticateLogin();break;default:await this.authenticatePlain();break}}async authenticatePlain(){let t=ve.from(`\0${this.config.user}\0${this.config.password}`).toString("base64");await this.sendCommand(`AUTH PLAIN ${t}`,235)}async authenticateLogin(){await this.sendCommand("AUTH LOGIN",334),await this.sendCommand(ve.from(this.config.user).toString("base64"),334),await this.sendCommand(ve.from(this.config.password).toString("base64"),235)}async authenticateCramMD5(){let t=await this.sendCommand("AUTH CRAM-MD5",334),e=ve.from(t.substr(4),"base64").toString("utf8"),r=Ze.createHmac("md5",this.config.password);r.update(e);let s=r.digest("hex"),i=`${this.config.user} ${s}`,o=ve.from(i).toString("base64");await this.sendCommand(o,235)}generateMessageId(){let t=Ze.randomBytes(16).toString("hex"),e=this.config.user.split("@")[1]||"localhost";return`<${t}@${e}>`}generateBoundary(){return`----=_NextPart_${Ze.randomBytes(12).toString("hex")}`}encodeHeaderValue(t){return/^[\x00-\x7F]*$/.test(t)?t:`=?UTF-8?Q?${t.replace(/[^\x00-\x7F]/g,e=>{let r=e.charCodeAt(0).toString(16).toUpperCase();return`=${r.length<2?`0${r}`:r}`})}?=`}sanitizeHeader(t){let e=t.replace(/[\r\n\t]+/g," ").replace(/\s{2,}/g," ").trim();return this.encodeHeaderValue(e)}createEmailHeaders(t){let e=this.generateMessageId(),r=new Date().toUTCString(),s=t.from||this.config.user,i=Array.isArray(t.to)?t.to.join(", "):t.to,o=[`From: ${this.sanitizeHeader(s)}`,`To: ${this.sanitizeHeader(i)}`,`Subject: ${this.sanitizeHeader(t.subject)}`,`Message-ID: ${e}`,`Date: ${r}`,"MIME-Version: 1.0"];if(t.cc){let n=Array.isArray(t.cc)?t.cc.join(", "):t.cc;o.push(`Cc: ${this.sanitizeHeader(n)}`)}if(t.replyTo&&o.push(`Reply-To: ${this.sanitizeHeader(t.replyTo)}`),t.headers)for(let[n,a]of Object.entries(t.headers))/^[a-zA-Z0-9-]+$/.test(n)&&(/^(from|to|cc|bcc|subject|date|message-id)$/i.test(n)||o.push(`${n}: ${this.sanitizeHeader(a)}`));return o}createMultipartEmail(t){let{text:e,html:r}=t,s=this.createEmailHeaders(t),i=this.generateBoundary();return r&&e?(s.push(`Content-Type: multipart/alternative; boundary="${i}"`),`${s.join(`\r
@@ -29,7 +29,7 @@ ${r}`:`${s.join(`\r
29
29
  `)}\r
30
30
  \r
31
31
  ${e||""}`)}async smtpHandshake(){let t=await this.sendCommand(`EHLO ${this.config.clientName}`,250);if(this.parseCapabilities(t),!this.secureMode&&this.serverCapabilities.includes("STARTTLS")){await this.sendCommand("STARTTLS",220),await this.upgradeToTLS();let e=await this.sendCommand(`EHLO ${this.config.clientName}`,250);this.parseCapabilities(e)}this.config.skipAuthentication?this.log("Authentication skipped (testing mode)"):await this.authenticate()}async sendEmail(t){let e=t.from||this.config.user,{to:r,subject:s}=t,i=t.text||"",o=t.html||"";if(!e||!r||!s||!i&&!o)return{success:!1,error:"Missing required email parameters (from, to, subject, and either text or html)"};let n=Array.isArray(t.to)?t.to:[t.to];if(this.config.skipEmailValidation)this.log("Email validation skipped (testing mode)");else{if(!ye(e))return{success:!1,error:"Invalid email address format"};for(let a of n)if(!ye(a))return{success:!1,error:`Invalid recipient email address format: ${a}`}}for(this.retryCount=0;this.retryCount<=this.config.maxRetries;this.retryCount++)try{this.retryCount>0&&(this.log(`Retrying email send (attempt ${this.retryCount} of ${this.config.maxRetries})...`),await new Promise(p=>setTimeout(p,this.config.retryDelay))),this.connected||(await this.connect(),await this.smtpHandshake()),await this.sendCommand(`MAIL FROM:<${e}>`,250);for(let p of n)await this.sendCommand(`RCPT TO:<${p}>`,250);if(t.cc){let p=Array.isArray(t.cc)?t.cc:[t.cc];for(let u of p)ye(u)&&await this.sendCommand(`RCPT TO:<${u}>`,250)}if(t.bcc){let p=Array.isArray(t.bcc)?t.bcc:[t.bcc];for(let u of p)ye(u)&&await this.sendCommand(`RCPT TO:<${u}>`,250)}await this.sendCommand("DATA",354);let a=this.createMultipartEmail(t);if(a.length>this.maxEmailSize)return{success:!1,error:"Email size exceeds maximum allowed"};await this.sendCommand(`${a}\r
32
- .`,250);let c=/Message-ID: (.*)/i.exec(a);return{success:!0,messageId:c?c[1].trim():void 0,message:"Email sent successfully"}}catch(a){let c=a.message;if(this.log(`Error sending email: ${c}`,!0),c.includes("5.")||c.includes("Authentication failed")||c.includes("certificate")||this.retryCount>=this.config.maxRetries)return{success:!1,error:c};try{this.connected&&await this.sendCommand("RSET",250)}catch{}this.socket?.end(),this.connected=!1}return{success:!1,error:"Maximum retry count exceeded"}}async close(){try{this.connected&&await this.sendCommand("QUIT",221)}catch(t){this.log(`Error during QUIT: ${t.message}`,!0)}finally{this.socket&&(this.socket.destroy(),this.socket=null,this.connected=!1)}}};var Qe=class{smtpClient;config;constructor(t){let e=new kt(t).get(),r=new Et(e);this.smtpClient=r,this.config=e}async send(t){try{let e=Array.isArray(t.to)?t.to:[t.to];if(!this.config.skipMXRecordCheck)for(let s of e)await At(s)||console.error(`Warning: No MX records found for recipient domain: ${s}`);let r=await this.smtpClient.sendEmail(t);r.success?console.log(`Message ID: ${r.messageId}`):console.error(`Failed to send email: ${r.error}`),await this.smtpClient.close()}catch(e){console.error("Error in email sending process:",e.message)}}};var et=()=>{let t=ks(process.env.DEBUG)||!1;return{auth:{jwtSecret:process.env.AUTH_JWT_SECRET||"your-jwt-secret",magicLinkExpirySeconds:900,jwtExpirySeconds:3600,refreshTokenExpirySeconds:604800,maxActiveSessions:3,appUrl:process.env.APP_URL||"http://localhost:3000",templates:null,debug:t},email:{emailSubject:"Your Secure Login Link",user:process.env.EMAIL_USER||"",host:process.env.EMAIL_HOST||"",password:process.env.EMAIL_PASSWORD||"",port:465,secure:!0,maxRetries:2,debug:t},storage:{databaseDirectory:"mikroauth",encryptionKey:process.env.STORAGE_KEY||"",debug:t},server:{port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"],debug:t}}};function ks(t){return t==="true"||t===!0}var As=class{algorithm="HS256";secret="HS256";constructor(t){if(process.env.NODE_ENV==="production"&&(!t||t.length<32||t===et().auth.jwtSecret))throw new Error("Production environment requires a strong JWT secret (min 32 chars)");this.secret=t}sign(t,e={}){let r={alg:this.algorithm,typ:"JWT"},s=Math.floor(Date.now()/1e3),i={...t,iat:s};e.exp!==void 0&&(i.exp=s+e.exp),e.notBefore!==void 0&&(i.nbf=s+e.notBefore),e.issuer&&(i.iss=e.issuer),e.audience&&(i.aud=e.audience),e.subject&&(i.sub=e.subject),e.jwtid&&(i.jti=e.jwtid);let o=this.base64UrlEncode(JSON.stringify(r)),n=this.base64UrlEncode(JSON.stringify(i)),a=`${o}.${n}`,c=this.createSignature(a);return`${a}.${c}`}verify(t,e={}){let r=this.decode(t);if(r.header.alg!==this.algorithm)throw new Error(`Invalid algorithm. Expected ${this.algorithm}, got ${r.header.alg}`);let[s,i]=t.split("."),o=`${s}.${i}`;if(this.createSignature(o)!==r.signature)throw new Error("Invalid signature");let n=r.payload,a=Math.floor(Date.now()/1e3),c=e.clockTolerance||0;if(n.exp!==void 0&&n.exp+c<a)throw new Error("Token expired");if(n.nbf!==void 0&&n.nbf-c>a)throw new Error("Token not yet valid");if(e.issuer&&n.iss!==e.issuer)throw new Error("Invalid issuer");if(e.audience&&n.aud!==e.audience)throw new Error("Invalid audience");if(e.subject&&n.sub!==e.subject)throw new Error("Invalid subject");return n}decode(t){let e=t.split(".");if(e.length!==3)throw new Error("Invalid token format");try{let[r,s,i]=e,o=JSON.parse(this.base64UrlDecode(r)),n=JSON.parse(this.base64UrlDecode(s));return{header:o,payload:n,signature:i}}catch{throw new Error("Failed to decode token")}}createSignature(t){let e=re.createHmac("sha256",this.secret).update(t).digest();return this.base64UrlEncode(e)}base64UrlEncode(t){let e;return typeof t=="string"?e=Buffer.from(t):e=t,e.toString("base64").replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}base64UrlDecode(t){let e=t.replace(/-/g,"+").replace(/_/g,"/");switch(e.length%4){case 0:break;case 2:e+="==";break;case 3:e+="=";break;default:throw new Error("Invalid base64 string")}return Buffer.from(e,"base64").toString()}},Is=class{templates;constructor(t){t?this.templates=t:this.templates=Es}getText(t,e,r){return this.templates.textVersion(t,e,r).trim()}getHtml(t,e,r){return this.templates.htmlVersion(t,e,r).trim()}},Es={textVersion:(t,e,r)=>`
32
+ .`,250);let c=/Message-ID: (.*)/i.exec(a);return{success:!0,messageId:c?c[1].trim():void 0,message:"Email sent successfully"}}catch(a){let c=a.message;if(this.log(`Error sending email: ${c}`,!0),c.includes("5.")||c.includes("Authentication failed")||c.includes("certificate")||this.retryCount>=this.config.maxRetries)return{success:!1,error:c};try{this.connected&&await this.sendCommand("RSET",250)}catch{}this.socket?.end(),this.connected=!1}return{success:!1,error:"Maximum retry count exceeded"}}async close(){try{this.connected&&await this.sendCommand("QUIT",221)}catch(t){this.log(`Error during QUIT: ${t.message}`,!0)}finally{this.socket&&(this.socket.destroy(),this.socket=null,this.connected=!1)}}};var Qe=class{smtpClient;config;constructor(t){let e=new At(t).get(),r=new Pt(e);this.smtpClient=r,this.config=e}async send(t){try{let e=Array.isArray(t.to)?t.to:[t.to];if(!this.config.skipMXRecordCheck)for(let s of e)await It(s)||console.error(`Warning: No MX records found for recipient domain: ${s}`);let r=await this.smtpClient.sendEmail(t);r.success?console.log(`Message ID: ${r.messageId}`):console.error(`Failed to send email: ${r.error}`),await this.smtpClient.close()}catch(e){console.error("Error in email sending process:",e.message)}}};var et=()=>{let t=As(process.env.DEBUG)||!1;return{auth:{jwtSecret:process.env.AUTH_JWT_SECRET||"your-jwt-secret",magicLinkExpirySeconds:900,jwtExpirySeconds:3600,refreshTokenExpirySeconds:604800,maxActiveSessions:3,appUrl:process.env.APP_URL||"http://localhost:3000",templates:null,debug:t},email:{emailSubject:"Your Secure Login Link",user:process.env.EMAIL_USER||"",host:process.env.EMAIL_HOST||"",password:process.env.EMAIL_PASSWORD||"",port:465,secure:!0,maxRetries:2,debug:t},storage:{databaseDirectory:"mikroauth",encryptionKey:process.env.STORAGE_KEY||"",debug:t},server:{port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"],debug:t}}};function As(t){return t==="true"||t===!0}var Is=class{algorithm="HS256";secret="HS256";constructor(t){if(process.env.NODE_ENV==="production"&&(!t||t.length<32||t===et().auth.jwtSecret))throw new Error("Production environment requires a strong JWT secret (min 32 chars)");this.secret=t}sign(t,e={}){let r={alg:this.algorithm,typ:"JWT"},s=Math.floor(Date.now()/1e3),i={...t,iat:s};e.exp!==void 0&&(i.exp=s+e.exp),e.notBefore!==void 0&&(i.nbf=s+e.notBefore),e.issuer&&(i.iss=e.issuer),e.audience&&(i.aud=e.audience),e.subject&&(i.sub=e.subject),e.jwtid&&(i.jti=e.jwtid);let o=this.base64UrlEncode(JSON.stringify(r)),n=this.base64UrlEncode(JSON.stringify(i)),a=`${o}.${n}`,c=this.createSignature(a);return`${a}.${c}`}verify(t,e={}){let r=this.decode(t);if(r.header.alg!==this.algorithm)throw new Error(`Invalid algorithm. Expected ${this.algorithm}, got ${r.header.alg}`);let[s,i]=t.split("."),o=`${s}.${i}`;if(this.createSignature(o)!==r.signature)throw new Error("Invalid signature");let n=r.payload,a=Math.floor(Date.now()/1e3),c=e.clockTolerance||0;if(n.exp!==void 0&&n.exp+c<a)throw new Error("Token expired");if(n.nbf!==void 0&&n.nbf-c>a)throw new Error("Token not yet valid");if(e.issuer&&n.iss!==e.issuer)throw new Error("Invalid issuer");if(e.audience&&n.aud!==e.audience)throw new Error("Invalid audience");if(e.subject&&n.sub!==e.subject)throw new Error("Invalid subject");return n}decode(t){let e=t.split(".");if(e.length!==3)throw new Error("Invalid token format");try{let[r,s,i]=e,o=JSON.parse(this.base64UrlDecode(r)),n=JSON.parse(this.base64UrlDecode(s));return{header:o,payload:n,signature:i}}catch{throw new Error("Failed to decode token")}}createSignature(t){let e=re.createHmac("sha256",this.secret).update(t).digest();return this.base64UrlEncode(e)}base64UrlEncode(t){let e;return typeof t=="string"?e=Buffer.from(t):e=t,e.toString("base64").replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}base64UrlDecode(t){let e=t.replace(/-/g,"+").replace(/_/g,"/");switch(e.length%4){case 0:break;case 2:e+="==";break;case 3:e+="=";break;default:throw new Error("Invalid base64 string")}return Buffer.from(e,"base64").toString()}},Es=class{templates;constructor(t){t?this.templates=t:this.templates=Ps}getText(t,e,r){return this.templates.textVersion(t,e,r).trim()}getHtml(t,e,r){return this.templates.htmlVersion(t,e,r).trim()}},Ps={textVersion:(t,e,r)=>`
33
33
  Click this link to login: ${t}
34
34
 
35
35
  Security Information:
@@ -108,10 +108,10 @@ If you didn't request this link, please ignore this email.
108
108
  </div>
109
109
  </body>
110
110
  </html>
111
- `},Ps=class{constructor(t){this.options=t}sentEmails=[];async sendMail(t){this.sentEmails.push(t),this.options?.logToConsole&&(console.log("Email sent:"),console.log(`From: ${t.from}`),console.log(`To: ${t.to}`),console.log(`Subject: ${t.subject}`),console.log(`Text: ${t.text}`)),this.options?.onSend&&this.options.onSend(t)}getSentEmails(){return[...this.sentEmails]}clearSentEmails(){this.sentEmails=[]}},Ts=class{data=new Map;collections=new Map;expiryEmitter=new Cs;expiryCheckInterval;constructor(t=1e3){this.expiryCheckInterval=setInterval(()=>this.checkExpiredItems(),t)}destroy(){clearInterval(this.expiryCheckInterval),this.data.clear(),this.collections.clear(),this.expiryEmitter.removeAllListeners()}checkExpiredItems(){let t=Date.now();for(let[e,r]of this.data.entries())r.expiry&&r.expiry<t&&(this.data.delete(e),this.expiryEmitter.emit("expired",e));for(let[e,r]of this.collections.entries())r.expiry&&r.expiry<t&&(this.collections.delete(e),this.expiryEmitter.emit("expired",e))}async set(t,e,r){let s=r?Date.now()+r*1e3:null;this.data.set(t,{value:e,expiry:s})}async get(t){let e=this.data.get(t);return e?e.expiry&&e.expiry<Date.now()?(this.data.delete(t),null):e.value:null}async delete(t){this.data.delete(t),this.collections.delete(t)}async addToCollection(t,e,r){this.collections.has(t)||this.collections.set(t,{items:[],expiry:r?Date.now()+r*1e3:null});let s=this.collections.get(t);s&&(r&&(s.expiry=Date.now()+r*1e3),s.items.push(e))}async removeFromCollection(t,e){let r=this.collections.get(t);r&&(r.items=r.items.filter(s=>s!==e))}async getCollection(t){let e=this.collections.get(t);return e?[...e.items]:[]}async getCollectionSize(t){let e=this.collections.get(t);return e?e.items.length:0}async removeOldestFromCollection(t){let e=this.collections.get(t);return!e||e.items.length===0?null:e.items.shift()||null}async findKeys(t){let e=t.replace(/\*/g,".*").replace(/\?/g,"."),r=new RegExp(`^${e}$`),s=Array.from(this.data.keys()).filter(o=>r.test(o)),i=Array.from(this.collections.keys()).filter(o=>r.test(o));return[...new Set([...s,...i])]}};function Pt(t){if(!t||t.trim()===""||(t.match(/@/g)||[]).length!==1)return!1;let[e,r]=t.split("@");return!(!e||!r||t.includes("..")||!Rs(e)||!js(r))}function Rs(t){return t.startsWith('"')&&t.endsWith('"')?!t.slice(1,-1).includes('"'):t.length>64||t.startsWith(".")||t.endsWith(".")?!1:/^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$/.test(t)}function js(t){if(t.startsWith("[")&&t.endsWith("]")){let r=t.slice(1,-1);return r.startsWith("IPv6:")?Os(r.slice(5)):$s(r)}let e=t.split(".");if(e.length===0)return!1;for(let r of e)if(!r||r.length>63||!/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/.test(r))return!1;if(e.length>1){let r=e[e.length-1];if(!/^[a-zA-Z]{2,}$/.test(r))return!1}return!0}function $s(t){return/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/.test(t)}function Os(t){if(!/^[a-fA-F0-9:]+$/.test(t))return!1;let e=t.split(":");return!(e.length<2||e.length>8)}var I=et(),Ms=t=>{let e={configFilePath:"mikroauth.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:I.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:I.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:I.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:I.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:I.auth.maxActiveSessions},{flag:"--appUrl",path:"auth.appUrl",defaultValue:I.auth.appUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:I.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:I.email.host},{flag:"--emailUser",path:"email.user",defaultValue:I.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:I.email.password},{flag:"--emailPort",path:"email.port",defaultValue:I.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:I.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:I.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:I.email.debug},{flag:"--dir",path:"storage.databaseDirectory",defaultValue:I.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:I.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:I.storage.debug},{flag:"--port",path:"server.port",defaultValue:I.server.port},{flag:"--host",path:"server.host",defaultValue:I.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:I.server.useHttps},{flag:"--https",path:"server.useHttp2",isFlag:!0,defaultValue:I.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:I.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:I.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:I.server.sslCa},{flag:"--ratelimit",path:"server.rateLimit.enabled",defaultValue:I.server.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"server.rateLimit.requestsPerMinute",defaultValue:I.server.rateLimit.requestsPerMinute},{flag:"--allowed",path:"server.allowedDomains",defaultValue:I.server.allowedDomains,parser:te.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:I.server.debug}]};return t&&(e.config=t),e},Ie={linkSent:"If a matching account was found, a magic link has been sent.",revokedSuccess:"All other sessions revoked successfully.",logoutSuccess:"Logged out successfully."},Tt=class{config;email;storage;jwtService;templates;constructor(t,e,r){let s=new ee(Ms({auth:t.auth,email:t.email})).get();s.auth.debug&&console.log("Using configuration:",s),this.config=s,this.email=e||new Ps,this.storage=r||new Ts,this.jwtService=new As(s.auth.jwtSecret),this.templates=new Is(s?.auth.templates),this.checkIfUsingDefaultCredentialsInProduction()}checkIfUsingDefaultCredentialsInProduction(){process.env.NODE_ENV==="production"&&this.config.auth.jwtSecret===et().auth.jwtSecret&&(console.error("WARNING: Using default secrets in production environment!"),process.exit(1))}generateToken(t){let e=Date.now().toString(),r=re.randomBytes(32).toString("hex");return re.createHash("sha256").update(`${t}:${e}:${r}`).digest("hex")}generateJsonWebToken(t){return this.jwtService.sign({sub:t.id,email:t.email,username:t.username,role:t.role,exp:Math.floor(Date.now()/1e3)+3600*24})}generateRefreshToken(){return re.randomBytes(40).toString("hex")}async trackSession(t,e,r){let s=`sessions:${t}`;if(await this.storage.getCollectionSize(s)>=this.config.auth.maxActiveSessions){let i=await this.storage.removeOldestFromCollection(s);i&&await this.storage.delete(`refresh:${i}`)}await this.storage.addToCollection(s,e,this.config.auth.refreshTokenExpirySeconds),await this.storage.set(`refresh:${e}`,JSON.stringify(r),this.config.auth.refreshTokenExpirySeconds)}generateMagicLinkUrl(t){let{token:e,email:r,appUrl:s}=t,i=s||this.config.auth.appUrl;try{return new xs(i),`${i}?token=${encodeURIComponent(e)}&email=${encodeURIComponent(r)}`}catch{throw new Error("Invalid base URL configuration")}}async createMagicLink(t){let{email:e,ip:r,metadata:s,appUrl:i,subject:o}=t;if(!Pt(e))throw new Error("Valid email required");try{let n=this.generateToken(e),a=`magic_link:${n}`,c={email:e,ipAddress:r||"unknown",createdAt:Date.now()};await this.storage.set(a,JSON.stringify(c),this.config.auth.magicLinkExpirySeconds);let l=await this.storage.findKeys("magic_link:*");for(let h of l){if(h===a)continue;let v=await this.storage.get(h);if(v)try{JSON.parse(v).email===e&&await this.storage.delete(h)}catch{}}let p=this.generateMagicLinkUrl({token:n,email:e,appUrl:i}),u=Math.ceil(this.config.auth.magicLinkExpirySeconds/60);return await this.email.sendMail({from:this.config.email.user,to:e,subject:o||this.config.email.emailSubject,text:this.templates.getText(p,u,s),html:this.templates.getHtml(p,u,s)}),{message:Ie.linkSent}}catch(n){throw console.error(`Failed to process magic link request: ${n}`),new Error("Failed to process magic link request")}}async createToken(t){let{email:e,username:r,role:s,ip:i}=t;if(!Pt(e))throw new Error("Valid email required");try{let o=re.randomBytes(16).toString("hex"),n=this.generateRefreshToken(),a=Date.now(),c={sub:e,username:r,role:s,jti:o,lastLogin:a,metadata:{ip:i||"unknown"},exp:Math.floor(Date.now()/1e3)+3600*24},l=this.jwtService.sign(c,{exp:this.config.auth.jwtExpirySeconds}),p={email:e,username:r,role:s,ipAddress:i||"unknown",tokenId:o,createdAt:a,lastLogin:a};return await this.trackSession(e,n,p),{accessToken:l,refreshToken:n,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(o){throw console.error("Token creation error:",o),new Error("Token creation failed")}}async verifyToken(t){let{token:e,email:r}=t;try{let s=`magic_link:${e}`,i=await this.storage.get(s);if(!i)throw new Error("Invalid or expired token");let o=JSON.parse(i);if(o.email!==r)throw new Error("Email mismatch");let n=o.username,a=o.role;await this.storage.delete(s);let c=re.randomBytes(16).toString("hex"),l=this.generateRefreshToken(),p={sub:r,username:n,role:a,jti:c,lastLogin:o.createdAt,metadata:{ip:o.ipAddress},exp:Math.floor(Date.now()/1e3)+3600*24},u=this.jwtService.sign(p,{exp:this.config.auth.jwtExpirySeconds});return await this.trackSession(r,l,{...o,tokenId:c,createdAt:Date.now()}),{accessToken:u,refreshToken:l,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(s){throw console.error("Token verification error:",s),new Error("Verification failed")}}async refreshAccessToken(t){try{let e=await this.storage.get(`refresh:${t}`);if(!e)throw new Error("Invalid or expired refresh token");let r=JSON.parse(e),s=r.email;if(!s)throw new Error("Invalid refresh token data");let i=r.username,o=r.role,n=re.randomBytes(16).toString("hex"),a={sub:s,username:i,role:o,jti:n,lastLogin:r.lastLogin||r.createdAt,metadata:{ip:r.ipAddress}},c=this.jwtService.sign(a,{exp:this.config.auth.jwtExpirySeconds});return r.lastUsed=Date.now(),await this.storage.set(`refresh:${t}`,JSON.stringify(r),this.config.auth.refreshTokenExpirySeconds),{accessToken:c,refreshToken:t,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(e){throw console.error("Token refresh error:",e),new Error("Token refresh failed")}}verify(t){try{return this.jwtService.verify(t)}catch{throw new Error("Invalid token")}}async logout(t){try{if(!t||typeof t!="string")throw new Error("Refresh token is required");let e=await this.storage.get(`refresh:${t}`);if(!e)return{message:Ie.logoutSuccess};let r=JSON.parse(e).email;if(!r)throw new Error("Invalid refresh token data");await this.storage.delete(`refresh:${t}`);let s=`sessions:${r}`;return await this.storage.removeFromCollection(s,t),{message:Ie.logoutSuccess}}catch(e){throw console.error("Logout error:",e),new Error("Logout failed")}}async getSessions(t){try{if(!t.user?.email)throw new Error("User not authenticated");let e=t.user.email,r=t.body?.refreshToken,s=`sessions:${e}`,i=(await this.storage.getCollection(s)).map(async n=>{try{let a=await this.storage.get(`refresh:${n}`);if(!a)return await this.storage.removeFromCollection(s,n),null;let c=JSON.parse(a);return{id:`${n.substring(0,8)}...`,createdAt:c.createdAt||0,lastLogin:c.lastLogin||c.createdAt||0,lastUsed:c.lastUsed||c.createdAt||0,metadata:{ip:c.ipAddress},isCurrentSession:n===r}}catch{return await this.storage.removeFromCollection(s,n),null}}),o=(await Promise.all(i)).filter(Boolean);return o.sort((n,a)=>a.createdAt-n.createdAt),{sessions:o}}catch(e){throw console.error("Get sessions error:",e),new Error("Failed to fetch sessions")}}async revokeSessions(t){try{if(!t.user?.email)throw new Error("User not authenticated");let e=t.user.email,r=t.body?.refreshToken,s=`sessions:${e}`,i=await this.storage.getCollection(s);for(let o of i)r&&o===r||await this.storage.delete(`refresh:${o}`);return await this.storage.delete(s),r&&await this.storage.get(`refresh:${r}`)&&await this.storage.addToCollection(s,r,this.config.auth.refreshTokenExpirySeconds),{message:Ie.revokedSuccess}}catch(e){throw console.error("Revoke sessions error:",e),new Error("Failed to revoke sessions")}}authenticate(t,e){try{let r=t.headers?.authorization;if(!r||!r.startsWith("Bearer "))throw new Error("Authentication required");let s=r.split(" ")[1];try{let i=this.verify(s);t.user={email:i.sub},e()}catch{throw new Error("Invalid or expired token")}}catch(r){e(r)}}},Us=class{key;algorithm="aes-256-gcm";keyLength=32;constructor(t){this.key=vs(t,"mikroauth-salt",this.keyLength)}encrypt(t){let e=ws(12),r=Ss(this.algorithm,this.key,e),s=Buffer.concat([r.update(t,"utf8"),r.final()]),i=r.getAuthTag();return`${e.toString("hex")}:${i.toString("hex")}:${s.toString("hex")}`}decrypt(t){let e=t.split(":");if(e.length!==3)throw new Error("Invalid encrypted data format");let[r,s,i]=e,o=Buffer.from(r,"hex"),n=Buffer.from(s,"hex"),a=Buffer.from(i,"hex"),c=bs(this.algorithm,this.key,o);return c.setAuthTag(n),Buffer.concat([c.update(a),c.final()]).toString("utf8")}},Rt=class{db;encryption;PREFIX_KV="kv:";PREFIX_COLLECTION="coll:";TABLE_NAME="mikroauth";constructor(t,e){this.db=t,e&&(this.encryption=new Us(e))}async start(){await this.db.start()}async close(){await this.db.close()}async set(t,e,r){let s=`${this.PREFIX_KV}${t}`,i=this.encryption?this.encryption.encrypt(e):e,o=r?Date.now()+r*1e3:void 0;await this.db.write(this.TABLE_NAME,s,i,o)}async get(t){let e=`${this.PREFIX_KV}${t}`,r=await this.db.get(this.TABLE_NAME,e);return r?this.encryption?this.encryption.decrypt(r):r:null}async delete(t){let e=`${this.PREFIX_KV}${t}`;await this.db.delete(this.TABLE_NAME,e)}async addToCollection(t,e,r){let s=`${this.PREFIX_COLLECTION}${t}`,i=await this.db.get(this.TABLE_NAME,s),o=[];if(i){let l=this.encryption?this.encryption.decrypt(i):i;o=JSON.parse(l)}o.includes(e)||o.push(e);let n=JSON.stringify(o),a=this.encryption?this.encryption.encrypt(n):n,c=r?Date.now()+r*1e3:void 0;await this.db.write(this.TABLE_NAME,s,a,c)}async removeFromCollection(t,e){let r=`${this.PREFIX_COLLECTION}${t}`,s=await this.db.get(this.TABLE_NAME,r);if(!s)return;let i=this.encryption?this.encryption.decrypt(s):s,o=JSON.parse(i);o=o.filter(c=>c!==e);let n=JSON.stringify(o),a=this.encryption?this.encryption.encrypt(n):n;await this.db.write(this.TABLE_NAME,r,a)}async getCollection(t){let e=`${this.PREFIX_COLLECTION}${t}`,r=await this.db.get(this.TABLE_NAME,e);if(!r)return[];let s=this.encryption?this.encryption.decrypt(r):r;return JSON.parse(s)}async getCollectionSize(t){return(await this.getCollection(t)).length}async removeOldestFromCollection(t){let e=`${this.PREFIX_COLLECTION}${t}`,r=await this.db.get(this.TABLE_NAME,e);if(!r)return null;let s=this.encryption?this.encryption.decrypt(r):r,i=JSON.parse(s);if(i.length===0)return null;let o=i.shift(),n=JSON.stringify(i),a=this.encryption?this.encryption.encrypt(n):n;return await this.db.write(this.TABLE_NAME,e,a),o}async findKeys(t){let e=t.replace(/\./g,"\\.").replace(/\*/g,".*").replace(/\?/g,"."),r=new RegExp(`^${e}$`),s=await this.db.get(this.TABLE_NAME);return Array.isArray(s)?s.filter(i=>{let o=i[0];return typeof o=="string"&&o.startsWith(this.PREFIX_KV)}).map(i=>i[0].substring(this.PREFIX_KV.length)).filter(i=>r.test(i)):[]}},jt=class{email;sender;constructor(t){this.sender=t.user,this.email=new Qe({config:t})}async sendMail(t){await this.email.send({from:this.sender,to:t.to,cc:t.cc,bcc:t.bcc,subject:t.subject,text:t.text,html:t.html})}};function Ee(t){if(!t.deflate&&!t.inflate)throw new Error("Dictionary must provide either deflate or inflate mapping");if(t.deflate&&t.inflate)throw new Error("Dictionary should provide only one of deflate or inflate (not both). The inverse will be auto-generated.");return t.deflate?{deflate:t.deflate,inflate:$t(t.deflate)}:{deflate:$t(t.inflate),inflate:t.inflate}}function $t(t){let e={};for(let[r,s]of Object.entries(t))e[s]=r;return e}function ae(t,e){if(t==null||typeof t!="object")return t;if(Array.isArray(t))return t.map(s=>ae(s,e));let r={};for(let[s,i]of Object.entries(t)){let o=e[s]||s;r[o]=ae(i,e)}return r}function se(t){if(!t||typeof t!="string")throw new Error("Table name must be a non-empty string");if(t.length>255)throw new Error("Table name must not exceed 255 characters");if(t.includes("/")||t.includes("\\"))throw new Error("Table name must not contain path separators");if(t.includes(".."))throw new Error('Table name must not contain ".."');if(t.startsWith("."))throw new Error('Table name must not start with "."');if(t.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(t.toUpperCase()))throw new Error(`Table name "${t}" is reserved by the filesystem`)}function Pe(t){if(t==null)throw new Error("Key must be defined");if(typeof t!="string")throw new Error("Key must be a string");if(t.length===0)throw new Error("Key must not be empty");if(t.length>1024)throw new Error("Key must not exceed 1024 characters");if(t.includes("\0"))throw new Error("Key must not contain null bytes")}function Ot(t){if(t===void 0)throw new Error("Value must not be undefined (use null instead)");let e=typeof t;if(e==="function")throw new Error("Value must be JSON-serializable: functions are not supported");if(e==="symbol")throw new Error("Value must be JSON-serializable: symbols are not supported");try{if(JSON.stringify(t)===void 0)throw new Error("Value must be JSON-serializable: value cannot be serialized")}catch(r){throw new Error(`Value must be JSON-serializable: ${r instanceof Error?r.message:String(r)}`)}}import{existsSync as tt,mkdirSync as Ls,readdirSync as Hs,openSync as Ds,closeSync as Ns}from"fs";import{readFile as Vs,writeFile as qs,rename as Fs,unlink as Mt,open as Bs}from"fs/promises";import{join as rt,dirname as _s}from"path";var ie=class{data=new Map;databaseDirectory;dictionaries=new Map;useFsync;constructor(t){this.databaseDirectory=t.databaseDirectory,this.useFsync=t.durableWrites??!1,t.dictionaries&&Object.entries(t.dictionaries).forEach(([e,r])=>{let s=Ee(r);this.dictionaries.set(e,s)}),tt(this.databaseDirectory)||Ls(this.databaseDirectory,{recursive:!0})}async start(){try{let t=Hs(this.databaseDirectory);for(let e of t)!e.endsWith(".tmp")&&!e.startsWith(".")&&await this.loadTable(e)}catch(t){throw console.error("Failed to start database:",t),t}}async write(t,e,r,s,i){if(se(t),Pe(e),Ot(r),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(t)||this.data.set(t,new Map);let o=this.data.get(t),a=(o.get(e)?.version||0)+1,c={value:r,version:a,timestamp:Date.now(),expiration:s||null,dictionaryName:i||void 0};return o.set(e,c),await this.persistTable(t),!0}catch(o){return console.error(`Write failed for ${t}:${e}:`,o),!1}}async get(t,e){se(t),e!==void 0&&Pe(e);try{this.data.has(t)||await this.loadTable(t);let r=this.data.get(t);if(!r)return e?void 0:[];if(e!==void 0){let o=r.get(e);if(!o)return;if(this.isExpired(o)){r.delete(e),await this.persistTable(t);return}return o.value}let s=[],i=[];for(let[o,n]of r.entries())this.isExpired(n)?i.push(o):s.push([o,n.value]);if(i.length>0){for(let o of i)r.delete(o);await this.persistTable(t)}return s}catch(r){return console.error(`Read failed for ${t}:${e}:`,r),e?void 0:[]}}async delete(t,e){se(t),Pe(e);try{this.data.has(t)||await this.loadTable(t);let r=this.data.get(t);if(!r||!r.has(e))return!1;let s=r.get(e);return s?this.isExpired(s)?(r.delete(e),await this.persistTable(t),!1):(r.delete(e),await this.persistTable(t),!0):!1}catch(r){return console.error(`Delete failed for ${t}:${e}:`,r),!1}}async getTableSize(t){se(t);try{this.data.has(t)||await this.loadTable(t);let e=this.data.get(t);if(!e)return 0;let r=0,s=[];for(let[i,o]of e.entries())this.isExpired(o)?s.push(i):r++;if(s.length>0){for(let i of s)e.delete(i);await this.persistTable(t)}return r}catch(e){return console.error(`Get table size failed for ${t}:`,e),0}}isExpired(t){return t.expiration===null?!1:Date.now()>t.expiration}async cleanupExpired(t){se(t);try{this.data.has(t)||await this.loadTable(t);let e=this.data.get(t);if(!e)return 0;let r=[];for(let[s,i]of e.entries())this.isExpired(i)&&r.push(s);for(let s of r)e.delete(s);return r.length>0&&await this.persistTable(t),r.length}catch(e){return console.error(`Cleanup failed for ${t}:`,e),0}}async cleanupAllExpired(){let t=0;for(let e of this.data.keys())t+=await this.cleanupExpired(e);return t}async deleteTable(t){se(t);try{this.data.delete(t);let e=rt(this.databaseDirectory,t);return tt(e)&&await Mt(e),!0}catch(e){return console.error(`Delete table failed for ${t}:`,e),!1}}listTables(){return Array.from(this.data.keys())}async flush(){try{let t=Array.from(this.data.keys()).map(e=>this.persistTable(e));await Promise.all(t)}catch(t){throw console.error("Flush failed:",t),t}}async close(){await this.flush()}addDictionary(t,e){let r=Ee(e);this.dictionaries.set(t,r)}removeDictionary(t){return this.dictionaries.delete(t)}listDictionaries(){return Array.from(this.dictionaries.keys())}async loadTable(t){let e=rt(this.databaseDirectory,t);if(!tt(e)){this.data.set(t,new Map);return}try{let r=await Vs(e);if(r.length===0){this.data.set(t,new Map);return}let s=this.deserializeTable(r);this.data.set(t,s)}catch(r){console.error(`Failed to load table ${t}:`,r),this.data.set(t,new Map)}}async persistTable(t){let e=this.data.get(t);if(!e)return;let r=this.serializeTable(e),s=rt(this.databaseDirectory,t),i=`${s}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await qs(i,r),this.useFsync){let o=await Bs(i,"r+");try{await o.sync()}finally{await o.close()}}if(await Fs(i,s),this.useFsync){let o=_s(s),n=Ds(o,"r");try{Ns(n)}catch{}}}catch(o){try{await Mt(i)}catch{}throw o}}serializeTable(t){let e=Array.from(t.entries()).map(([r,s])=>{let i=s.dictionaryName?this.dictionaries.get(s.dictionaryName):void 0,o={d:i?ae(s.value,i.deflate):s.value,v:s.version,t:s.timestamp,x:s.expiration};return s.dictionaryName&&(o.n=s.dictionaryName),[r,o]});return Buffer.from(JSON.stringify(e),"utf8")}deserializeTable(t){let r=JSON.parse(t.toString("utf8")).map(([s,i])=>{let o=i.n,n=o?this.dictionaries.get(o):void 0;return[s,{value:n?ae(i.d,n.inflate):i.d,version:i.v,timestamp:i.t,expiration:i.x,dictionaryName:o||void 0}]});return new Map(r)}};import{join as Li}from"node:path";import Ti from"node:http";import{join as gt}from"node:path";var Ut=class{requests=new Map;limit;windowMs;constructor(t=100,e=60){this.limit=t,this.windowMs=e*1e3,setInterval(()=>this.cleanup(),this.windowMs)}getLimit(){return this.limit}isAllowed(t){let e=Date.now(),r=t||"unknown",s=this.requests.get(r);return(!s||s.resetTime<e)&&(s={count:0,resetTime:e+this.windowMs},this.requests.set(r,s)),s.count++,s.count<=this.limit}getRemainingRequests(t){let e=Date.now(),r=t||"unknown",s=this.requests.get(r);return!s||s.resetTime<e?this.limit:Math.max(0,this.limit-s.count)}getResetTime(t){let e=Date.now(),r=t||"unknown",s=this.requests.get(r);return!s||s.resetTime<e?Math.floor((e+this.windowMs)/1e3):Math.floor(s.resetTime/1e3)}cleanup(){let t=Date.now();for(let[e,r]of this.requests.entries())r.resetTime<t&&this.requests.delete(e)}};import{URL as zs}from"url";var Lt=class{routes=[];globalMiddlewares=[];pathPatterns=new Map;use(t){return this.globalMiddlewares.push(t),this}get(t,...e){let r=e.pop();return this.register("GET",t,r,e)}post(t,...e){let r=e.pop();return this.register("POST",t,r,e)}put(t,...e){let r=e.pop();return this.register("PUT",t,r,e)}delete(t,...e){let r=e.pop();return this.register("DELETE",t,r,e)}patch(t,...e){let r=e.pop();return this.register("PATCH",t,r,e)}any(t,...e){let r=e.pop(),s=e;return this.register("GET",t,r,s),this.register("POST",t,r,s),this.register("PUT",t,r,s),this.register("DELETE",t,r,s),this.register("PATCH",t,r,s),this.register("OPTIONS",t,r,s),this}options(t,...e){let r=e.pop();return this.register("OPTIONS",t,r,e)}match(t,e){for(let r of this.routes){if(r.method!==t)continue;let s=this.pathPatterns.get(r.path);if(!s)continue;let i=s.pattern.exec(e);if(!i)continue;let o={};return s.paramNames.forEach((n,a)=>{o[n]=i[a+1]||""}),{route:r,params:o}}return null}async handle(t,e){let r=t.method||"GET",s=new zs(t.url||"/",`http://${t.headers.host}`),i=s.pathname,o=this.match(r,i);if(!o)return null;let{route:n,params:a}=o,c={};s.searchParams.forEach((u,h)=>{c[h]=u});let l={req:t,res:e,params:a,query:c,body:t.body||{},headers:t.headers,path:i,state:{},raw:()=>e,binary:(u,h="application/octet-stream",v=200)=>({statusCode:v,body:u,headers:{"Content-Type":h,"Content-Length":u.length.toString()},isRaw:!0}),text:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"text/plain"}}),form:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),json:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"application/json"}}),html:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"text/html"}}),redirect:(u,h=302)=>({statusCode:h,body:null,headers:{Location:u}}),status:function(u){return{raw:()=>e,binary:(h,v="application/octet-stream")=>({statusCode:u,body:h,headers:{"Content-Type":v,"Content-Length":h.length.toString()},isRaw:!0}),text:h=>({statusCode:u,body:h,headers:{"Content-Type":"text/plain"}}),json:h=>({statusCode:u,body:h,headers:{"Content-Type":"application/json"}}),html:h=>({statusCode:u,body:h,headers:{"Content-Type":"text/html"}}),form:h=>({statusCode:u,body:h,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),redirect:(h,v=302)=>({statusCode:v,body:null,headers:{Location:h}}),status:h=>this.status(h)}}},p=[...this.globalMiddlewares,...n.middlewares];return this.executeMiddlewareChain(l,p,n.handler)}register(t,e,r,s=[]){return this.routes.push({method:t,path:e,handler:r,middlewares:s}),this.pathPatterns.set(e,this.createPathPattern(e)),this}createPathPattern(t){let e=[],r=t.replace(/\/:[^/]+/g,s=>{let i=s.slice(2);return e.push(i),"/([^/]+)"});return r.endsWith("/*")?(r=`${r.slice(0,-2)}(?:/(.*))?`,e.push("wildcard")):r=r.replace(/\/$/,"/?"),{pattern:new RegExp(`^${r}$`),paramNames:e}}async executeMiddlewareChain(t,e,r){let s=0,i=async()=>{if(s<e.length){let o=e[s++];return o(t,i)}return r(t)};return i()}};var Te=()=>({port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",debug:Ws(process.env.DEBUG)||!1,maxBodySize:1048576,requestTimeout:3e4,rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"]});function Ws(t){return t==="true"||t===!0}var V=Te(),Ht=t=>({configFilePath:"mikroserve.config.json",args:process.argv,options:[{flag:"--port",path:"port",defaultValue:V.port},{flag:"--host",path:"host",defaultValue:V.host},{flag:"--https",path:"useHttps",defaultValue:V.useHttps,isFlag:!0},{flag:"--http2",path:"useHttp2",defaultValue:V.useHttp2,isFlag:!0},{flag:"--cert",path:"sslCert",defaultValue:V.sslCert},{flag:"--key",path:"sslKey",defaultValue:V.sslKey},{flag:"--ca",path:"sslCa",defaultValue:V.sslCa},{flag:"--ratelimit",path:"rateLimit.enabled",defaultValue:V.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"rateLimit.requestsPerMinute",defaultValue:V.rateLimit.requestsPerMinute},{flag:"--allowed",path:"allowedDomains",defaultValue:V.allowedDomains,parser:te.array},{flag:"--debug",path:"debug",defaultValue:V.debug,isFlag:!0},{flag:"--max-body-size",path:"maxBodySize",defaultValue:V.maxBodySize},{flag:"--request-timeout",path:"requestTimeout",defaultValue:V.requestTimeout}],config:t});function Dt(t,e){let r=e.match(/boundary=(?:"([^"]+)"|([^;]+))/i);if(!r)throw new Error("Invalid multipart/form-data: missing boundary");let s=r[1]||r[2],i=Buffer.from(`--${s}`),o=Buffer.from(`--${s}--`),n={},a={},c=Gs(t,i);for(let l of c){if(l.length===0||l.equals(o.subarray(i.length)))continue;let p=Ks(l);if(!p)continue;let{name:u,filename:h,contentType:v,data:R}=p;if(h){let S={filename:h,contentType:v||"application/octet-stream",data:R,size:R.length};a[u]?Array.isArray(a[u])?a[u].push(S):a[u]=[a[u],S]:a[u]=S}else{let S=R.toString("utf8");n[u]?Array.isArray(n[u])?n[u].push(S):n[u]=[n[u],S]:n[u]=S}}return{fields:n,files:a}}function Gs(t,e){let r=[],s=0;for(;s<t.length;){let i=t.indexOf(e,s);if(i===-1)break;s!==i&&r.push(t.subarray(s,i)),s=i+e.length,s<t.length&&t[s]===13&&t[s+1]===10&&(s+=2)}return r}function Ks(t){let e=Buffer.from(`\r
111
+ `},Ts=class{constructor(t){this.options=t}sentEmails=[];async sendMail(t){this.sentEmails.push(t),this.options?.logToConsole&&(console.log("Email sent:"),console.log(`From: ${t.from}`),console.log(`To: ${t.to}`),console.log(`Subject: ${t.subject}`),console.log(`Text: ${t.text}`)),this.options?.onSend&&this.options.onSend(t)}getSentEmails(){return[...this.sentEmails]}clearSentEmails(){this.sentEmails=[]}},Rs=class{data=new Map;collections=new Map;expiryEmitter=new ks;expiryCheckInterval;constructor(t=1e3){this.expiryCheckInterval=setInterval(()=>this.checkExpiredItems(),t)}destroy(){clearInterval(this.expiryCheckInterval),this.data.clear(),this.collections.clear(),this.expiryEmitter.removeAllListeners()}checkExpiredItems(){let t=Date.now();for(let[e,r]of this.data.entries())r.expiry&&r.expiry<t&&(this.data.delete(e),this.expiryEmitter.emit("expired",e));for(let[e,r]of this.collections.entries())r.expiry&&r.expiry<t&&(this.collections.delete(e),this.expiryEmitter.emit("expired",e))}async set(t,e,r){let s=r?Date.now()+r*1e3:null;this.data.set(t,{value:e,expiry:s})}async get(t){let e=this.data.get(t);return e?e.expiry&&e.expiry<Date.now()?(this.data.delete(t),null):e.value:null}async delete(t){this.data.delete(t),this.collections.delete(t)}async addToCollection(t,e,r){this.collections.has(t)||this.collections.set(t,{items:[],expiry:r?Date.now()+r*1e3:null});let s=this.collections.get(t);s&&(r&&(s.expiry=Date.now()+r*1e3),s.items.push(e))}async removeFromCollection(t,e){let r=this.collections.get(t);r&&(r.items=r.items.filter(s=>s!==e))}async getCollection(t){let e=this.collections.get(t);return e?[...e.items]:[]}async getCollectionSize(t){let e=this.collections.get(t);return e?e.items.length:0}async removeOldestFromCollection(t){let e=this.collections.get(t);return!e||e.items.length===0?null:e.items.shift()||null}async findKeys(t){let e=t.replace(/\*/g,".*").replace(/\?/g,"."),r=new RegExp(`^${e}$`),s=Array.from(this.data.keys()).filter(o=>r.test(o)),i=Array.from(this.collections.keys()).filter(o=>r.test(o));return[...new Set([...s,...i])]}};function Tt(t){if(!t||t.trim()===""||(t.match(/@/g)||[]).length!==1)return!1;let[e,r]=t.split("@");return!(!e||!r||t.includes("..")||!js(e)||!$s(r))}function js(t){return t.startsWith('"')&&t.endsWith('"')?!t.slice(1,-1).includes('"'):t.length>64||t.startsWith(".")||t.endsWith(".")?!1:/^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$/.test(t)}function $s(t){if(t.startsWith("[")&&t.endsWith("]")){let r=t.slice(1,-1);return r.startsWith("IPv6:")?Us(r.slice(5)):Os(r)}let e=t.split(".");if(e.length===0)return!1;for(let r of e)if(!r||r.length>63||!/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/.test(r))return!1;if(e.length>1){let r=e[e.length-1];if(!/^[a-zA-Z]{2,}$/.test(r))return!1}return!0}function Os(t){return/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/.test(t)}function Us(t){if(!/^[a-fA-F0-9:]+$/.test(t))return!1;let e=t.split(":");return!(e.length<2||e.length>8)}var I=et(),Ms=t=>{let e={configFilePath:"mikroauth.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:I.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:I.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:I.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:I.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:I.auth.maxActiveSessions},{flag:"--appUrl",path:"auth.appUrl",defaultValue:I.auth.appUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:I.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:I.email.host},{flag:"--emailUser",path:"email.user",defaultValue:I.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:I.email.password},{flag:"--emailPort",path:"email.port",defaultValue:I.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:I.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:I.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:I.email.debug},{flag:"--dir",path:"storage.databaseDirectory",defaultValue:I.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:I.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:I.storage.debug},{flag:"--port",path:"server.port",defaultValue:I.server.port},{flag:"--host",path:"server.host",defaultValue:I.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:I.server.useHttps},{flag:"--https",path:"server.useHttp2",isFlag:!0,defaultValue:I.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:I.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:I.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:I.server.sslCa},{flag:"--ratelimit",path:"server.rateLimit.enabled",defaultValue:I.server.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"server.rateLimit.requestsPerMinute",defaultValue:I.server.rateLimit.requestsPerMinute},{flag:"--allowed",path:"server.allowedDomains",defaultValue:I.server.allowedDomains,parser:te.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:I.server.debug}]};return t&&(e.config=t),e},Ie={linkSent:"If a matching account was found, a magic link has been sent.",revokedSuccess:"All other sessions revoked successfully.",logoutSuccess:"Logged out successfully."},Rt=class{config;email;storage;jwtService;templates;constructor(t,e,r){let s=new ee(Ms({auth:t.auth,email:t.email})).get();s.auth.debug&&console.log("Using configuration:",s),this.config=s,this.email=e||new Ts,this.storage=r||new Rs,this.jwtService=new Is(s.auth.jwtSecret),this.templates=new Es(s?.auth.templates),this.checkIfUsingDefaultCredentialsInProduction()}checkIfUsingDefaultCredentialsInProduction(){process.env.NODE_ENV==="production"&&this.config.auth.jwtSecret===et().auth.jwtSecret&&(console.error("WARNING: Using default secrets in production environment!"),process.exit(1))}generateToken(t){let e=Date.now().toString(),r=re.randomBytes(32).toString("hex");return re.createHash("sha256").update(`${t}:${e}:${r}`).digest("hex")}generateJsonWebToken(t){return this.jwtService.sign({sub:t.id,email:t.email,username:t.username,role:t.role,exp:Math.floor(Date.now()/1e3)+3600*24})}generateRefreshToken(){return re.randomBytes(40).toString("hex")}async trackSession(t,e,r){let s=`sessions:${t}`;if(await this.storage.getCollectionSize(s)>=this.config.auth.maxActiveSessions){let i=await this.storage.removeOldestFromCollection(s);i&&await this.storage.delete(`refresh:${i}`)}await this.storage.addToCollection(s,e,this.config.auth.refreshTokenExpirySeconds),await this.storage.set(`refresh:${e}`,JSON.stringify(r),this.config.auth.refreshTokenExpirySeconds)}generateMagicLinkUrl(t){let{token:e,email:r,appUrl:s}=t,i=s||this.config.auth.appUrl;try{return new Cs(i),`${i}?token=${encodeURIComponent(e)}&email=${encodeURIComponent(r)}`}catch{throw new Error("Invalid base URL configuration")}}async createMagicLink(t){let{email:e,ip:r,metadata:s,appUrl:i,subject:o}=t;if(!Tt(e))throw new Error("Valid email required");try{let n=this.generateToken(e),a=`magic_link:${n}`,c={email:e,ipAddress:r||"unknown",createdAt:Date.now()};await this.storage.set(a,JSON.stringify(c),this.config.auth.magicLinkExpirySeconds);let l=await this.storage.findKeys("magic_link:*");for(let h of l){if(h===a)continue;let v=await this.storage.get(h);if(v)try{JSON.parse(v).email===e&&await this.storage.delete(h)}catch{}}let p=this.generateMagicLinkUrl({token:n,email:e,appUrl:i}),u=Math.ceil(this.config.auth.magicLinkExpirySeconds/60);return await this.email.sendMail({from:this.config.email.user,to:e,subject:o||this.config.email.emailSubject,text:this.templates.getText(p,u,s),html:this.templates.getHtml(p,u,s)}),{message:Ie.linkSent}}catch(n){throw console.error(`Failed to process magic link request: ${n}`),new Error("Failed to process magic link request")}}async createToken(t){let{email:e,username:r,role:s,ip:i}=t;if(!Tt(e))throw new Error("Valid email required");try{let o=re.randomBytes(16).toString("hex"),n=this.generateRefreshToken(),a=Date.now(),c={sub:e,username:r,role:s,jti:o,lastLogin:a,metadata:{ip:i||"unknown"},exp:Math.floor(Date.now()/1e3)+3600*24},l=this.jwtService.sign(c,{exp:this.config.auth.jwtExpirySeconds}),p={email:e,username:r,role:s,ipAddress:i||"unknown",tokenId:o,createdAt:a,lastLogin:a};return await this.trackSession(e,n,p),{accessToken:l,refreshToken:n,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(o){throw console.error("Token creation error:",o),new Error("Token creation failed")}}async verifyToken(t){let{token:e,email:r}=t;try{let s=`magic_link:${e}`,i=await this.storage.get(s);if(!i)throw new Error("Invalid or expired token");let o=JSON.parse(i);if(o.email!==r)throw new Error("Email mismatch");let n=o.username,a=o.role;await this.storage.delete(s);let c=re.randomBytes(16).toString("hex"),l=this.generateRefreshToken(),p={sub:r,username:n,role:a,jti:c,lastLogin:o.createdAt,metadata:{ip:o.ipAddress},exp:Math.floor(Date.now()/1e3)+3600*24},u=this.jwtService.sign(p,{exp:this.config.auth.jwtExpirySeconds});return await this.trackSession(r,l,{...o,tokenId:c,createdAt:Date.now()}),{accessToken:u,refreshToken:l,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(s){throw console.error("Token verification error:",s),new Error("Verification failed")}}async refreshAccessToken(t){try{let e=await this.storage.get(`refresh:${t}`);if(!e)throw new Error("Invalid or expired refresh token");let r=JSON.parse(e),s=r.email;if(!s)throw new Error("Invalid refresh token data");let i=r.username,o=r.role,n=re.randomBytes(16).toString("hex"),a={sub:s,username:i,role:o,jti:n,lastLogin:r.lastLogin||r.createdAt,metadata:{ip:r.ipAddress}},c=this.jwtService.sign(a,{exp:this.config.auth.jwtExpirySeconds});return r.lastUsed=Date.now(),await this.storage.set(`refresh:${t}`,JSON.stringify(r),this.config.auth.refreshTokenExpirySeconds),{accessToken:c,refreshToken:t,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(e){throw console.error("Token refresh error:",e),new Error("Token refresh failed")}}verify(t){try{return this.jwtService.verify(t)}catch{throw new Error("Invalid token")}}async logout(t){try{if(!t||typeof t!="string")throw new Error("Refresh token is required");let e=await this.storage.get(`refresh:${t}`);if(!e)return{message:Ie.logoutSuccess};let r=JSON.parse(e).email;if(!r)throw new Error("Invalid refresh token data");await this.storage.delete(`refresh:${t}`);let s=`sessions:${r}`;return await this.storage.removeFromCollection(s,t),{message:Ie.logoutSuccess}}catch(e){throw console.error("Logout error:",e),new Error("Logout failed")}}async getSessions(t){try{if(!t.user?.email)throw new Error("User not authenticated");let e=t.user.email,r=t.body?.refreshToken,s=`sessions:${e}`,i=(await this.storage.getCollection(s)).map(async n=>{try{let a=await this.storage.get(`refresh:${n}`);if(!a)return await this.storage.removeFromCollection(s,n),null;let c=JSON.parse(a);return{id:`${n.substring(0,8)}...`,createdAt:c.createdAt||0,lastLogin:c.lastLogin||c.createdAt||0,lastUsed:c.lastUsed||c.createdAt||0,metadata:{ip:c.ipAddress},isCurrentSession:n===r}}catch{return await this.storage.removeFromCollection(s,n),null}}),o=(await Promise.all(i)).filter(Boolean);return o.sort((n,a)=>a.createdAt-n.createdAt),{sessions:o}}catch(e){throw console.error("Get sessions error:",e),new Error("Failed to fetch sessions")}}async revokeSessions(t){try{if(!t.user?.email)throw new Error("User not authenticated");let e=t.user.email,r=t.body?.refreshToken,s=`sessions:${e}`,i=await this.storage.getCollection(s);for(let o of i)r&&o===r||await this.storage.delete(`refresh:${o}`);return await this.storage.delete(s),r&&await this.storage.get(`refresh:${r}`)&&await this.storage.addToCollection(s,r,this.config.auth.refreshTokenExpirySeconds),{message:Ie.revokedSuccess}}catch(e){throw console.error("Revoke sessions error:",e),new Error("Failed to revoke sessions")}}authenticate(t,e){try{let r=t.headers?.authorization;if(!r||!r.startsWith("Bearer "))throw new Error("Authentication required");let s=r.split(" ")[1];try{let i=this.verify(s);t.user={email:i.sub},e()}catch{throw new Error("Invalid or expired token")}}catch(r){e(r)}}},Ls=class{key;algorithm="aes-256-gcm";keyLength=32;constructor(t){this.key=ws(t,"mikroauth-salt",this.keyLength)}encrypt(t){let e=Ss(12),r=bs(this.algorithm,this.key,e),s=Buffer.concat([r.update(t,"utf8"),r.final()]),i=r.getAuthTag();return`${e.toString("hex")}:${i.toString("hex")}:${s.toString("hex")}`}decrypt(t){let e=t.split(":");if(e.length!==3)throw new Error("Invalid encrypted data format");let[r,s,i]=e,o=Buffer.from(r,"hex"),n=Buffer.from(s,"hex"),a=Buffer.from(i,"hex"),c=xs(this.algorithm,this.key,o);return c.setAuthTag(n),Buffer.concat([c.update(a),c.final()]).toString("utf8")}},jt=class{db;encryption;PREFIX_KV="kv:";PREFIX_COLLECTION="coll:";TABLE_NAME="mikroauth";constructor(t,e){this.db=t,e&&(this.encryption=new Ls(e))}async start(){await this.db.start()}async close(){await this.db.close()}async set(t,e,r){let s=`${this.PREFIX_KV}${t}`,i=this.encryption?this.encryption.encrypt(e):e,o=r?Date.now()+r*1e3:void 0;await this.db.write(this.TABLE_NAME,s,i,o)}async get(t){let e=`${this.PREFIX_KV}${t}`,r=await this.db.get(this.TABLE_NAME,e);return r?this.encryption?this.encryption.decrypt(r):r:null}async delete(t){let e=`${this.PREFIX_KV}${t}`;await this.db.delete(this.TABLE_NAME,e)}async addToCollection(t,e,r){let s=`${this.PREFIX_COLLECTION}${t}`,i=await this.db.get(this.TABLE_NAME,s),o=[];if(i){let l=this.encryption?this.encryption.decrypt(i):i;o=JSON.parse(l)}o.includes(e)||o.push(e);let n=JSON.stringify(o),a=this.encryption?this.encryption.encrypt(n):n,c=r?Date.now()+r*1e3:void 0;await this.db.write(this.TABLE_NAME,s,a,c)}async removeFromCollection(t,e){let r=`${this.PREFIX_COLLECTION}${t}`,s=await this.db.get(this.TABLE_NAME,r);if(!s)return;let i=this.encryption?this.encryption.decrypt(s):s,o=JSON.parse(i);o=o.filter(c=>c!==e);let n=JSON.stringify(o),a=this.encryption?this.encryption.encrypt(n):n;await this.db.write(this.TABLE_NAME,r,a)}async getCollection(t){let e=`${this.PREFIX_COLLECTION}${t}`,r=await this.db.get(this.TABLE_NAME,e);if(!r)return[];let s=this.encryption?this.encryption.decrypt(r):r;return JSON.parse(s)}async getCollectionSize(t){return(await this.getCollection(t)).length}async removeOldestFromCollection(t){let e=`${this.PREFIX_COLLECTION}${t}`,r=await this.db.get(this.TABLE_NAME,e);if(!r)return null;let s=this.encryption?this.encryption.decrypt(r):r,i=JSON.parse(s);if(i.length===0)return null;let o=i.shift(),n=JSON.stringify(i),a=this.encryption?this.encryption.encrypt(n):n;return await this.db.write(this.TABLE_NAME,e,a),o}async findKeys(t){let e=t.replace(/\./g,"\\.").replace(/\*/g,".*").replace(/\?/g,"."),r=new RegExp(`^${e}$`),s=await this.db.get(this.TABLE_NAME);return Array.isArray(s)?s.filter(i=>{let o=i[0];return typeof o=="string"&&o.startsWith(this.PREFIX_KV)}).map(i=>i[0].substring(this.PREFIX_KV.length)).filter(i=>r.test(i)):[]}},$t=class{email;sender;constructor(t){this.sender=t.user,this.email=new Qe({config:t})}async sendMail(t){await this.email.send({from:this.sender,to:t.to,cc:t.cc,bcc:t.bcc,subject:t.subject,text:t.text,html:t.html})}};function Ee(t){if(!t.deflate&&!t.inflate)throw new Error("Dictionary must provide either deflate or inflate mapping");if(t.deflate&&t.inflate)throw new Error("Dictionary should provide only one of deflate or inflate (not both). The inverse will be auto-generated.");return t.deflate?{deflate:t.deflate,inflate:Ot(t.deflate)}:{deflate:Ot(t.inflate),inflate:t.inflate}}function Ot(t){let e={};for(let[r,s]of Object.entries(t))e[s]=r;return e}function ce(t,e){if(t==null||typeof t!="object")return t;if(Array.isArray(t))return t.map(s=>ce(s,e));let r={};for(let[s,i]of Object.entries(t)){let o=e[s]||s;r[o]=ce(i,e)}return r}function se(t){if(!t||typeof t!="string")throw new Error("Table name must be a non-empty string");if(t.length>255)throw new Error("Table name must not exceed 255 characters");if(t.includes("/")||t.includes("\\"))throw new Error("Table name must not contain path separators");if(t.includes(".."))throw new Error('Table name must not contain ".."');if(t.startsWith("."))throw new Error('Table name must not start with "."');if(t.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(t.toUpperCase()))throw new Error(`Table name "${t}" is reserved by the filesystem`)}function Pe(t){if(t==null)throw new Error("Key must be defined");if(typeof t!="string")throw new Error("Key must be a string");if(t.length===0)throw new Error("Key must not be empty");if(t.length>1024)throw new Error("Key must not exceed 1024 characters");if(t.includes("\0"))throw new Error("Key must not contain null bytes")}function Ut(t){if(t===void 0)throw new Error("Value must not be undefined (use null instead)");let e=typeof t;if(e==="function")throw new Error("Value must be JSON-serializable: functions are not supported");if(e==="symbol")throw new Error("Value must be JSON-serializable: symbols are not supported");try{if(JSON.stringify(t)===void 0)throw new Error("Value must be JSON-serializable: value cannot be serialized")}catch(r){throw new Error(`Value must be JSON-serializable: ${r instanceof Error?r.message:String(r)}`)}}import{existsSync as tt,mkdirSync as Hs,readdirSync as Ds,openSync as Ns,closeSync as Vs}from"fs";import{readFile as qs,writeFile as Fs,rename as Bs,unlink as Mt,open as _s}from"fs/promises";import{join as rt,dirname as zs}from"path";var ie=class{data=new Map;databaseDirectory;dictionaries=new Map;useFsync;constructor(t){this.databaseDirectory=t.databaseDirectory,this.useFsync=t.durableWrites??!1,t.dictionaries&&Object.entries(t.dictionaries).forEach(([e,r])=>{let s=Ee(r);this.dictionaries.set(e,s)}),tt(this.databaseDirectory)||Hs(this.databaseDirectory,{recursive:!0})}async start(){try{let t=Ds(this.databaseDirectory);for(let e of t)!e.endsWith(".tmp")&&!e.startsWith(".")&&await this.loadTable(e)}catch(t){throw console.error("Failed to start database:",t),t}}async write(t,e,r,s,i){if(se(t),Pe(e),Ut(r),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(t)||this.data.set(t,new Map);let o=this.data.get(t),a=(o.get(e)?.version||0)+1,c={value:r,version:a,timestamp:Date.now(),expiration:s||null,dictionaryName:i||void 0};return o.set(e,c),await this.persistTable(t),!0}catch(o){return console.error(`Write failed for ${t}:${e}:`,o),!1}}async get(t,e){se(t),e!==void 0&&Pe(e);try{this.data.has(t)||await this.loadTable(t);let r=this.data.get(t);if(!r)return e?void 0:[];if(e!==void 0){let o=r.get(e);if(!o)return;if(this.isExpired(o)){r.delete(e),await this.persistTable(t);return}return o.value}let s=[],i=[];for(let[o,n]of r.entries())this.isExpired(n)?i.push(o):s.push([o,n.value]);if(i.length>0){for(let o of i)r.delete(o);await this.persistTable(t)}return s}catch(r){return console.error(`Read failed for ${t}:${e}:`,r),e?void 0:[]}}async delete(t,e){se(t),Pe(e);try{this.data.has(t)||await this.loadTable(t);let r=this.data.get(t);if(!r||!r.has(e))return!1;let s=r.get(e);return s?this.isExpired(s)?(r.delete(e),await this.persistTable(t),!1):(r.delete(e),await this.persistTable(t),!0):!1}catch(r){return console.error(`Delete failed for ${t}:${e}:`,r),!1}}async getTableSize(t){se(t);try{this.data.has(t)||await this.loadTable(t);let e=this.data.get(t);if(!e)return 0;let r=0,s=[];for(let[i,o]of e.entries())this.isExpired(o)?s.push(i):r++;if(s.length>0){for(let i of s)e.delete(i);await this.persistTable(t)}return r}catch(e){return console.error(`Get table size failed for ${t}:`,e),0}}isExpired(t){return t.expiration===null?!1:Date.now()>t.expiration}async cleanupExpired(t){se(t);try{this.data.has(t)||await this.loadTable(t);let e=this.data.get(t);if(!e)return 0;let r=[];for(let[s,i]of e.entries())this.isExpired(i)&&r.push(s);for(let s of r)e.delete(s);return r.length>0&&await this.persistTable(t),r.length}catch(e){return console.error(`Cleanup failed for ${t}:`,e),0}}async cleanupAllExpired(){let t=0;for(let e of this.data.keys())t+=await this.cleanupExpired(e);return t}async deleteTable(t){se(t);try{this.data.delete(t);let e=rt(this.databaseDirectory,t);return tt(e)&&await Mt(e),!0}catch(e){return console.error(`Delete table failed for ${t}:`,e),!1}}listTables(){return Array.from(this.data.keys())}async flush(){try{let t=Array.from(this.data.keys()).map(e=>this.persistTable(e));await Promise.all(t)}catch(t){throw console.error("Flush failed:",t),t}}async close(){await this.flush()}addDictionary(t,e){let r=Ee(e);this.dictionaries.set(t,r)}removeDictionary(t){return this.dictionaries.delete(t)}listDictionaries(){return Array.from(this.dictionaries.keys())}async loadTable(t){let e=rt(this.databaseDirectory,t);if(!tt(e)){this.data.set(t,new Map);return}try{let r=await qs(e);if(r.length===0){this.data.set(t,new Map);return}let s=this.deserializeTable(r);this.data.set(t,s)}catch(r){console.error(`Failed to load table ${t}:`,r),this.data.set(t,new Map)}}async persistTable(t){let e=this.data.get(t);if(!e)return;let r=this.serializeTable(e),s=rt(this.databaseDirectory,t),i=`${s}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await Fs(i,r),this.useFsync){let o=await _s(i,"r+");try{await o.sync()}finally{await o.close()}}if(await Bs(i,s),this.useFsync){let o=zs(s),n=Ns(o,"r");try{Vs(n)}catch{}}}catch(o){try{await Mt(i)}catch{}throw o}}serializeTable(t){let e=Array.from(t.entries()).map(([r,s])=>{let i=s.dictionaryName?this.dictionaries.get(s.dictionaryName):void 0,o={d:i?ce(s.value,i.deflate):s.value,v:s.version,t:s.timestamp,x:s.expiration};return s.dictionaryName&&(o.n=s.dictionaryName),[r,o]});return Buffer.from(JSON.stringify(e),"utf8")}deserializeTable(t){let r=JSON.parse(t.toString("utf8")).map(([s,i])=>{let o=i.n,n=o?this.dictionaries.get(o):void 0;return[s,{value:n?ce(i.d,n.inflate):i.d,version:i.v,timestamp:i.t,expiration:i.x,dictionaryName:o||void 0}]});return new Map(r)}};import{join as Hi}from"node:path";import Ri from"node:http";import{join as yt}from"node:path";var Lt=class{requests=new Map;limit;windowMs;constructor(t=100,e=60){this.limit=t,this.windowMs=e*1e3,setInterval(()=>this.cleanup(),this.windowMs)}getLimit(){return this.limit}isAllowed(t){let e=Date.now(),r=t||"unknown",s=this.requests.get(r);return(!s||s.resetTime<e)&&(s={count:0,resetTime:e+this.windowMs},this.requests.set(r,s)),s.count++,s.count<=this.limit}getRemainingRequests(t){let e=Date.now(),r=t||"unknown",s=this.requests.get(r);return!s||s.resetTime<e?this.limit:Math.max(0,this.limit-s.count)}getResetTime(t){let e=Date.now(),r=t||"unknown",s=this.requests.get(r);return!s||s.resetTime<e?Math.floor((e+this.windowMs)/1e3):Math.floor(s.resetTime/1e3)}cleanup(){let t=Date.now();for(let[e,r]of this.requests.entries())r.resetTime<t&&this.requests.delete(e)}};import{URL as Ws}from"url";var Ht=class{routes=[];globalMiddlewares=[];pathPatterns=new Map;use(t){return this.globalMiddlewares.push(t),this}get(t,...e){let r=e.pop();return this.register("GET",t,r,e)}post(t,...e){let r=e.pop();return this.register("POST",t,r,e)}put(t,...e){let r=e.pop();return this.register("PUT",t,r,e)}delete(t,...e){let r=e.pop();return this.register("DELETE",t,r,e)}patch(t,...e){let r=e.pop();return this.register("PATCH",t,r,e)}any(t,...e){let r=e.pop(),s=e;return this.register("GET",t,r,s),this.register("POST",t,r,s),this.register("PUT",t,r,s),this.register("DELETE",t,r,s),this.register("PATCH",t,r,s),this.register("OPTIONS",t,r,s),this}options(t,...e){let r=e.pop();return this.register("OPTIONS",t,r,e)}match(t,e){for(let r of this.routes){if(r.method!==t)continue;let s=this.pathPatterns.get(r.path);if(!s)continue;let i=s.pattern.exec(e);if(!i)continue;let o={};return s.paramNames.forEach((n,a)=>{o[n]=i[a+1]||""}),{route:r,params:o}}return null}async handle(t,e){let r=t.method||"GET",s=new Ws(t.url||"/",`http://${t.headers.host}`),i=s.pathname,o=this.match(r,i);if(!o)return null;let{route:n,params:a}=o,c={};s.searchParams.forEach((u,h)=>{c[h]=u});let l={req:t,res:e,params:a,query:c,body:t.body||{},headers:t.headers,path:i,state:{},raw:()=>e,binary:(u,h="application/octet-stream",v=200)=>({statusCode:v,body:u,headers:{"Content-Type":h,"Content-Length":u.length.toString()},isRaw:!0}),text:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"text/plain"}}),form:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),json:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"application/json"}}),html:(u,h=200)=>({statusCode:h,body:u,headers:{"Content-Type":"text/html"}}),redirect:(u,h=302)=>({statusCode:h,body:null,headers:{Location:u}}),status:function(u){return{raw:()=>e,binary:(h,v="application/octet-stream")=>({statusCode:u,body:h,headers:{"Content-Type":v,"Content-Length":h.length.toString()},isRaw:!0}),text:h=>({statusCode:u,body:h,headers:{"Content-Type":"text/plain"}}),json:h=>({statusCode:u,body:h,headers:{"Content-Type":"application/json"}}),html:h=>({statusCode:u,body:h,headers:{"Content-Type":"text/html"}}),form:h=>({statusCode:u,body:h,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),redirect:(h,v=302)=>({statusCode:v,body:null,headers:{Location:h}}),status:h=>this.status(h)}}},p=[...this.globalMiddlewares,...n.middlewares];return this.executeMiddlewareChain(l,p,n.handler)}register(t,e,r,s=[]){return this.routes.push({method:t,path:e,handler:r,middlewares:s}),this.pathPatterns.set(e,this.createPathPattern(e)),this}createPathPattern(t){let e=[],r=t.replace(/\/:[^/]+/g,s=>{let i=s.slice(2);return e.push(i),"/([^/]+)"});return r.endsWith("/*")?(r=`${r.slice(0,-2)}(?:/(.*))?`,e.push("wildcard")):r=r.replace(/\/$/,"/?"),{pattern:new RegExp(`^${r}$`),paramNames:e}}async executeMiddlewareChain(t,e,r){let s=0,i=async()=>{if(s<e.length){let o=e[s++];return o(t,i)}return r(t)};return i()}};var Te=()=>({port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",debug:Gs(process.env.DEBUG)||!1,maxBodySize:1048576,requestTimeout:3e4,rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"]});function Gs(t){return t==="true"||t===!0}var V=Te(),Dt=t=>({configFilePath:"mikroserve.config.json",args:process.argv,options:[{flag:"--port",path:"port",defaultValue:V.port},{flag:"--host",path:"host",defaultValue:V.host},{flag:"--https",path:"useHttps",defaultValue:V.useHttps,isFlag:!0},{flag:"--http2",path:"useHttp2",defaultValue:V.useHttp2,isFlag:!0},{flag:"--cert",path:"sslCert",defaultValue:V.sslCert},{flag:"--key",path:"sslKey",defaultValue:V.sslKey},{flag:"--ca",path:"sslCa",defaultValue:V.sslCa},{flag:"--ratelimit",path:"rateLimit.enabled",defaultValue:V.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"rateLimit.requestsPerMinute",defaultValue:V.rateLimit.requestsPerMinute},{flag:"--allowed",path:"allowedDomains",defaultValue:V.allowedDomains,parser:te.array},{flag:"--debug",path:"debug",defaultValue:V.debug,isFlag:!0},{flag:"--max-body-size",path:"maxBodySize",defaultValue:V.maxBodySize},{flag:"--request-timeout",path:"requestTimeout",defaultValue:V.requestTimeout}],config:t});function Nt(t,e){let r=e.match(/boundary=(?:"([^"]+)"|([^;]+))/i);if(!r)throw new Error("Invalid multipart/form-data: missing boundary");let s=r[1]||r[2],i=Buffer.from(`--${s}`),o=Buffer.from(`--${s}--`),n={},a={},c=Ks(t,i);for(let l of c){if(l.length===0||l.equals(o.subarray(i.length)))continue;let p=Js(l);if(!p)continue;let{name:u,filename:h,contentType:v,data:R}=p;if(h){let S={filename:h,contentType:v||"application/octet-stream",data:R,size:R.length};a[u]?Array.isArray(a[u])?a[u].push(S):a[u]=[a[u],S]:a[u]=S}else{let S=R.toString("utf8");n[u]?Array.isArray(n[u])?n[u].push(S):n[u]=[n[u],S]:n[u]=S}}return{fields:n,files:a}}function Ks(t,e){let r=[],s=0;for(;s<t.length;){let i=t.indexOf(e,s);if(i===-1)break;s!==i&&r.push(t.subarray(s,i)),s=i+e.length,s<t.length&&t[s]===13&&t[s+1]===10&&(s+=2)}return r}function Js(t){let e=Buffer.from(`\r
112
112
  \r
113
113
  `),r=t.indexOf(e);if(r===-1)return null;let s=t.subarray(0,r),i=t.subarray(r+4),n=s.toString("utf8").split(`\r
114
- `),a="",c="",l,p;for(let h of n){let v=h.toLowerCase();if(v.startsWith("content-disposition:")){a=h.substring(20).trim();let R=a.match(/name="([^"]+)"/);R&&(c=R[1]);let S=a.match(/filename="([^"]+)"/);S&&(l=S[1])}else v.startsWith("content-type:")&&(p=h.substring(13).trim())}if(!c)return null;let u=i;return u.length>=2&&u[u.length-2]===13&&u[u.length-1]===10&&(u=u.subarray(0,u.length-2)),{disposition:a,name:c,filename:l,contentType:p,data:u}}import{readFileSync as ce}from"fs";import st from"http";import Js from"http2";import Xs from"https";var we=class{config;rateLimiter;router;shutdownHandlers=[];constructor(t){let e=new ee(Ht(t||{})).get();e.debug&&console.log("Using configuration:",e),this.config=e,this.router=new Lt;let r=e.rateLimit.requestsPerMinute||Te().rateLimit.requestsPerMinute;this.rateLimiter=new Ut(r,60),e.rateLimit.enabled===!0&&this.use(this.rateLimitMiddleware.bind(this))}use(t){return this.router.use(t),this}get(t,...e){return this.router.get(t,...e),this}post(t,...e){return this.router.post(t,...e),this}put(t,...e){return this.router.put(t,...e),this}delete(t,...e){return this.router.delete(t,...e),this}patch(t,...e){return this.router.patch(t,...e),this}any(t,...e){return this.router.any(t,...e),this}options(t,...e){return this.router.options(t,...e),this}start(){let t=this.createServer(),{port:e,host:r}=this.config;return this.setupGracefulShutdown(t),t.listen(e,r,()=>{let s=t.address(),i=this.config.useHttps||this.config.useHttp2?"https":"http";console.log(`MikroServe running at ${i}://${s.address!=="::"?s.address:"localhost"}:${s.port}`)}),t}createServer(){let t=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 e={key:ce(this.config.sslKey),cert:ce(this.config.sslCert),...this.config.sslCa?{ca:ce(this.config.sslCa)}:{}};return Js.createSecureServer(e,t)}catch(e){throw e.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${e.message}`):e}}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 e={key:ce(this.config.sslKey),cert:ce(this.config.sslCert),...this.config.sslCa?{ca:ce(this.config.sslCa)}:{}};return Xs.createServer(e,t)}catch(e){throw e.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${e.message}`):e}}return st.createServer(t)}async rateLimitMiddleware(t,e){let r=t.req.socket.remoteAddress||"unknown";return t.res.setHeader("X-RateLimit-Limit",this.rateLimiter.getLimit().toString()),t.res.setHeader("X-RateLimit-Remaining",this.rateLimiter.getRemainingRequests(r).toString()),t.res.setHeader("X-RateLimit-Reset",this.rateLimiter.getResetTime(r).toString()),this.rateLimiter.isAllowed(r)?e():{statusCode:429,body:{error:"Too Many Requests",message:"Rate limit exceeded, please try again later"},headers:{"Content-Type":"application/json"}}}async requestHandler(t,e){let r=Date.now(),s=t.method||"UNKNOWN",i=t.url||"/unknown",o=this.config.debug;try{if(this.setCorsHeaders(e,t),this.setSecurityHeaders(e,this.config.useHttps),o&&console.log(`${s} ${i}`),t.method==="OPTIONS"){if(e instanceof st.ServerResponse)e.statusCode=204,e.end();else{let a=e;a.writeHead(204),a.end()}return}try{t.body=await this.parseBody(t)}catch(a){return o&&console.error("Body parsing error:",a.message),this.respond(e,{statusCode:400,body:{error:"Bad Request",message:a.message}})}let n=await this.router.handle(t,e);return n?n._handled?void 0:this.respond(e,n):this.respond(e,{statusCode:404,body:{error:"Not Found",message:"The requested endpoint does not exist"}})}catch(n){return console.error("Server error:",n),this.respond(e,{statusCode:500,body:{error:"Internal Server Error",message:o?n.message:"An unexpected error occurred"}})}finally{o&&this.logDuration(r,s,i)}}logDuration(t,e,r){let s=Date.now()-t;console.log(`${e} ${r} completed in ${s}ms`)}async parseBody(t){return new Promise((e,r)=>{let s=[],i=0,o=this.config.maxBodySize,n=!1,a=null,c=this.config.debug,l=t.headers["content-type"]||"";c&&console.log("Content-Type:",l),this.config.requestTimeout>0&&(a=setTimeout(()=>{n||(n=!0,c&&console.log("Request timeout exceeded"),r(new Error("Request timeout")))},this.config.requestTimeout));let p=()=>{a&&(clearTimeout(a),a=null)};t.on("data",u=>{if(!n){if(i+=u.length,c&&console.log(`Received chunk: ${u.length} bytes, total size: ${i}`),i>o){n=!0,p(),c&&console.log(`Body size exceeded limit: ${i} > ${o}`),r(new Error("Request body too large"));return}s.push(u)}}),t.on("end",()=>{if(!n){n=!0,p(),c&&console.log(`Request body complete: ${i} bytes`);try{if(s.length>0){let u=Buffer.concat(s);if(l.includes("application/json"))try{let h=u.toString("utf8");e(JSON.parse(h))}catch(h){r(new Error(`Invalid JSON in request body: ${h.message}`))}else if(l.includes("application/x-www-form-urlencoded")){let h=u.toString("utf8"),v={};new URLSearchParams(h).forEach((R,S)=>{v[S]=R}),e(v)}else if(l.includes("multipart/form-data"))try{let h=Dt(u,l);e(h)}catch(h){r(new Error(`Invalid multipart form data: ${h.message}`))}else this.isBinaryContentType(l)?e(u):e(u.toString("utf8"))}else e({})}catch(u){r(new Error(`Invalid request body: ${u}`))}}}),t.on("error",u=>{n||(n=!0,p(),r(new Error(`Error reading request body: ${u.message}`)))}),t.on("close",()=>{p()})})}isBinaryContentType(t){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(r=>t.includes(r))}setCorsHeaders(t,e){let r=e.headers.origin,{allowedDomains:s=["*"]}=this.config;!r||s.length===0||s.includes("*")?t.setHeader("Access-Control-Allow-Origin","*"):s.includes(r)&&(t.setHeader("Access-Control-Allow-Origin",r),t.setHeader("Vary","Origin")),t.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),t.setHeader("Access-Control-Max-Age","86400")}setSecurityHeaders(t,e=!1){let r={"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((e||this.config.useHttp2)&&(r["Strict-Transport-Security"]="max-age=31536000; includeSubDomains"),t instanceof st.ServerResponse)Object.entries(r).forEach(([s,i])=>{t.setHeader(s,i)});else{let s=t;Object.entries(r).forEach(([i,o])=>{s.setHeader(i,o)})}}respond(t,e){let r={...e.headers||{}};(i=>typeof i.writeHead=="function"&&typeof i.end=="function")(t)?(t.writeHead(e.statusCode,r),e.body===null||e.body===void 0?t.end():e.isRaw||typeof e.body=="string"?t.end(e.body):t.end(JSON.stringify(e.body))):(console.warn("Unexpected response object type without writeHead/end methods"),t.writeHead?.(e.statusCode,r),e.body===null||e.body===void 0?t.end?.():e.isRaw||typeof e.body=="string"?t.end?.(e.body):t.end?.(JSON.stringify(e.body)))}setupGracefulShutdown(t){let e=n=>{console.log("Shutting down MikroServe server..."),n&&console.error("Error:",n),this.cleanupShutdownHandlers(),t.close(()=>{console.log("Server closed successfully"),process.env.NODE_ENV!=="test"&&process.env.VITEST!=="true"&&setImmediate(()=>process.exit(n?1:0))})},r=()=>e(),s=()=>e(),i=n=>e(n),o=n=>e(n);this.shutdownHandlers=[r,s,i,o],process.on("SIGINT",r),process.on("SIGTERM",s),process.on("uncaughtException",i),process.on("unhandledRejection",o)}cleanupShutdownHandlers(){if(this.shutdownHandlers.length>0){let[t,e,r,s]=this.shutdownHandlers;process.removeListener("SIGINT",t),process.removeListener("SIGTERM",e),process.removeListener("uncaughtException",r),process.removeListener("unhandledRejection",s),this.shutdownHandlers=[]}}};import{timingSafeEqual as Ys}from"node:crypto";var le="x-molnos-cluster-secret";function Nt(t,e){if(!t)return!1;let r=Buffer.from(t),s=Buffer.from(e);return r.length!==s.length?!1:Ys(r,s)}function Se(t){return async(e,r)=>{let s=e.headers[le];return s?Nt(s,t)?(e.state.isClusterRequest=!0,r()):e.json({success:!1,error:"Invalid cluster authentication"},403):r()}}var x=class extends Error{constructor(e){super(),this.name="ValidationError",this.message=e||"Invalid input",this.cause={statusCode:400}}},be=class extends Error{constructor(e){super(),this.name="IdentityAlreadyExistsError",this.message=e||"Identity already exists",this.cause={statusCode:400}}},F=class extends Error{constructor(e){super(),this.name="NotFoundError",this.message=e||"Resource not found",this.cause={statusCode:404}}},Re=class extends Error{constructor(e){super(),this.name="InvalidInputError",this.message=e||"Invalid input",this.cause={statusCode:400}}};var je=class extends Error{constructor(e){super(),this.name="ConfigurationError",this.message=e||"Invalid configuration",this.cause={statusCode:400}}};var ue=class extends Error{constructor(e){super(),this.name="PermissionDeniedError",this.message=e||"Permission denied",this.cause={statusCode:403}}},z=class extends Error{constructor(e){super(),this.name="AlreadyExistsError",this.message=e||"Resource already exists",this.cause={statusCode:409}}},$e=class extends Error{constructor(e){super(),this.name="PortInUseError",this.message=e||"Port already in use",this.cause={statusCode:409}}},xe=class extends Error{constructor(e){super(),this.name="RoleNotFoundError",this.message=e||"Role not found",this.cause={statusCode:404}}},Oe=class extends Error{constructor(e){super(),this.name="ProtectedResourceError",this.message=e||"Cannot modify protected resource",this.cause={statusCode:403}}},Me=class extends Error{constructor(e){super(),this.name="ServiceRequestError",this.message=e||"Service request failed",this.cause={statusCode:502}}},Ue=class extends Error{constructor(e){super(),this.name="WorkerUnavailableError",this.message=e||"Worker node is unavailable",this.cause={statusCode:503}}},Le=class extends Error{constructor(e){super(),this.name="WorkerTimeoutError",this.message=e||"Worker node did not respond in time",this.cause={statusCode:504}}};var Zs=5e3;async function it(t,e,r,s,i,o){let n=new URL(e,t.url),a=new Headers;for(let[u,h]of Object.entries(i)){let v=u.toLowerCase();v==="host"||v==="connection"||v==="keep-alive"||v==="transfer-encoding"||a.set(u,h)}o&&a.set(le,o);let c=t.timeoutMs||Zs,l=new AbortController,p=setTimeout(()=>l.abort(),c);try{let u;s&&(Buffer.isBuffer(s)?u=new Uint8Array(s):u=s);let h=await fetch(n.toString(),{method:r,headers:a,body:u,signal:l.signal});return clearTimeout(p),h}catch(u){throw clearTimeout(p),u.name==="AbortError"?new Le(`Worker at ${t.url} did not respond within ${c}ms`):new Ue(`Worker at ${t.url} is unavailable: ${u.message}`)}}async function ot(t,e){let r=e.headers.get("content-type")||"",s=e.status;if(r.includes("application/json")){let n=await e.text();try{let a=JSON.parse(n);return t.json(a,s)}catch{return t.text(n,s)}}if(r.startsWith("text/")||r.includes("javascript")||r.includes("xml")){let n=await e.text();return t.text(n,s)}let i=await e.arrayBuffer(),o=t.binary(Buffer.from(i),r||"application/octet-stream");return s!==200?{...o,statusCode:s}:o}var He={healthCheckPath:"/health",healthCheckIntervalMs:3e4,timeoutMs:5e3,failureThreshold:3},Ce=class{workers=new Map;timers=new Map;async registerWorkers(e){let r=Object.keys(e);for(let s of r){let i=e[s];i&&await this.registerWorker(s,i)}}async registerWorker(e,r){let s={url:r.url,capability:e,healthy:!0,consecutiveFailures:0,timeoutMs:r.timeoutMs||He.timeoutMs};this.workers.set(e,s);let i=r.healthCheckIntervalMs||He.healthCheckIntervalMs,o=r.healthCheckPath||He.healthCheckPath,n=setInterval(()=>this.checkHealth(e,o),i);this.timers.set(e,n),await this.checkHealth(e,o)}async checkHealth(e,r){let s=this.workers.get(e);if(s){try{let i=new AbortController,o=setTimeout(()=>i.abort(),s.timeoutMs),n=await fetch(`${s.url}${r}`,{method:"GET",signal:i.signal});clearTimeout(o),n.ok?this.handleSuccess(s):this.handleFailure(s)}catch{this.handleFailure(s)}s.lastHealthCheck=new Date}}handleSuccess(e){e.healthy||console.log(`[WorkerHealthChecker] Worker ${e.capability} at ${e.url} is now healthy`),e.healthy=!0,e.consecutiveFailures=0}handleFailure(e){e.consecutiveFailures++,e.consecutiveFailures>=He.failureThreshold&&(e.healthy&&console.error(`[WorkerHealthChecker] Worker ${e.capability} at ${e.url} is now unhealthy (${e.consecutiveFailures} consecutive failures)`),e.healthy=!1)}isHealthy(e){return this.workers.get(e)?.healthy??!1}getWorkerState(e){return this.workers.get(e)}getAllWorkerStates(){return new Map(this.workers)}hasWorker(e){return this.workers.has(e)}shutdown(){for(let e of this.timers.values())clearInterval(e);this.timers.clear(),this.workers.clear()}};import oi from"node:crypto";import{getRandomValues as Qs}from"node:crypto";var nt=class{options;defaultLength=16;defaultOnlyLowerCase=!1;defaultStyle="extended";defaultUrlSafe=!0;constructor(t){if(this.options={},t)for(let[e,r]of Object.entries(t))this.options[e]=this.generateConfig(r)}add(t){if(!t?.name)throw new Error("Missing name for the ID configuration");let e=this.generateConfig(t);this.options[t.name]=e}remove(t){if(!t?.name)throw new Error("Missing name for the ID configuration");delete this.options[t.name]}create(t,e,r,s){let i=this.generateConfig({length:t,style:e,onlyLowerCase:r,urlSafe:s});return this.generateId(i)}custom(t){if(this.options[t])return this.generateId(this.options[t]);throw new Error(`No configuration found with name: ${t}`)}generateConfig(t){return{name:t?.name||"",length:t?.length||this.defaultLength,onlyLowerCase:t?.onlyLowerCase??this.defaultOnlyLowerCase,style:t?.style||this.defaultStyle,urlSafe:t?.urlSafe??this.defaultUrlSafe}}getCharacterSet(t,e,r){if(t==="hex")return e?"0123456789abcdef":"0123456789ABCDEFabcdef";if(t==="alphanumeric")return e?"abcdefghijklmnopqrstuvwxyz0123456789":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";if(t==="extended")return r?e?"abcdefghijklmnopqrstuvwxyz0123456789-._~":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~":e?"abcdefghijklmnopqrstuvwxyz0123456789-._~!$()*+,;=:":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$()*+,;=:";throw new Error(`Unknown ID style "${t} provided. Must be one of "extended" (default), "alphanumeric", or "hex".`)}generateId(t){let{length:e,onlyLowerCase:r,style:s,urlSafe:i}=t;if(e<0||e===0)throw new Error("ID length cannot be negative");let o=this.getCharacterSet(s,r,i),n=(2<<Math.log(o.length-1)/Math.LN2)-1,a=Math.ceil(1.6*n*e/o.length),c="";for(;c.length<e;){let l=new Uint8Array(a);Qs(l);for(let p=0;p<a;p++){let u=l[p]&n;if(u<o.length&&(c+=o[u],c.length===e))break}}return c}};var ei=8,ti=40,ri=/^[a-zA-Z0-9_-]{1,40}$/;function ke(){return new nt().create(ei,"alphanumeric",!1,!0)}function si(t){return ri.test(t)}function ii(t){if(!si(t))throw new Error(`Invalid ID format: "${t}". IDs must be 1-${ti} characters using only alphanumeric characters, underscores, and hyphens.`)}function De(t){return t?(ii(t),t):ke()}function qt(t,e,r){if(!r)return!1;let s=typeof t=="string"?[t]:t,i=typeof e=="string"?[e]:e;if(r.roles?.some(a=>a==="administrator"||a.id==="administrator"))return!0;let n=(r.roles||[]).flatMap(a=>typeof a=="string"?[]:(a.policies||[]).flatMap(l=>l?.permissions&&l?.targets?{permissions:l.permissions,targets:l.targets}:[]));for(let a of s)for(let c of i)if(!n.some(p=>Vt(p?.permissions,a)&&Vt(p?.targets,c)))return!1;return!0}function Vt(t,e){return!t||t.length===0?!1:t.some(r=>{if(r==="*"||r===e)return!0;if(r.endsWith("*")&&r!=="*"){let s=r.slice(0,-1);return e.startsWith(s)}return!1})}var oe=class{id;name;type;roles;metadata;constructor(e){let{id:r,name:s,type:i,roles:o,metadata:n}=this.createIdentity(e);this.id=r,this.name=s,this.type=i,this.roles=o,this.metadata=n}createIdentity(e){let r=e?.id||this.createId(),s=e?.name||"",i=e?.type||"service_account",o=e?.metadata||{},n=e?.roles||["user"];return e&&this.validate({id:r,name:s,type:i,metadata:o,roles:n}),{id:r,name:s,type:i,metadata:{...o,createdAt:new Date().toISOString()},roles:n}}changeName(e){this.name=e}changeEmail(e){this.metadata||(this.metadata={}),this.metadata.email=e}updateMetadata(e){let r=this.metadata?JSON.parse(JSON.stringify(this.metadata)):{};this.metadata={...r,...e}}updateRoles(e){this.validateRoles(e),this.roles=e}createId(){return De()}isValidRoleId(e){return typeof e!="string"||e.length===0?!1:/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)}isValidType(e){return["user","service_account"].includes(e)}validate(e){let r=e.id||"",s=e.name||"",i=e.type||"",o=e.metadata||{},n=e.roles||[];if(!r)throw new x("Missing ID");if(!s)throw new x("Missing name");if(!i||!this.isValidType(i))throw new x("Missing or invalid type");if(i==="user"&&!o?.email)throw new x("Missing email for user identity");if(!n||n.length===0)throw new x("Must have at least one role");this.validateRoles(n)}validateRoles(e){(e||[]).forEach(r=>{let s=r.id||r;if(!this.isValidRoleId(s))throw new x(`Invalid role ID '${s}'`)})}can(e,r,s){return qt(e,r,s)}fromDTO(e){return this.validate(e),this.id=e.id,this.name=e.name,this.type=e.type,this.metadata=e.metadata||{},this.roles=e.roles,this}toDTO(){return{id:this.id,name:this.name,type:this.type,metadata:this.metadata,roles:this.roles}}};function Ft(){return[{id:"administrator",name:"Administrator",description:"Full system administrator with all permissions",policies:[{permissions:["*"],targets:["*"]}],constraints:{assumable_by:{identities:[],roles:[],services:[]},assumption_constraints:{max_duration:3600,require_reason:!0,audit_level:"high"}}},{id:"user",name:"User",description:"Read-only access to resources",policies:[{permissions:["*.read"],targets:["*"]}],constraints:{assumable_by:{identities:[],roles:[],services:[]},assumption_constraints:{max_duration:3600,require_reason:!1,audit_level:"low"}}}]}var Ne=class{mikroAuth;db;tableName="identity_service";initialUser;roles;identities;serviceAccountTokens;constructor(e,r,s){this.mikroAuth=e,this.db=r,this.initialUser=s,this.roles=[],this.identities=[],this.serviceAccountTokens=new Map}async start(){await this.loadState(),this.roles.find(e=>e.id==="administrator")||this.createBaseRoles(),this.identities.length===0&&this.createInitialUser()}createBaseRoles(){let e=Ft();for(let r of e)this.roles.push(r)}async createInitialUser(){let e=this.initialUser.email,r=this.initialUser.userName,s=await this.addUser(e,r,["administrator"]);return await this.mikroAuth.createMagicLink({email:e}),s}async getUserByEmail(e){let r=this.identities.find(s=>s.type==="user"&&s.metadata?.email===e&&s.metadata?.active!==!1);if(r)return this.enrichIdentityWithRoles(r)}async addUser(e,r,s=["user"],i=!0,o){if((await this.getUsers()).find(l=>l.metadata.email===e))throw new be(`User with email ${e} already exists`);let c=new oe({id:o,name:r,type:"user",metadata:{email:e,active:i},roles:s}).toDTO();return this.identities.push(c),await this.saveState(),this.enrichIdentityWithRoles(c)}async addServiceAccount(e,r,s,i){if((await this.getServiceAccounts()).find(l=>l.name===e))throw new be(`Service account with name ${e} already exists`);let a=new oe({id:i,name:e,type:"service_account",metadata:{description:r},roles:s}).toDTO(),c=this.generateServiceAccountToken();return this.serviceAccountTokens.set(c,a.id),this.identities.push(a),await this.saveState(),{...this.enrichIdentityWithRoles(a),apiKey:c}}async rotateServiceAccountKey(e){let r=await this.getIdentityById(e);if(!r||r.type!=="service_account")return;for(let[i,o]of this.serviceAccountTokens.entries())o===e&&this.serviceAccountTokens.delete(i);let s=this.generateServiceAccountToken();return this.serviceAccountTokens.set(s,e),await this.saveState(),s}async deleteIdentity(e){for(let[s,i]of this.serviceAccountTokens.entries())i===e&&this.serviceAccountTokens.delete(s);let r=this.identities.filter(s=>s.id!==e);this.identities=r,await this.saveState()}async updateIdentity(e,r){let s=await this.getIdentityById(e);if(!s)return;let i=new oe().fromDTO(s);r?.name&&i.changeName(r.name),r?.email&&i.changeEmail(r.email),r?.roles&&i.updateRoles(r.roles),r?.metadata&&i.updateMetadata(r.metadata);let o=i.toDTO();return this.updateIdentityList(o),await this.saveState(),this.enrichIdentityWithRoles(o)}updateIdentityList(e){if(!e)throw new x("Cannot update identity list: updatedIdentity is null or undefined");let r=JSON.parse(JSON.stringify(this.identities)),s=r.find(i=>i.id===e.id);s&&Object.assign(s,e),this.identities=r}generateServiceAccountToken(){return`sa.${ke()}.${oi.randomBytes(32).toString("hex")}`}async getUserFromToken(e){if(e&&e.startsWith("Bearer ")){let r=e.split(" ")[1];if(r.startsWith("sa.")){let i=this.serviceAccountTokens.get(r);if(i){let o=this.identities.find(n=>n.id===i&&n.type==="service_account");if(o)return this.enrichIdentityWithRoles(o)}}else try{let i=this.mikroAuth.verify(r),o=i.email||i.sub;return this.getUserByEmail(o)}catch{let o=new Error("Invalid token");throw o.cause={statusCode:401},o}}}async getIdentityById(e){return this.identities.find(r=>r.id===e)}async getUserById(e){let r=await this.getIdentityById(e);if(!(!r||r.type!=="user"))return this.enrichIdentityWithRoles(r)}async getServiceAccountById(e){let r=await this.getIdentityById(e);if(!(!r||r.type!=="service_account"))return this.enrichIdentityWithRoles(r)}async updateUser(e,r){let s=await this.getIdentityById(e);if(!(!s||s.type!=="user"))return this.updateIdentity(e,r)}async updateServiceAccount(e,r){let s=await this.getIdentityById(e);if(!s||s.type!=="service_account")return;let i={...r};return r.description!==void 0&&(i.metadata={...i.metadata||{},description:r.description},delete i.description),this.updateIdentity(e,i)}async deleteUser(e){let r=await this.getIdentityById(e);return!r||r.type!=="user"?!1:(await this.deleteIdentity(e),!0)}async deleteServiceAccount(e){let r=await this.getIdentityById(e);return!r||r.type!=="service_account"?!1:(await this.deleteIdentity(e),!0)}enrichIdentityWithRoles(e){let r=JSON.parse(JSON.stringify(e));return e.roles?r.roles=e.roles.map(s=>this.roles.find(i=>i.id===s)).filter(Boolean):r.roles=[],r}async getIdentities(){return this.identities}async getUsers(){return this.identities.filter(e=>e.type==="user")}async getServiceAccounts(){return this.identities.filter(e=>e.type==="service_account")}can(e,r,s){return new oe(s).can(e,r,s)}async createCustomRole(e,r,s,i,o){if(this.roles.find(l=>l.id===e))throw new z(`Role with ID ${e} already exists`);let c={id:e,name:r,description:s,policies:[{permissions:i,targets:["*"]}],constraints:o||{assumable_by:{identities:[],roles:[],services:["functions"]},assumption_constraints:{max_duration:3600,require_reason:!1,audit_level:"medium"}}};this.roles.push(c),await this.saveState()}async updateRole(e,r){let s=this.roles.find(i=>i.id===e);if(!s)throw new xe(`Role with ID ${e} not found`);r.name!==void 0&&(s.name=r.name),r.description!==void 0&&(s.description=r.description),r.permissions!==void 0&&(s.policies=[{permissions:r.permissions,targets:["*"]}]),r.constraints!==void 0&&(s.constraints=r.constraints),await this.saveState()}async deleteRole(e){let r=this.roles.findIndex(s=>s.id===e);if(r===-1)throw new xe(`Role with ID ${e} not found`);if(e==="administrator"||e==="user")throw new Oe("Cannot delete base roles");this.roles.splice(r,1),await this.saveState()}async getRoles(){return this.roles}async getRole(e){return this.roles.find(r=>r.id===e)}async loadState(){let e=await this.load("identities");e&&(this.identities=e);let r=await this.load("roles");r&&(this.roles=r);let s=await this.load("serviceAccountTokens");if(s){let i=new Map(Object.entries(s));s&&Object.keys(s).length>0&&(this.serviceAccountTokens=i)}}async saveState(){let e=Object.fromEntries(this.serviceAccountTokens);await this.write("identities",this.identities),await this.write("roles",this.roles),await this.write("serviceAccountTokens",e)}async load(e){return await this.db.get(this.tableName,e)}async write(e,r){await this.db.write(this.tableName,e,r)}};import{existsSync as ni}from"node:fs";import{spawn as ai}from"node:child_process";import{createServer as ci}from"node:net";var Bt={storage:{name:"storage",path:"./storage.mjs",port:3001,prefix:"/storage",args:["--force"]},functions:{name:"functions",path:"./functions.mjs",port:3002,prefix:"/functions",args:["--force"]},sites:{name:"sites",path:"./sites.mjs",port:3003,prefix:"/sites",args:["--force"]},databases:{name:"databases",path:"./databases.mjs",port:3004,prefix:"/databases",args:["--force"]},observability:{name:"observability",path:"./observability.mjs",port:3005,prefix:"/observability",args:["--force"]}},de=class{db;services=new Map;tableName="molnosmanagement";environmentVariables={};clusterConfig;setEnvironmentVariables(e){this.environmentVariables={...this.environmentVariables,...e}}setClusterConfig(e){this.clusterConfig=e}shouldSpawnLocally(e){if(!this.clusterConfig||this.clusterConfig.mode==="standalone")return!0;let r=e;return this.clusterConfig.mode==="core"?!this.clusterConfig.workers?.[r]:this.clusterConfig.mode==="worker"?this.clusterConfig.capabilities?.includes(r)??!1:!0}async isPortInUse(e){return new Promise(r=>{let s=ci();s.once("error",i=>{i.code==="EADDRINUSE"?r(!0):r(!1)}),s.once("listening",()=>{s.close(),r(!1)}),s.listen(e,"127.0.0.1")})}constructor(e){this.db=new ie({databaseDirectory:e.dbPath})}getServiceDefinition(e){let r=e.toLowerCase(),s=Bt[r];if(!s)throw new F(`Unknown service: ${e}. Valid services are: ${Object.keys(Bt).join(", ")}`);return s}async start(){await this.db.start();let e=await this.db.get(this.tableName,"services")||[];for(let r of e){if(r.restartPolicy&&(r.restartPolicy.attempts=0),r.healthCheck&&(r.healthCheck.consecutiveFailures=0,r.healthCheck.consecutiveSuccesses=0,r.healthCheck.healthy=!0),this.services.set(r.name,r),!this.shouldSpawnLocally(r.name)){console.log(`[ManagementService] Skipping ${r.name} - handled by remote worker`);continue}r.active&&await this.startService(r.name)}}async stopAllServices(){let e=[];for(let[r,s]of this.services.entries())(s.active||s.process)&&e.push(this.stopService(r));await Promise.all(e)}async shutdown(){await this.stopAllServices()}validateServiceConfig(e){if(!e.name||e.name.trim()==="")throw new x("Service name is required");if(!e.path||e.path.trim()==="")throw new x("Service path is required");if(!ni(e.path))throw new je(`Service path does not exist: ${e.path}`);if(!e.port||e.port<1||e.port>65535)throw new x(`Invalid port: ${e.port}`);if(!e.prefix||!e.prefix.startsWith("/"))throw new x("Service prefix must start with /")}cleanServiceForStorage(e){let{process:r,...s}=e;if(s.healthCheck){let{timer:i,consecutiveFailures:o,consecutiveSuccesses:n,healthy:a,...c}=s.healthCheck;s.healthCheck=c}if(s.restartPolicy){let{attempts:i,...o}=s.restartPolicy;s.restartPolicy=o}return s}async registerService(e,r){let s;typeof e=="string"?s={...this.getServiceDefinition(e),...r}:s=e,this.validateServiceConfig(s);let i={...s,active:!1},o=await this.getServices(),n=[],a=[];if(o.forEach(l=>{n.push(l.name),a.push(l.port)}),a.includes(i.port))throw new $e(`Port ${i.port} already in use`);if(n.includes(i.name))throw new z(`Service with name '${i.name}' already exists`);i.restartPolicy&&(i.restartPolicy.attempts=0),i.healthCheck&&(i.healthCheck.consecutiveFailures=0,i.healthCheck.consecutiveSuccesses=0,i.healthCheck.healthy=!0),this.services.set(i.name,i);let c=await this.db.get(this.tableName,"services")||[];return c.push(this.cleanServiceForStorage(i)),await this.db.write(this.tableName,"services",c),i.name}async startService(e){let r=this.services.get(e);if(!r)return!1;if(!this.shouldSpawnLocally(e))return console.log(`[ManagementService] Cannot start ${e} - not configured to run locally`),!1;if(r.process&&r.active)return!0;if(await this.isPortInUse(r.port))return console.error(`[ManagementService] Cannot start ${e}: Port ${r.port} is already in use. Please kill the process using this port.`),!1;try{let i={stdio:"pipe",detached:!1,env:{...process.env,...this.environmentVariables}},o=r.args||[],n=`--port=${r.port}`,a=ai("node",[r.path,n,...o],i);r.process=a,r.restartPolicy&&(r.restartPolicy.attempts=0);let c=!1;return a.stdout.on("data",l=>{let p=l.toString();console.log(`[${e}] ${p}`)}),a.stderr.on("data",l=>{let p=l.toString();console.error(`[${e}] ERROR: ${p}`),(p.includes("EADDRINUSE")||p.includes("address already in use"))&&(c=!0)}),a.on("exit",l=>{r.active=!1,r.process=void 0,c&&console.error(`[ManagementService] Service ${e} failed to start due to startup error`),this.handleServiceExit(r,l||0)}),await new Promise(l=>setTimeout(l,500)),r.process&&!r.process.killed?(r.active=!0,await this.updateServiceStatus(e,!0),r.healthCheck&&this.startHealthCheck(r),!0):(console.error(`[ManagementService] Service ${e} exited immediately after spawn`),!1)}catch(i){return console.error(`[ManagementService] Failed to start ${e}:`,i),!1}}startHealthCheck(e){let r=e.healthCheck;if(!r)return;let s=async()=>{if(e.healthCheck)try{let i=new AbortController,o=setTimeout(()=>i.abort(),e.healthCheck.timeoutMs),n=await fetch(`http://127.0.0.1:${e.port}${e.healthCheck.path}`,{signal:i.signal});clearTimeout(o),n.ok&&e.healthCheck?(e.healthCheck.consecutiveSuccesses=(e.healthCheck.consecutiveSuccesses||0)+1,e.healthCheck.consecutiveFailures=0,e.healthCheck.consecutiveSuccesses>=e.healthCheck.successThreshold&&(e.healthCheck.healthy=!0)):this.handleHealthCheckFailure(e)}catch{this.handleHealthCheckFailure(e)}};r.timer=setInterval(s,r.intervalMs)}handleHealthCheckFailure(e){e.healthCheck&&(e.healthCheck.consecutiveFailures=(e.healthCheck.consecutiveFailures||0)+1,e.healthCheck.consecutiveSuccesses=0,e.healthCheck.consecutiveFailures>=e.healthCheck.failureThreshold&&(e.healthCheck.healthy=!1,e.healthCheck.restartOnFailure&&this.restartService(e.name).catch(()=>{})))}async handleServiceExit(e,r){if(await this.updateServiceStatus(e.name,!1),!e.restartPolicy||e.restartPolicy.type==="never"||e.restartPolicy.type==="on-failure"&&r===0||e.restartPolicy.maxAttempts>0&&(e.restartPolicy.attempts||0)>=e.restartPolicy.maxAttempts)return;e.restartPolicy.attempts=(e.restartPolicy.attempts||0)+1;let s=e.restartPolicy.backoffMs;setTimeout(()=>{this.startService(e.name).catch(()=>{})},s)}async stopService(e){let r=this.services.get(e);if(!r)return!1;if(r.healthCheck?.timer&&(clearInterval(r.healthCheck.timer),r.healthCheck.timer=void 0),!r.process)return r.active&&(r.active=!1,await this.updateServiceStatus(e,!1)),!0;try{let s=i=>{try{return process.kill(i,0),!0}catch{return!1}};if(r.process?.pid){let i=r.process.pid;if(s(i))try{process.kill(i,"SIGTERM");let o=setTimeout(()=>{try{s(i)&&process.kill(i,"SIGKILL")}catch{}},5*1e3);await new Promise(n=>{if(!r.process){clearTimeout(o),n();return}let a=setTimeout(()=>{clearTimeout(o),n()},6*1e3);r.process.once("exit",()=>{clearTimeout(o),clearTimeout(a),n()})})}catch(o){if(o.code!=="ESRCH")throw o}}return r.active=!1,r.process=void 0,await this.updateServiceStatus(e,!1),!0}catch{return r.active&&(r.active=!1,r.process=void 0,await this.updateServiceStatus(e,!1)),!1}}async restartService(e){return await this.stopService(e),await new Promise(r=>setTimeout(r,500)),this.startService(e)}async updateServiceStatus(e,r){let s=await this.db.get(this.tableName,"services")||[],i=s.findIndex(o=>o.name===e);if(i>=0){let o=this.services.get(e);o?(o.active=r,s[i]=this.cleanServiceForStorage(o)):s[i].active=r,await this.db.write(this.tableName,"services",s)}}async getService(e){return(await this.getServices()).find(s=>s.name===e)}async getServices(){return(await this.db.get(this.tableName,"services")||[]).map(({process:r,...s})=>s)}async getServiceStats(e){let r=this.services.get(e);return r?{name:r.name,active:r.active,health:r.healthCheck?{healthy:r.healthCheck.healthy||!1,consecutiveSuccesses:r.healthCheck.consecutiveSuccesses||0,consecutiveFailures:r.healthCheck.consecutiveFailures||0}:null,restarts:r.restartPolicy&&r.restartPolicy.attempts||0}:null}async updateService(e,r){let s=this.services.get(e);if(!s)return!1;let i=s.active;Object.assign(s,r);let o=await this.db.get(this.tableName,"services")||[],n=o.findIndex(a=>a.name===e);return n>=0?(o[n]=this.cleanServiceForStorage(s),await this.db.write(this.tableName,"services",o),i!==s.active&&(s.active?await this.startService(e):await this.stopService(e)),!0):!1}async removeService(e){let r=this.services.get(e);r?.healthCheck?.timer&&(clearInterval(r.healthCheck.timer),r.healthCheck.timer=void 0),await this.stopService(e),this.services.delete(e);let i=(await this.db.get(this.tableName,"services")||[]).filter(o=>o.name!==e);return await this.db.write(this.tableName,"services",i),!0}};var W=class{id;name;description;redirectUris;metadata;owners;constructor(e){let r=this.createApplication(e);this.id=r.id,this.name=r.name,this.description=r.description,this.redirectUris=r.redirectUris,this.metadata=r.metadata,this.owners=r.owners}createApplication(e){let r=e?.id||this.createId(),s=e?.name||"",i=e?.description,o=e?.redirectUris||[],n=e?.owners||[],a=new Date().toISOString(),c={...e?.metadata||{},createdAt:e?.metadata?.createdAt||a,updatedAt:a,createdBy:e?.metadata?.createdBy||n[0]||""};return e&&this.validate({id:r,name:s,description:i,redirectUris:o,metadata:c,owners:n}),{id:r,name:s,description:i,redirectUris:o,metadata:c,owners:n}}update(e){e.name!==void 0&&(this.name=e.name),e.description!==void 0&&(this.description=e.description),e.redirectUris!==void 0&&(this.validateRedirectUris(e.redirectUris),this.redirectUris=e.redirectUris),e.owners!==void 0&&(this.owners=e.owners),e.metadata!==void 0?this.metadata={...this.metadata,...e.metadata,updatedAt:new Date().toISOString()}:this.metadata.updatedAt=new Date().toISOString(),this.validate(this.toDTO())}isValidRedirectUri(e){return this.redirectUris.includes(e)}isOwner(e){return this.owners.includes(e)}createId(){return De()}validate(e){let{id:r,name:s,redirectUris:i,metadata:o,owners:n}=e;if(!r)throw new x("Missing ID");if(!s||s.trim().length===0)throw new x("Missing or invalid name");if(!o)throw new x("Missing metadata");if(!n||n.length===0)throw new x("Application must have at least one owner");this.validateRedirectUris(i)}validateRedirectUris(e){if(!e||e.length===0)throw new x("At least one redirect URI is required");for(let r of e)try{let s=new URL(r);if(s.protocol!=="https:"&&s.protocol!=="http:"&&s.protocol!=="custom:")throw new x(`Invalid redirect URI protocol: ${r}. Must use https:, http: (localhost only), or custom: (for native apps)`);s.protocol==="http:"&&!s.hostname.match(/^(localhost|127\.0\.0\.1|\[::1\])$/)&&console.warn(`Warning: HTTP redirect URI detected for non-localhost: ${r}. HTTPS is recommended for production.`)}catch{throw new x(`Invalid redirect URI format: ${r}`)}}fromDTO(e){return this.validate(e),this.id=e.id,this.name=e.name,this.description=e.description,this.redirectUris=e.redirectUris,this.metadata=e.metadata,this.owners=e.owners,this}toDTO(){return{id:this.id,name:this.name,description:this.description,redirectUris:this.redirectUris,metadata:this.metadata,owners:this.owners}}};var Ve=class{db;tableName="molnosapplications";key="applications";applications;constructor(e){this.db=new ie({databaseDirectory:e.dbPath}),this.applications=[]}async start(){await this.db.start(),await this.loadState()}async loadState(){let e=await this.db.get(this.tableName,this.key)||[];this.applications=e}async saveState(){await this.db.write(this.tableName,this.key,this.applications)}async createApplication(e,r){let s=e.owners.includes(r)?e.owners:[...e.owners,r],o=new W({...e,owners:s,metadata:{...e.metadata,createdBy:r}}).toDTO();if(this.applications.find(a=>a.name===o.name))throw new z(`Application with name '${o.name}' already exists`);return this.applications.push(o),await this.saveState(),o}async getApplication(e,r){let s=this.applications.find(o=>o.id===e);if(!s)throw new F(`Application with ID '${e}' not found`);let i=new W().fromDTO(s);if(r&&!i.isOwner(r))throw new ue("Only application owners can view application details");return i.toDTO()}async getApplicationById(e){return this.applications.find(s=>s.id===e)||null}async listApplications(e){return this.applications.filter(r=>r.owners.includes(e)).map(r=>new W().fromDTO(r).toDTO())}async updateApplication(e,r,s){let i=this.applications.findIndex(a=>a.id===e);if(i===-1)throw new F(`Application with ID '${e}' not found`);let o=this.applications[i],n=new W().fromDTO(o);if(!n.isOwner(s))throw new ue("Only application owners can update the application");if(r.owners&&r.owners.length===0)throw new x("Application must have at least one owner");if(r.owners&&!r.owners.includes(s)&&o.owners.length===1&&o.owners[0]===s)throw new x("Cannot remove yourself as the last owner of the application");return n.update(r),this.applications[i]=n.toDTO(),await this.saveState(),this.applications[i]}async deleteApplication(e,r){let s=this.applications.findIndex(n=>n.id===e);if(s===-1)throw new F(`Application with ID '${e}' not found`);let i=this.applications[s];if(!new W().fromDTO(i).isOwner(r))throw new ue("Only application owners can delete the application");this.applications.splice(s,1),await this.saveState()}async validateRedirectUri(e,r){let s=await this.getApplicationById(e);return s?new W().fromDTO(s).isValidRedirectUri(r):!1}getAllApplicationsInternal(){return this.applications}};async function w(t){return t.body||{}}function m(t,e="An error occurred"){let r=t?.message||t||e,s=t?.cause?.statusCode||t?.statusCode||400;return{message:r,status:s}}async function _t(t,e,r,s){try{let i=await w(t),{email:o,redirectUrl:n,applicationId:a}=i;if(!o)return t.json({error:"Email is required"},400);let c=o.trim().toLowerCase(),l;if(n){if(!a)return t.json({error:"applicationId is required when redirectUrl is provided"},400);if(!await s.validateRedirectUri(a,n))return t.json({error:"Invalid redirectUrl or applicationId. The redirect URI must be registered for this application."},400);l=(await s.getApplicationById(a))?.name}let p=!1;return await e.getUserByEmail(c)&&(p=!0),p&&await r.createMagicLink({email:c,subject:`Sign In To ${l||"MolnOS"}`,appUrl:n,metadata:{appName:l,redirectUrl:n,applicationId:a}}),t.json({success:!0,message:"If a matching account was found, a magic link has been sent."})}catch(i){let{message:o,status:n}=m(i,"Error during login");return t.json({error:o},n)}}async function zt(t,e,r){try{let s=t.query.token,i=t.query.email;if(!s)return t.json({error:"Token is required as query parameter"},400);if(!i)return t.json({error:"Email is required as query parameter"},400);try{let o=await e.verifyToken({token:s,email:i});if(!o)return t.json({error:"Invalid or expired token"},401);let n=o.metadata;if(n?.redirectUrl&&n?.applicationId)if(await r.validateRedirectUri(n.applicationId,n.redirectUrl)){let c=new URL(n.redirectUrl);return c.searchParams.set("access_token",o.accessToken),c.searchParams.set("refresh_token",o.refreshToken),c.searchParams.set("expires_in",o.expiresIn.toString()),t.redirect(c.toString(),302)}else return console.warn(`Redirect URL validation failed for applicationId: ${n.applicationId}`),t.json({...o,warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);return t.json(o,200)}catch{return t.json({error:"Invalid or expired token"},401)}}catch(s){let{message:i,status:o}=m(s,"Error verifying token");return t.json({error:i},o)}}async function Wt(t,e){try{let s=(await w(t)).refreshToken;if(!s)return t.json({error:"Value for refreshToken is required"},400);try{let i=await e.refreshAccessToken(s);return t.json(i,200)}catch{return t.json({error:"Invalid or expired token"},401)}}catch(r){let{message:s,status:i}=m(r,"Error refreshing token");return t.json({error:s},i)}}async function Gt(t){try{let e=t.state.user;return t.json(e)}catch(e){let{message:r,status:s}=m(e,"Error getting user info");return t.json({error:r},s)}}function g(t,e,r={}){let s=Array.isArray(e)?e:[e];if(!t||!t.roles||!Array.isArray(t.roles)){let n=new Error("Unauthorized: User or roles missing");throw n.cause={statusCode:403},n}let i=t.roles.flatMap(n=>n?.policies?.flatMap(a=>(a?.permissions||[]).flatMap(l=>typeof l=="string"?l:l&&typeof l=="object"&&l.actions?l.actions:[]))||[]);if(!s.every(n=>i.includes(n)||i.includes("*")?!0:i.some(a=>{if(a.endsWith(".*")){let c=a.slice(0,-2);return n.startsWith(`${c}.`)}return!1}))){let n=new Error("Unauthorized");throw n.cause={statusCode:403},n}return!0}async function Kt(t,e){try{let r=t.state.user;g(r,"identity.identities.get",{});let s=await e.getIdentities();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting identities");return t.json({error:s},i)}}var H=class{isSilent;propertyPath="";constructor(t=!1){this.isSilent=t}test(t,e){if(!e)throw new Error("Missing input!");this.updatePropertyPath();let{results:r,errors:s}=this.validate(t.properties,e),i=this.compileErrors(r,s),o=this.isSuccessful(r,i);return{errors:i,success:o}}compileErrors(t,e){let r=t.filter(s=>s.success===!1);return[...e,...r].flatMap(s=>s)}isSuccessful(t,e){return t.every(r=>r.success===!0)&&e.length===0}validate(t,e,r=[],s=[]){let i=t?.additionalProperties??!0,o=t?.required||[];s=this.checkForRequiredKeysErrors(o,e,s),s=this.checkForDisallowedProperties(Object.keys(e),Object.keys(t),s,i);for(let n in t){let a=o.includes(n)&&n!=="required",c=t[n],l=e[n],p=c.additionalProperties??!0;a&&(s=this.checkForRequiredKeysErrors(c.required||[],l,s)),this.isDefined(l)&&(this.handleValidation(n,l,c,r),s=this.checkForDisallowedProperties(Object.keys(l),Object.keys(c),s,p),this.handleNestedObject(l,c,r,s))}return{results:r,errors:s}}updatePropertyPath(t,e=""){if(!t){this.propertyPath="";return}e&&(this.propertyPath=e),this.propertyPath=`${this.propertyPath}.${t}`,this.propertyPath.startsWith(".")&&(this.propertyPath=this.propertyPath.substring(1,this.propertyPath.length))}isDefined(t){return!!(typeof t=="number"&&t===0||t||t===""||typeof t=="boolean")}checkForRequiredKeysErrors(t,e,r){if(!this.areRequiredKeysPresent(t,e)){let s=e?Object.keys(e):[],i=this.findNonOverlappingElements(t,s),o=i.length>0?`Missing the required key: '${i.join(", ")}'!`:`Missing values for required keys: '${s.filter(n=>!e[n]).join(", ")}'!`;r.push({key:"",value:e,success:!1,error:o})}return r}checkForDisallowedProperties(t,e,r,s){if(!s){let i=this.findNonOverlappingElements(t,e);i.length>0&&r.push({key:`${e}`,value:t,success:!1,error:`Has additional (disallowed) properties: '${i.join(", ")}'!`})}return r}handleValidation(t,e,r,s){this.updatePropertyPath(t);let i=this.validateProperty(this.propertyPath,r,e);s.push(...i);let o=(a,c)=>{a.forEach(l=>{let p=this.validateProperty(this.propertyPath,c.items,l);s.push(...p)}),this.updatePropertyPath()},n=a=>{let c=Object.keys(a),l=this.propertyPath;c.forEach(p=>{if(this.updatePropertyPath(p,l),this.isArray(a[p])&&r[p]?.items!=null)o(a[p],r[p]);else{let u=this.validateProperty(this.propertyPath,r[p],a[p]);s.push(...u)}})};this.isArray(e)&&r.items!=null?o(e,r):this.isObject(e)?n(e):this.updatePropertyPath()}handleNestedObject(t,e,r,s){if(this.isObject(t)){let i=this.getNestedObjects(t);for(let o of i){let n=e[o],a=t[o];n&&typeof a=="object"&&this.validate(n,a,r,s)}}}getNestedObjects(t){return Object.keys(t).filter(e=>{if(this.isObject(t))return e})}findNonOverlappingElements(t,e){return t.filter(r=>!e.includes(r))}areRequiredKeysPresent(t,e=[]){return t.every(r=>Object.keys(e).includes(r)?this.isDefined(e[r]):!1)}validateProperty(t,e,r){return this.validateInput(e,r).map(i=>{let{success:o,error:n}=i;return{key:t,value:r,success:o,error:n??""}})}validateInput(t,e){if(t){let r=[{condition:()=>t.type,validator:()=>this.isCorrectType(t.type,e),error:"Invalid type"},{condition:()=>t.format,validator:()=>this.isCorrectFormat(t.format,e),error:"Invalid format"},{condition:()=>t.minLength,validator:()=>this.isMinimumLength(t.minLength,e),error:"Length too short"},{condition:()=>t.maxLength,validator:()=>this.isMaximumLength(t.maxLength,e),error:"Length too long"},{condition:()=>t.minValue,validator:()=>this.isMinimumValue(t.minValue,e),error:"Value too small"},{condition:()=>t.maxValue,validator:()=>this.isMaximumValue(t.maxValue,e),error:"Value too large"},{condition:()=>t.matchesPattern,validator:()=>this.matchesPattern(t.matchesPattern,e),error:"Pattern does not match"}],s=[];for(let i of r)i.condition()&&!i.validator()&&s.push({success:!1,error:i.error});return s}else this.isSilent||console.warn(`Missing property '${t}' for match '${e}'. Skipping...`);return[{success:!0}]}isCorrectType(t,e){return Array.isArray(t)||(t=[t]),t.some(r=>{switch(r){case"string":return typeof e=="string";case"number":return typeof e=="number"&&!isNaN(e);case"boolean":return typeof e=="boolean";case"object":return this.isObject(e);case"array":return this.isArray(e)}})}isObject(t){return t!==null&&!this.isArray(t)&&typeof t=="object"&&t instanceof Object&&Object.prototype.toString.call(t)==="[object Object]"}isArray(t){return Array.isArray(t)}isCorrectFormat(t,e){switch(t){case"alphanumeric":return new RegExp(/^[a-zA-Z0-9]+$/).test(e);case"numeric":return new RegExp(/^-?\d+(\.\d+)?$/).test(e);case"email":return new RegExp(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/).test(e);case"date":return new RegExp(/^\d{4}-\d{2}-\d{2}$/).test(e);case"url":return new RegExp(/^(https?):\/\/[^\s$.?#].[^\s]*$/).test(e);case"hexColor":return new RegExp(/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i).test(e)}}isMinimumLength(t,e){return Array.isArray(e)?e.length>=t:e?.toString().length>=t}isMaximumLength(t,e){return Array.isArray(e)?e.length<=t:e.toString().length<=t}isMinimumValue(t,e){return e>=t}isMaximumValue(t,e){return e<=t}matchesPattern(t,e){return new RegExp(t).test(e)}schemaFrom(t){let e={properties:{additionalProperties:!1,required:[]}};for(let r in t){let s=t[r];e.properties.required.push(r),Array.isArray(s)?e.properties[r]=this.generateArraySchema(s):typeof s=="object"&&s!==null?e.properties[r]=this.generateNestedObjectSchema(s):e.properties[r]=this.generatePropertySchema(s)}return e}generateArraySchema(t){let e={type:"array"},r=t.filter(s=>s);if(r.length>0){let s=r[0];r.every(o=>typeof o==typeof s)?typeof s=="object"&&!Array.isArray(s)?e.items=this.generateNestedObjectSchema(s):e.items=this.generatePropertySchema(s):console.warn("All elements in array are not of the same type. Unable to generate a schema for these elements.")}return e}generateNestedObjectSchema(t){let e={type:"object",additionalProperties:!1,required:[]};for(let r in t){let s=t[r];e.required.push(r),typeof s=="object"&&!Array.isArray(s)&&s!==null?e[r]=this.generateNestedObjectSchema(s):e[r]=this.generatePropertySchema(s)}return e}generatePropertySchema(t){let e=typeof t,r={type:e};return e==="string"&&(r.minLength=1),r}};var Jt={properties:{id:{type:"string",minLength:1,maxLength:40,pattern:"^[a-zA-Z0-9_-]{1,40}$"},email:{type:"string",format:"email",minLength:3},name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}},verified:{type:"boolean"}},required:["email","name","roles"],additionalProperties:!1};var ui=new H(!0);async function Xt(t,e){try{let r=t.state.user,s=await w(t),i=ui.test(Jt,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);g(r,"identity.user.create",{});let{id:o,email:n,name:a,roles:c,verified:l}=s,p=await e.addUser(n,a,c,l,o);return t.json(p,201)}catch(r){let{message:s,status:i}=m(r,"Error creating user");return t.json({error:s},i)}}async function Yt(t,e){try{let r=t.state.user;g(r,"identity.user.get",{});let s=await e.getUsers();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting users");return t.json({error:s},i)}}function E(t){return t.params}async function Zt(t,e){try{let r=t.state.user,s=E(t),{userId:i}=s;g(r,"identity.user.get",{userId:i});let o=await e.getUserById(i);return o?t.json(o):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting user");return t.json({error:s},i)}}var Qt={properties:{name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var pi=new H(!0);async function er(t,e){try{let r=t.state.user,s=E(t),{userId:i}=s,o=await w(t),n=pi.test(Qt,o);if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);g(r,"identity.user.update",{userId:i});let{name:a,roles:c}=o,l=await e.updateUser(i,{name:a,roles:c});return l?t.json(l):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error updating user");return t.json({error:s},i)}}async function tr(t,e){try{let r=t.state.user,s=E(t),{userId:i}=s;return g(r,"identity.user.delete",{userId:i}),await e.deleteUser(i)?t.body(null,204):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting user");return t.json({error:s},i)}}async function rr(t,e){try{let r=t.state.user,s=await w(t);if(!s.name||!s.description||!s.roles||!Array.isArray(s.roles))return t.json({error:"Invalid input: name, description, and roles are required"},400);if(!["user","administrator"].every(l=>s.roles.includes(l)||!s.roles.includes(l)))return t.json({error:"Invalid input: roles must be user or administrator"},400);g(r,"identity.service-account.create",{});let{id:i,name:o,description:n,roles:a}=s,c=await e.addServiceAccount(o,n,a,i);return t.json(c,201)}catch(r){let{message:s,status:i}=m(r,"Error creating service account");return t.json({error:s},i)}}async function sr(t,e){try{let r=t.state.user;g(r,"identity.service-account.get",{});let s=await e.getServiceAccounts();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting service accounts");return t.json({error:s},i)}}async function ir(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s;g(r,"identity.service-account.get",{serviceAccountId:i});let o=await e.getServiceAccountById(i);return o?t.json(o):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting service account");return t.json({error:s},i)}}var or={properties:{name:{type:"string",minLength:1,maxLength:100},description:{type:"string",minLength:1,maxLength:500},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var mi=new H(!0);async function nr(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s,o=await w(t),n=mi.test(or,o);if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);g(r,"identity.service-account.update",{serviceAccountId:i});let{name:a,description:c,roles:l}=o,p=await e.updateServiceAccount(i,{name:a,description:c,roles:l});return p?t.json(p):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error updating service account");return t.json({error:s},i)}}async function ar(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s;return g(r,"identity.service-account.delete",{serviceAccountId:i}),await e.deleteServiceAccount(i)?t.body(null,204):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting service account");return t.json({error:s},i)}}async function cr(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s;g(r,"identity.service-account.update",{serviceAccountId:i});let o=await e.rotateServiceAccountKey(i);return o?t.json({apiKey:o}):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error rotating service account key");return t.json({error:s},i)}}async function lr(t,e){try{let r=t.state.user;g(r,"identity.role.get",{});let s=await e.getRoles();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting roles");return t.json({error:s},i)}}async function ur(t,e){try{let r=t.state.user;g(r,"identity.role.get",{});let s=t.params.roleId;if(!s)return t.text("Missing role ID",400);let i=await e.getRole(s);return i?t.json(i):t.text("Role not found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting role");return t.json({error:s},i)}}async function dr(t,e){try{let r=t.state.user;g(r,"identity.role.create",{});let s=await w(t),{roleId:i,name:o,description:n,permissions:a,constraints:c}=s;if(!i||!o||!n)return t.text("Missing required fields: roleId, name, description",400);if(!a||!Array.isArray(a))return t.text("Permissions must be a non-empty array",400);await e.createCustomRole(i,o,n,a,c);let l=await e.getRole(i);return t.json(l,201)}catch(r){let{message:s,status:i}=m(r,"Error creating role");return t.json({error:s},i)}}async function pr(t,e){try{let r=t.state.user;g(r,"identity.role.update",{});let s=t.params.roleId;if(!s)return t.text("Missing role ID",400);let i=await w(t),{name:o,description:n,permissions:a,constraints:c}=i;await e.updateRole(s,{name:o,description:n,permissions:a,constraints:c});let l=await e.getRole(s);return t.json(l)}catch(r){let{message:s,status:i}=m(r,"Error updating role");return t.json({error:s},i)}}async function hr(t,e){try{let r=t.state.user;g(r,"identity.role.delete",{});let s=t.params.roleId;return s?s==="administrator"||s==="user"?t.text("Cannot delete base roles",403):(await e.deleteRole(s),t.json({message:"Role deleted successfully"})):t.text("Missing role ID",400)}catch(r){let{message:s,status:i}=m(r,"Error deleting role");return t.json({error:s},i)}}async function mr(t,e){try{let r=t.state.user;g(r,"management.services.get",{});let s=await e.getServices();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting services");return t.json({error:s},i)}}async function fr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;g(r,"management.service.get",{serviceName:i});let o=await e.getService(i);return o?t.json(o):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting service");return t.json({error:s},i)}}var gr={properties:{name:{type:"string",minLength:1},path:{type:"string"},port:{type:"number",minValue:1,maxValue:65535},prefix:{type:"string"},healthCheckPath:{type:"string"},healthCheckInterval:{type:"number",minValue:1e3}},required:["name"],additionalProperties:!0};var gi=new H(!0);async function yr(t,e){try{let r=t.state.user,s=await w(t),i=gi.test(gr,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);if(g(r,"management.service.create",{}),["storage","functions","sites","databases","observability"].includes(s.name.toLowerCase())){let{name:a,...c}=s;await e.registerService(a,c)}else{if(!s.path||!s.port||!s.prefix)return t.json({error:"Custom services require: name, path, port, and prefix"},400);await e.registerService(s)}return t.text("",201)}catch(r){let{message:s,status:i}=m(r,"Error creating service");return t.json({error:s},i)}}var vr={properties:{name:{type:"string",minLength:1},path:{type:"string"},port:{type:"number",minValue:1,maxValue:65535},prefix:{type:"string"},healthCheckPath:{type:"string"},healthCheckInterval:{type:"number",minValue:1e3}},required:["name"],additionalProperties:!0};var vi=new H(!0);async function wr(t,e){try{let r=t.state.user,s=E(t),i=await w(t),o=i.name,n=vi.test(vr,i);return n.success?(g(r,"management.service.update",{serviceName:o}),o!==s.serviceName?t.json({error:"Service name in body must match path parameter"},400):(await e.updateService(o,i),t.body(null,204))):t.json({error:"Invalid input",details:n.errors},400)}catch(r){let{message:s,status:i}=m(r,"Error updating service");return t.json({error:s},i)}}async function Sr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;return g(r,"management.service.delete",{serviceName:i}),await e.getService(i)?(await e.removeService(i),t.body(null,204)):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting service");return t.json({error:s},i)}}async function br(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.start",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=await e.startService(i);return t.json({serviceName:i,isStarted:n})}catch(r){let{message:s,status:i}=m(r,"Error starting service");return t.json({error:s},i)}}async function xr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.stop",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=await e.stopService(i);return t.json({serviceName:i,isStopped:n})}catch(r){let{message:s,status:i}=m(r,"Error stopping service");return t.json({error:s},i)}}async function Cr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.get",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=new URL("http://127.0.0.1:3005/events");n.searchParams.set("service",i),t.query.startTime&&n.searchParams.set("startTime",t.query.startTime),t.query.endTime&&n.searchParams.set("endTime",t.query.endTime),t.query.level&&n.searchParams.set("level",t.query.level),t.query.limit&&n.searchParams.set("limit",t.query.limit),t.query.offset&&n.searchParams.set("offset",t.query.offset);let a=await fetch(n.toString());if(!a.ok)throw new Me(`Observability service error: ${a.statusText}`);let c=await a.json();return t.json({serviceName:i,logs:c.events,count:c.count})}catch(r){let{message:s,status:i}=m(r,"Error getting service logs");return t.json({error:s},i)}}async function kr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.start",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=await e.restartService(i);return t.json({serviceName:i,restarted:n})}catch(r){let{message:s,status:i}=m(r,"Error restarting service");return t.json({error:s},i)}}function Ar(t,e,r,s,i){let o=t.find(c=>c.service===e);if(!o){let c=new Error(`Function bindings do not include access to service: ${e}`);throw c.cause={statusCode:403},c}if(!o.permissions||o.permissions.length===0)return;for(let c of o.permissions)if(!(c.resource&&c.resource!==r)){if(!c.resource||!c.actions||c.actions.length===0)return;if(c.actions.includes(s)){if(c.targets&&c.targets.length>0){if(!i)return;if(!c.targets.includes(i))continue}return}}let n=i?`:${i}`:"",a=new Error(`Function bindings do not allow: ${e}.${r}.${s}${n}`);throw a.cause={statusCode:403},a}async function P(t,e,r,s,i,o,n){if(!e)return null;let a=t.state.user;if(!a){let l=t.headers.authorization;if(!l){let u=new Error("Unauthorized: No authentication provided");throw u.cause={statusCode:401},u}let p=l.replace(/^Bearer\s+/i,"");if(a=await e.getUserFromToken(p),!a){let u=new Error("Unauthorized: Invalid token");throw u.cause={statusCode:401},u}}g(a,r,{});let c=t.headers["x-function-bindings"];if(c)try{let l=Array.isArray(c)?c[0]:c,p=JSON.parse(l);Ar(p,s,i,o,n)}catch(l){if(l.cause?.statusCode===403)throw l;let p=new Error("Invalid function bindings header");throw p.cause={statusCode:400},p}return a}async function Ir(t,e,r){try{let s=await w(t),i=t.state.requestingIdentity;if(!i)return t.json({error:"Authentication required"},401);let{id:o,name:n,description:a,redirectUris:c,metadata:l}=s;if(!n||!c)return t.json({error:"Missing required fields: name and redirectUris are required"},400);await P(t,r,"applications.application.create","applications","application","create",n);let p={id:o,name:n,description:a,redirectUris:Array.isArray(c)?c:[c],metadata:l,owners:[i.id]},u=await e.createApplication(p,i.id);return t.json(u,201)}catch(s){let{message:i,status:o}=m(s,"Error creating application");return t.json({error:i},o)}}async function Er(t,e,r){try{let s=t.params.id,i=t.state.requestingIdentity;if(!s)return t.json({error:"Application ID is required"},400);await P(t,r,"applications.application.read","applications","application","read",s);let o=await e.getApplication(s,i?.id);return t.json(o,200)}catch(s){let{message:i,status:o}=m(s,"Error retrieving application");return t.json({error:i},o)}}async function Pr(t,e,r){try{let s=t.state.requestingIdentity;if(!s)return t.json({error:"Authentication required"},401);await P(t,r,"applications.application.list","applications","application","list");let i=await e.listApplications(s.id);return t.json({applications:i,total:i.length},200)}catch(s){let{message:i,status:o}=m(s,"Error listing applications");return t.json({error:i},o)}}async function Tr(t,e,r){try{let s=t.params.id,i=await w(t),o=t.state.requestingIdentity;if(!o)return t.json({error:"Authentication required"},401);if(!s)return t.json({error:"Application ID is required"},400);await P(t,r,"applications.application.update","applications","application","update",s);let n=await e.updateApplication(s,i,o.id);return t.json(n,200)}catch(s){let{message:i,status:o}=m(s,"Error updating application");return t.json({error:i},o)}}async function Rr(t,e,r){try{let s=t.params.id,i=t.state.requestingIdentity;return i?s?(await P(t,r,"applications.application.delete","applications","application","delete",s),await e.deleteApplication(s,i.id),t.json({success:!0,message:"Application deleted"},200)):t.json({error:"Application ID is required"},400):t.json({error:"Authentication required"},401)}catch(s){let{message:i,status:o}=m(s,"Error deleting application");return t.json({error:i},o)}}async function jr(t,e,r){try{await P(t,r,"contexts.context.get","contexts","context","get");let i=e.listContexts().map(o=>{let n=e.getContextResources(o.name);return{...o,resourceCount:{functions:n.functions.length,databases:n.databases.length,storage:n.storage.length,sites:n.sites.length,users:n.users.length,serviceAccounts:n.serviceAccounts.length}}});return t.json({success:!0,contexts:i},200)}catch(s){let{message:i,status:o}=m(s,"Error listing contexts");return t.json({error:i},o)}}async function $r(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);await P(t,r,"contexts.context.get","contexts","context","get",s);let i=e.getContextWithResources(s);return t.json({success:!0,context:i},200)}catch(s){let{message:i,status:o}=m(s,"Error getting context");return t.json({error:i},o)}}var wi=new H(!0),Si={properties:{name:{type:"string",minLength:1,maxLength:64},intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},required:["name"],additionalProperties:!1};async function Or(t,e,r){try{let s=await w(t),i=wi.test(Si,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);await P(t,r,"contexts.context.create","contexts","context","create");let{name:o,intent:n,attributes:a}=s,c=await e.createContext({name:o,intent:n,attributes:a});return t.json({success:!0,context:c},201)}catch(s){let{message:i,status:o}=m(s,"Error creating context");return t.json({error:i},o)}}var bi=new H(!0),xi={properties:{intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},additionalProperties:!1};async function Mr(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);let i=await w(t),o=bi.test(xi,i||{});if(!o.success)return t.json({error:"Invalid input",details:o.errors},400);await P(t,r,"contexts.context.update","contexts","context","update",s);let{intent:n,attributes:a}=i||{},c=await e.updateContext(s,{intent:n,attributes:a});return t.json({success:!0,context:c},200)}catch(s){let{message:i,status:o}=m(s,"Error updating context");return t.json({error:i},o)}}async function Ur(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);if(s==="default")return t.json({error:"Cannot delete the default context"},400);await P(t,r,"contexts.context.delete","contexts","context","delete",s);let i=e.getContextResources(s);return await e.deleteContext(s),t.json({success:!0,message:`Context '${s}' deleted`,orphanedResources:i},200)}catch(s){let{message:i,status:o}=m(s,"Error deleting context");return t.json({error:i},o)}}async function Lr(t,e,r,s){try{let i=t.params.contextName;if(!i)return t.json({error:"contextName parameter is required"},400);await P(t,r,"contexts.context.delete-resources","contexts","context","delete-resources",i);let o=t.headers.authorization,n=o?.startsWith("Bearer ")?o.slice(7):o,a=s(n),c=e.getContextResources(i),l={success:!0,context:i,deleted:[],errors:[],summary:{totalResources:0,deletedCount:0,failedCount:0}};if(l.summary.totalResources=c.functions.length+c.databases.length+c.storage.length+c.sites.length+c.applications.length+c.users.length+c.serviceAccounts.length,a.functions){let u=await a.functions.list();for(let h of c.functions)try{let v=u.find(R=>R.id===h);v&&(await a.functions.delete(h),await e.unregisterResource(i,"function",h),l.deleted.push({type:"function",name:v.name}))}catch(v){l.errors.push({type:"function",name:h,error:v.message||"Unknown error"}),l.success=!1}}if(a.databases)for(let u of c.databases)try{await a.databases.deleteTable(u),await e.unregisterResource(i,"database",u),l.deleted.push({type:"database",name:u})}catch(h){l.errors.push({type:"database",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.storage)for(let u of c.storage)try{await a.storage.deleteBucket(u),await e.unregisterResource(i,"storage",u),l.deleted.push({type:"storage",name:u})}catch(h){l.errors.push({type:"storage",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.sites)for(let u of c.sites)try{await a.sites.deleteProject(u),await e.unregisterResource(i,"site",u),l.deleted.push({type:"site",name:u})}catch(h){l.errors.push({type:"site",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.applications){let u=await a.applications.list();for(let h of c.applications)try{let v=u.find(R=>R.id===h);v&&(await a.applications.delete(h),await e.unregisterResource(i,"application",h),l.deleted.push({type:"application",name:v.name}))}catch(v){l.errors.push({type:"application",name:h,error:v.message||"Unknown error"}),l.success=!1}}if(a.identity)for(let u of c.users)try{let h=await a.identity.getUser(u);h&&(await a.identity.deleteUser(h.id),await e.unregisterResource(i,"user",u),l.deleted.push({type:"user",name:u}))}catch(h){l.errors.push({type:"user",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.identity)for(let u of c.serviceAccounts)try{let h=await a.identity.getServiceAccount(u);h&&(await a.identity.deleteServiceAccount(h.id),await e.unregisterResource(i,"serviceAccount",u),l.deleted.push({type:"serviceAccount",name:u}))}catch(h){l.errors.push({type:"serviceAccount",name:u,error:h.message||"Unknown error"}),l.success=!1}l.summary.deletedCount=l.deleted.length,l.summary.failedCount=l.errors.length;let p=l.success?200:207;return t.json(l,p)}catch(i){let{message:o,status:n}=m(i,"Error deleting context resources");return t.json({error:o},n)}}async function Hr(t,e,r){try{await P(t,r,"iac.config.get","iac","config","get");let s=await w(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,n=e().validate(i);return t.json({success:!0,valid:n.valid,errors:n.errors,warnings:n.warnings},200)}catch(s){let{message:i,status:o}=m(s,"Error validating IaC");return t.json({error:i},o)}}async function Dr(t,e,r){try{await P(t,r,"iac.config.create","iac","config","create");let s=await w(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,o=t.headers.authorization,n=o?.startsWith("Bearer ")?o.slice(7):o,a=e(n),c=t.query?.prune==="true",l=await a.apply(i,{prune:c}),p=l.success?200:207;return t.json({success:l.success,context:l.context,created:l.created,updated:l.updated,unchanged:l.unchanged,deleted:l.deleted,errors:l.errors},p)}catch(s){let{message:i,status:o}=m(s,"Error applying IaC");return t.json({error:i},o)}}var G="default",qe=class{db;tableName="context_service";contexts;resourceMappings;constructor(e){this.db=e,this.contexts=[],this.resourceMappings=[]}async start(){await this.loadState()}async loadState(){try{let e=await this.db.get(this.tableName,"state");e&&(this.contexts=e.contexts||[],this.resourceMappings=e.resourceMappings||[])}catch{this.contexts=[],this.resourceMappings=[]}}async saveState(){await this.db.write(this.tableName,"state",{contexts:this.contexts,resourceMappings:this.resourceMappings})}async createContext(e){let r=e.name;if(this.contexts.find(o=>o.name===r))throw new z(`Context '${r}' already exists`);let s=new Date().toISOString(),i={name:r,intent:e.intent,attributes:e.attributes,createdAt:s,updatedAt:s};return this.contexts.push(i),await this.saveState(),i}getContext(e){let r=this.contexts.find(s=>s.name===e);if(!r)throw new F(`Context '${e}' not found`);return r}getContextWithResources(e){let r=this.getContext(e),s=this.getContextResources(e);return{...r,resources:s}}async updateContext(e,r){let s=this.contexts.findIndex(n=>n.name===e);if(s===-1)throw new F(`Context '${e}' not found`);let i=this.contexts[s],o={...i,intent:r.intent??i.intent,attributes:r.attributes??i.attributes,updatedAt:new Date().toISOString()};return this.contexts[s]=o,await this.saveState(),o}async deleteContext(e){let r=this.contexts.findIndex(s=>s.name===e);if(r===-1)throw new F(`Context '${e}' not found`);this.contexts.splice(r,1),this.resourceMappings=this.resourceMappings.filter(s=>s.context!==e),await this.saveState()}contextExists(e){return this.contexts.some(r=>r.name===e)}listContexts(){return[...this.contexts].sort((e,r)=>e.name.localeCompare(r.name))}async ensureContext(e){let r=e||G;return this.contextExists(r)||await this.createContext({name:r,intent:r===G?"Default context for resources without explicit context assignment.":void 0}),r}async registerResource(e,r,s){await this.ensureContext(e),this.resourceMappings.find(o=>o.context===e&&o.resourceType===r&&o.resourceName===s)||(this.resourceMappings.push({context:e,resourceType:r,resourceName:s,createdAt:new Date().toISOString()}),await this.saveState())}async unregisterResource(e,r,s){this.resourceMappings=this.resourceMappings.filter(i=>!(i.context===e&&i.resourceType===r&&i.resourceName===s)),await this.saveState()}getContextResources(e){let r=this.resourceMappings.filter(i=>i.context===e),s={functions:[],databases:[],storage:[],sites:[],users:[],serviceAccounts:[],applications:[]};for(let i of r)switch(i.resourceType){case"function":s.functions.push(i.resourceName);break;case"database":s.databases.push(i.resourceName);break;case"storage":s.storage.push(i.resourceName);break;case"site":s.sites.push(i.resourceName);break;case"user":s.users.push(i.resourceName);break;case"serviceAccount":s.serviceAccounts.push(i.resourceName);break;case"application":s.applications.push(i.resourceName);break}return s}getResourceContext(e,r){return this.resourceMappings.find(i=>i.resourceType===e&&i.resourceName===r)?.context||G}async moveResource(e,r,s,i){await this.unregisterResource(s,e,r),await this.registerResource(i,e,r)}listResourcesByType(e,r){return this.resourceMappings.filter(s=>s.context===e&&s.resourceType===r).map(s=>s.resourceName)}};async function Nr(t,e,r){try{await P(t,r,"iac.config.get","iac","config","get");let s=await w(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,o=t.headers.authorization,n=o?.startsWith("Bearer ")?o.slice(7):o,a=e(n),c=a.validate(i);if(!c.valid)return t.json({success:!1,valid:!1,errors:c.errors,warnings:c.warnings},400);let l=await a.diff(i);return t.json({success:!0,context:i.context?.name||G,toCreate:l.toCreate,toUpdate:l.toUpdate,toDelete:l.toDelete,unchanged:l.unchanged,warnings:c.warnings},200)}catch(s){let{message:i,status:o}=m(s,"Error generating IaC diff");return t.json({error:i},o)}}import{promises as Fe}from"node:fs";import{join as at,resolve as ki}from"node:path";var Vr={$schema:"https://json-schema.org/draft-07/schema#",$id:"https://schemas.molnos.cloud/schema-config-v1.json",title:"MolnOS IaC Configuration",description:"Infrastructure-as-Code configuration file for MolnOS contexts",type:"object",properties:{$schema:{type:"string",description:"JSON Schema reference for editor support"},version:{type:"string",enum:["1"],description:"IaC schema version"},context:{type:"object",description:"Context definition (optional, defaults to 'default' context)",properties:{name:{type:"string",minLength:1,maxLength:64,pattern:"^[a-z][a-z0-9-]*$",description:"Context name (lowercase, alphanumeric with hyphens)"},intent:{type:"string",maxLength:1e3,description:"Human-readable description of what this context does"},attributes:{type:"object",description:"Freeform intent attributes for policy hints and visualization"}},required:["name"]},resources:{type:"object",description:"Resource declarations",properties:{functions:{type:"object",description:"Function deployments"},databases:{type:"object",description:"Database table declarations"},storage:{type:"object",description:"Storage bucket declarations"},sites:{type:"object",description:"Static site declarations"}}},identities:{type:"object",description:"Identity declarations",properties:{users:{type:"object",description:"User declarations"},serviceAccounts:{type:"object",description:"Service account declarations"}}}},required:["version"]};var Ai=new H(!0),Be=class{contextService;clients;constructor(e,r){this.contextService=e,this.clients=r}async loadConfiguration(e){let r=ki(e);try{let s=await Fe.readFile(r,"utf-8");return JSON.parse(s)}catch(s){throw s.code==="ENOENT"?new x(`IaC file not found: ${e}`):s instanceof SyntaxError?new x(`Invalid JSON in IaC file: ${s.message}`):s}}validate(e){let r=[],s=[],i=Ai.test(Vr,e);if(!i.success)for(let o of i.errors||[])r.push({path:o.key||"",message:o.error||"Validation error"});if(e.version!=="1"&&r.push({path:"version",message:`Unsupported IaC version: ${e.version}. Only version "1" is supported.`}),e.resources?.functions){for(let[o,n]of Object.entries(e.resources.functions))if(n.bindings)for(let a of n.bindings){let c=a.resource;c.includes(":")||(a.service==="databases"?e.resources?.databases?.[c]||s.push({path:`resources.functions.${o}.bindings`,message:`Database '${c}' is not declared in this configuration`}):a.service==="storage"&&(e.resources?.storage?.[c]||s.push({path:`resources.functions.${o}.bindings`,message:`Storage bucket '${c}' is not declared in this configuration`})))}}return{valid:r.length===0,errors:r,warnings:s}}async apply(e,r={}){let s=this.validate(e);if(!s.valid)return{success:!1,context:e.context?.name||G,created:[],updated:[],unchanged:[],deleted:[],errors:s.errors.map(n=>({type:"validation",name:n.path,error:n.message}))};let i=e.context?.name||G,o={success:!0,context:i,created:[],updated:[],unchanged:[],deleted:[],errors:[]};if(await this.contextService.ensureContext(i),e.context)try{await this.contextService.contextExists(i)&&await this.contextService.updateContext(i,{intent:e.context.intent,attributes:e.context.attributes})}catch{}if(e.resources?.databases&&this.clients.databases)for(let[n]of Object.entries(e.resources.databases))try{await this.clients.databases.tableExists(n)?o.unchanged.push({type:"database",name:n}):(await this.clients.databases.createTable(n),await this.contextService.registerResource(i,"database",n),o.created.push({type:"database",name:n}))}catch(a){o.errors.push({type:"database",name:n,error:a.message||"Unknown error"}),o.success=!1}if(e.resources?.storage&&this.clients.storage)for(let[n,a]of Object.entries(e.resources.storage))try{await this.clients.storage.bucketExists(n)?await this.clients.storage.isBucketPublic(n)!==(a.public||!1)?(await this.clients.storage.updateBucket(n,{public:a.public}),o.updated.push({type:"storage",name:n})):o.unchanged.push({type:"storage",name:n}):(await this.clients.storage.createBucket(n,a.public||!1),await this.contextService.registerResource(i,"storage",n),o.created.push({type:"storage",name:n}))}catch(c){o.errors.push({type:"storage",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.resources?.functions&&this.clients.functions)for(let[n,a]of Object.entries(e.resources.functions))try{let c;if(a.code)c=a.code;else if(a.source){let p=r.basePath?at(r.basePath,a.source):a.source;try{c=await Fe.readFile(p,"utf-8")}catch{throw new Error(`Cannot read function source: ${a.source}`)}}else throw new Error('Function must have either "code" or "source" defined');let l=await this.clients.functions.get(n);if(l)await this.clients.functions.update(l.id,{code:c,methods:a.methods,bindings:a.bindings,allowUnauthenticated:a.allowUnauthenticated,passAllHeaders:a.passAllHeaders}),o.updated.push({type:"function",name:n});else{let p=await this.clients.functions.deploy(n,c,{id:a.id,methods:a.methods,bindings:a.bindings,allowUnauthenticated:a.allowUnauthenticated,passAllHeaders:a.passAllHeaders});await this.contextService.registerResource(i,"function",p.id),o.created.push({type:"function",name:n})}}catch(c){o.errors.push({type:"function",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.resources?.sites&&this.clients.sites)for(let[n,a]of Object.entries(e.resources.sites))try{let c;if(a.files&&a.files.length>0)c=a.files;else if(a.source){let p=r.basePath?at(r.basePath,a.source):a.source;if(c=await this.loadSiteFiles(p),c.length===0)throw new Error(`No files found in site source: ${a.source}`)}else throw new Error('Site must have either "files" or "source" defined');let l=await this.clients.sites.getProject(n);await this.clients.sites.uploadProject(c,n),await this.contextService.registerResource(i,"site",n),l?o.updated.push({type:"site",name:n}):o.created.push({type:"site",name:n})}catch(c){o.errors.push({type:"site",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.identities?.users&&this.clients.identity)for(let[n,a]of Object.entries(e.identities.users))try{let c=await this.clients.identity.getUser(a.email);c?(await this.clients.identity.updateUser(c.id,{roles:a.roles}),o.updated.push({type:"user",name:a.email})):(await this.clients.identity.createUser(a.email,n,a.roles,{id:a.id}),await this.contextService.registerResource(i,"user",a.email),o.created.push({type:"user",name:a.email}))}catch(c){o.errors.push({type:"user",name:a.email,error:c.message||"Unknown error"}),o.success=!1}if(e.identities?.serviceAccounts&&this.clients.identity)for(let[n,a]of Object.entries(e.identities.serviceAccounts))try{let c=await this.clients.identity.getServiceAccount(n);c?(await this.clients.identity.updateServiceAccount(c.id,{roles:a.roles,description:a.description}),o.updated.push({type:"serviceAccount",name:n})):(await this.clients.identity.createServiceAccount(n,a.roles,a.description,{id:a.id}),await this.contextService.registerResource(i,"serviceAccount",n),o.created.push({type:"serviceAccount",name:n}))}catch(c){o.errors.push({type:"serviceAccount",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.resources?.applications&&this.clients.applications)for(let[n,a]of Object.entries(e.resources.applications))try{let c=await this.clients.applications.get(n);if(c)await this.clients.applications.update(c.id,{description:a.description,redirectUris:a.redirectUris}),o.updated.push({type:"application",name:n});else{let l=await this.clients.applications.create(n,a.description,a.redirectUris,{id:a.id});await this.contextService.registerResource(i,"application",l.id),o.created.push({type:"application",name:n})}}catch(c){o.errors.push({type:"application",name:n,error:c.message||"Unknown error"}),o.success=!1}if(r.prune){let n=await this.contextService.getContextResources(i);if(this.clients.functions){let a=Object.keys(e.resources?.functions||{}),c=await this.clients.functions.list();for(let l of n.functions){let p=c.find(u=>u.id===l);if(p&&!a.includes(p.name))try{await this.clients.functions.delete(l),await this.contextService.unregisterResource(i,"function",l),o.deleted.push({type:"function",name:p.name})}catch(u){o.errors.push({type:"function",name:p.name,error:`Failed to delete: ${u.message||"Unknown error"}`}),o.success=!1}}}if(this.clients.databases){let a=Object.keys(e.resources?.databases||{});for(let c of n.databases)if(!a.includes(c))try{await this.clients.databases.deleteTable(c),await this.contextService.unregisterResource(i,"database",c),o.deleted.push({type:"database",name:c})}catch(l){o.errors.push({type:"database",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.storage){let a=Object.keys(e.resources?.storage||{});for(let c of n.storage)if(!a.includes(c))try{await this.clients.storage.deleteBucket(c),await this.contextService.unregisterResource(i,"storage",c),o.deleted.push({type:"storage",name:c})}catch(l){o.errors.push({type:"storage",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.sites){let a=Object.keys(e.resources?.sites||{});for(let c of n.sites)if(!a.includes(c))try{await this.clients.sites.deleteProject(c),await this.contextService.unregisterResource(i,"site",c),o.deleted.push({type:"site",name:c})}catch(l){o.errors.push({type:"site",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.applications){let a=Object.keys(e.resources?.applications||{}),c=await this.clients.applications.list();for(let l of n.applications){let p=c.find(u=>u.id===l);if(p&&!a.includes(p.name))try{await this.clients.applications.delete(l),await this.contextService.unregisterResource(i,"application",l),o.deleted.push({type:"application",name:p.name})}catch(u){o.errors.push({type:"application",name:p.name,error:`Failed to delete: ${u.message||"Unknown error"}`}),o.success=!1}}}if(this.clients.identity){let a=Object.values(e.identities?.users||{}).map(c=>c.email);for(let c of n.users)if(!a.includes(c))try{let l=await this.clients.identity.getUser(c);l&&(await this.clients.identity.deleteUser(l.id),await this.contextService.unregisterResource(i,"user",c),o.deleted.push({type:"user",name:c}))}catch(l){o.errors.push({type:"user",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.identity){let a=Object.keys(e.identities?.serviceAccounts||{});for(let c of n.serviceAccounts)if(!a.includes(c))try{let l=await this.clients.identity.getServiceAccount(c);l&&(await this.clients.identity.deleteServiceAccount(l.id),await this.contextService.unregisterResource(i,"serviceAccount",c),o.deleted.push({type:"serviceAccount",name:c}))}catch(l){o.errors.push({type:"serviceAccount",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}}return o}async loadSiteFiles(e,r=""){let s=[];try{let i=await Fe.readdir(e,{withFileTypes:!0});for(let o of i){let n=at(e,o.name),a=r?`${r}/${o.name}`:o.name;if(o.isDirectory()){let c=await this.loadSiteFiles(n,a);s.push(...c)}else if(o.isFile()){let l=(await Fe.readFile(n)).toString("base64");s.push({path:a,content:l})}}}catch(i){if(i.code!=="ENOENT")throw i}return s}async diff(e){let r=e.context?.name||G,s=[],i=[],o=[],n=[],a=await this.contextService.getContextResources(r);if(this.clients.databases){let c=Object.keys(e.resources?.databases||{});for(let l of c)await this.clients.databases.tableExists(l)?n.push({type:"database",name:l}):s.push({type:"database",name:l});for(let l of a.databases)c.includes(l)||o.push({type:"database",name:l})}if(this.clients.storage){let c=Object.keys(e.resources?.storage||{});for(let l of c)if(await this.clients.storage.bucketExists(l)){let u=e.resources?.storage?.[l];await this.clients.storage.isBucketPublic(l)!==(u?.public||!1)?i.push({type:"storage",name:l}):n.push({type:"storage",name:l})}else s.push({type:"storage",name:l});for(let l of a.storage)c.includes(l)||o.push({type:"storage",name:l})}if(this.clients.functions){let c=Object.keys(e.resources?.functions||{});for(let l of c)await this.clients.functions.get(l)?i.push({type:"function",name:l}):s.push({type:"function",name:l});for(let l of a.functions)c.includes(l)||o.push({type:"function",name:l})}if(this.clients.sites){let c=Object.keys(e.resources?.sites||{});for(let l of c)await this.clients.sites.getProject(l)?i.push({type:"site",name:l}):s.push({type:"site",name:l});for(let l of a.sites)c.includes(l)||o.push({type:"site",name:l})}if(this.clients.applications){let c=Object.keys(e.resources?.applications||{});for(let l of c)await this.clients.applications.get(l)?i.push({type:"application",name:l}):s.push({type:"application",name:l});for(let l of a.applications)c.includes(l)||o.push({type:"application",name:l})}return{toCreate:s,toUpdate:i,toDelete:o,unchanged:n}}};var X=class{constructor(e,r){this.baseUrl=e;this.authToken=r}async request(e,r,s,i){let o=`${this.baseUrl}${r}`;if(i){let u=new URLSearchParams(i);o+=`?${u.toString()}`}let n={"Content-Type":"application/json"};this.authToken&&(n.Authorization=`Bearer ${this.authToken}`);let a={method:e,headers:n};s&&(a.body=JSON.stringify(s));let c=await fetch(o,a),l=c.headers.get("content-type"),p;if(l?.includes("application/json")?p=await c.json():p=await c.text(),!c.ok){let u=typeof p=="object"&&p.error?p.error:typeof p=="string"?p:JSON.stringify(p);throw new Error(u)}return p}},ct=class extends X{async createTable(e){await this.request("POST",`/tables/${e}`)}async tableExists(e){try{return((await this.request("GET","/tables")).tables||[]).some(i=>i.name===e)}catch{return!1}}async deleteTable(e){await this.request("DELETE",`/tables/${e}`)}async listTables(){return((await this.request("GET","/tables")).tables||[]).map(s=>s.name)}},lt=class extends X{async createBucket(e,r){await this.request("POST",`/buckets/${e}`,{public:r})}async bucketExists(e){try{return await this.request("GET",`/buckets/${e}`),!0}catch{return!1}}async updateBucket(e,r){await this.request("PATCH",`/buckets/${e}`,r)}async deleteBucket(e){await this.request("DELETE",`/buckets/${e}`)}async listBuckets(){return(await this.request("GET","/buckets")).buckets||[]}async isBucketPublic(e){try{return(await this.request("GET",`/buckets/${e}`)).public===!0}catch{return!1}}},ut=class extends X{async deploy(e,r,s){let i=await this.request("POST","/deploy",{name:e,code:r,id:s.id,methods:s.methods,bindings:s.bindings,allowUnauthenticated:s.allowUnauthenticated,passAllHeaders:s.passAllHeaders,env:s.env});return i.function||i}async get(e){try{return((await this.request("GET","/list")).functions||[]).find(i=>i.name===e)||null}catch{return null}}async update(e,r){let s=await this.request("PUT",`/${e}`,r);return s.function||s}async delete(e){await this.request("DELETE",`/${e}`)}async list(){return(await this.request("GET","/list")).functions||[]}},dt=class extends X{async uploadProject(e,r){return await this.request("POST","/projects",{files:e,projectId:r})}async getProject(e){try{return((await this.request("GET","/projects")).projects||[]).find(i=>i.projectId===e)||null}catch{return null}}async deleteProject(e){await this.request("DELETE",`/projects/${e}`)}async listProjects(){return(await this.request("GET","/projects")).projects||[]}},pt=class extends X{async createUser(e,r,s,i){let o=await this.request("POST","/identity/users",{email:e,name:r,roles:s,id:i?.id});return o.user||o}async getUser(e){try{return((await this.request("GET","/identity/users")).users||[]).find(i=>i.metadata?.email===e)||null}catch{return null}}async updateUser(e,r){let s=await this.request("PATCH",`/identity/users/${e}`,r);return s.user||s}async deleteUser(e){await this.request("DELETE",`/identity/users/${e}`)}async listUsers(){return(await this.request("GET","/identity/users")).users||[]}async createServiceAccount(e,r,s,i){let o=await this.request("POST","/identity/service-accounts",{name:e,roles:r,description:s,id:i?.id});return o.serviceAccount||o}async getServiceAccount(e){try{return((await this.request("GET","/identity/service-accounts")).serviceAccounts||[]).find(i=>i.name===e)||null}catch{return null}}async updateServiceAccount(e,r){let s=await this.request("PATCH",`/identity/service-accounts/${e}`,r);return s.serviceAccount||s}async deleteServiceAccount(e){await this.request("DELETE",`/identity/service-accounts/${e}`)}async listServiceAccounts(){return(await this.request("GET","/identity/service-accounts")).serviceAccounts||[]}},ht=class extends X{async create(e,r,s,i){return await this.request("POST","/applications",{name:e,description:r,redirectUris:s,id:i?.id})}async get(e){try{return((await this.request("GET","/applications")).applications||[]).find(i=>i.name===e)||null}catch{return null}}async update(e,r){return await this.request("PATCH",`/applications/${e}`,r)}async delete(e){await this.request("DELETE",`/applications/${e}`)}async list(){return(await this.request("GET","/applications")).applications||[]}};function mt(t){let{serviceUrls:e,authToken:r}=t,s={};return e.databases&&(s.databases=new ct(e.databases,r)),e.storage&&(s.storage=new lt(e.storage,r)),e.functions&&(s.functions=new ut(e.functions,r)),e.sites&&(s.sites=new dt(e.sites,r)),e.identity&&(s.identity=new pt(e.identity,r)),e.applications&&(s.applications=new ht(e.applications,r)),s}import{readFileSync as Ii,existsSync as Ei}from"node:fs";function qr(){let t=process.env.MOLNOS_RUNTIME_CONFIG,e={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:"http://127.0.0.1:3000"},context:{apiUrl:"http://127.0.0.1:3000"},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(!t||!Ei(t))return e;try{let r=Ii(t,"utf-8");return JSON.parse(r)}catch(r){return console.error("[loadRuntimeConfig] Failed to load runtime config:",r),e}}async function Fr(t,e,r,s){try{let i=t.headers["x-forwarded-for"],o=(Array.isArray(i)?i[0]:i)?.split(",")[0]?.trim()||t.headers["x-real-ip"]||"unknown";if(!r.checkRateLimit(`oauth:${o}`)){let p=r.getRateLimitInfo(`oauth:${o}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((p.reset-Date.now())/1e3)},429)}let n=Array.isArray(t.query.redirect_uri)?t.query.redirect_uri[0]:t.query.redirect_uri,a=Array.isArray(t.query.application_id)?t.query.application_id[0]:t.query.application_id,c=r.generateState(t,s,n,a),l=e.getAuthorizationUrl(c);return t.redirect(l,302)}catch(i){let{message:o,status:n}=m(i,"Error initiating OAuth flow");return t.json({error:o},n)}}async function Br(t,e,r,s,i,o){try{let n=t.headers["x-forwarded-for"],a=Array.isArray(n)?n[0]:n,c=t.headers["x-real-ip"],l=Array.isArray(c)?c[0]:c,p=a?.split(",")[0]?.trim()||l||"unknown";if(!r.checkRateLimit(`oauth:${p}`)){let R=r.getRateLimitInfo(`oauth:${p}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((R.reset-Date.now())/1e3)},429)}let u=r.validateCallback(t,o);if(!u.valid)return t.json({error:u.error||"Invalid OAuth callback"},400);let h=await e.handleCallback(u.code,p),v=await s.getUserByEmail(h.user.email);if(!v)return t.json({error:"User not found. You must be invited before signing in with OAuth."},403);if(await s.updateUser(v.id,{lastLogin:new Date().toISOString()}),u.redirectUrl){if(u.applicationId&&!await i.validateRedirectUri(u.applicationId,u.redirectUrl))return console.warn(`Redirect URL validation failed for applicationId: ${u.applicationId}`),t.json({success:!0,accessToken:h.accessToken,refreshToken:h.refreshToken,expiresIn:h.expiresIn,tokenType:h.tokenType,user:{id:v.id,email:h.user.email,name:h.user.name,username:h.user.username},warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);let R=new URL(u.redirectUrl);return R.searchParams.set("access_token",h.accessToken),R.searchParams.set("refresh_token",h.refreshToken),R.searchParams.set("expires_in",h.expiresIn.toString()),t.redirect(R.toString(),302)}return t.json({success:!0,accessToken:h.accessToken,refreshToken:h.refreshToken,expiresIn:h.expiresIn,tokenType:h.tokenType,user:{id:v.id,email:h.user.email,name:h.user.name,username:h.user.username}})}catch(n){let{message:a,status:c}=m(n,"OAuth authentication failed");return t.json({error:a},c)}}async function _r(t,e){try{let r=Array.from(e.values()).map(s=>s.getPublicInfo());return t.json({providers:r,count:r.length})}catch(r){let{message:s,status:i}=m(r,"Error listing OAuth providers");return t.json({error:s},i)}}var _e=class{constructor(e,r){this.config=e;this.mikroAuth=r}getAuthorizationUrl(e){let r=Array.isArray(this.config.scopes)?this.config.scopes.join(" "):this.config.scopes,s=new URLSearchParams({client_id:this.config.clientId,redirect_uri:this.config.redirectUri,response_type:"code",scope:r,state:e,...this.config.authorizationParams});return`${this.config.authorizationUrl}?${s}`}async exchangeCodeForTokens(e){let r=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,code:e,grant_type:"authorization_code",redirect_uri:this.config.redirectUri}),s=await fetch(this.config.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json",...this.config.tokenHeaders},body:r.toString()});if(!s.ok){let i=await s.text();throw new Error(`Token exchange failed: ${s.status} ${s.statusText} - ${i}`)}return s.json()}async fetchUserInfo(e){let r=await fetch(this.config.userInfoUrl,{headers:{Authorization:`Bearer ${e}`,Accept:"application/json",...this.config.userInfoHeaders}});if(!r.ok){let s=await r.text();throw new Error(`User info fetch failed: ${r.status} ${r.statusText} - ${s}`)}return r.json()}mapUserInfo(e){return this.config.userMapping?this.config.userMapping(e):{id:e.sub||e.id?.toString(),email:e.email,name:e.name||e.preferred_username,username:e.preferred_username||e.username||e.email?.split("@")[0]}}async handleCallback(e,r){let s=await this.exchangeCodeForTokens(e),i=await this.fetchUserInfo(s.access_token),o=this.mapUserInfo(i);if(!o.email)throw new Error("OAuth provider did not return user email");let n=await this.mikroAuth.createToken({email:o.email,username:o.username||o.name,role:"user",ip:r});return{accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.exp,tokenType:n.tokenType,user:o}}getPublicInfo(){return{id:this.config.id,name:this.config.name,loginUrl:`/auth/oauth/${this.config.id}`}}};import Pi from"node:crypto";var ze=class{stateStore=new Map;rateLimitStore=new Map;stateExpiryMs;rateLimitMaxAttempts;rateLimitWindowMs;stateCleanupInterval;rateLimitCleanupInterval;constructor(e){this.stateExpiryMs=(e?.stateExpirySeconds||600)*1e3,this.rateLimitMaxAttempts=e?.rateLimiting?.maxAttempts||10,this.rateLimitWindowMs=e?.rateLimiting?.windowMs||900*1e3,this.startCleanupTasks()}generateState(e,r,s,i){let o=Pi.randomBytes(32).toString("hex"),n=this.getClientIp(e),a=e.headers["user-agent"]||"";return this.stateStore.set(o,{expires:Date.now()+this.stateExpiryMs,providerId:r,ip:n,userAgent:a,redirectUrl:s,applicationId:i}),o}validateState(e,r,s,i){let o=this.stateStore.get(e);return o?o.expires<Date.now()?(this.stateStore.delete(e),!1):o.providerId!==r||o.ip!==s||i&&o.userAgent&&o.userAgent!==i?!1:(this.stateStore.delete(e),!0):!1}checkRateLimit(e){let r=Date.now(),s=this.rateLimitStore.get(e);return!s||s.resetAt<r?(this.rateLimitStore.set(e,{count:1,resetAt:r+this.rateLimitWindowMs}),!0):s.count>=this.rateLimitMaxAttempts?!1:(s.count++,!0)}getRateLimitInfo(e){let r=this.rateLimitStore.get(e),s=Date.now();return!r||r.resetAt<s?{limit:this.rateLimitMaxAttempts,remaining:this.rateLimitMaxAttempts-1,reset:s+this.rateLimitWindowMs}:{limit:this.rateLimitMaxAttempts,remaining:Math.max(0,this.rateLimitMaxAttempts-r.count),reset:r.resetAt}}validateCallback(e,r){let s=Array.isArray(e.query.code)?e.query.code[0]:e.query.code,i=Array.isArray(e.query.state)?e.query.state[0]:e.query.state,o=Array.isArray(e.query.error)?e.query.error[0]:e.query.error,n=Array.isArray(e.query.error_description)?e.query.error_description[0]:e.query.error_description;if(o)return{valid:!1,error:`OAuth provider error: ${n||o}`};if(!s||!i)return{valid:!1,error:"Missing code or state parameter"};let a=this.stateStore.get(i),c=this.getClientIp(e),l=e.headers["user-agent"];return this.validateState(i,r,c,l)?{valid:!0,code:s,state:i,redirectUrl:a?.redirectUrl,applicationId:a?.applicationId}:{valid:!1,error:"Invalid or expired state token (CSRF protection failed)"}}getClientIp(e){let r=e.headers["x-forwarded-for"],s=Array.isArray(r)?r[0]:r,i=e.headers["x-real-ip"],o=Array.isArray(i)?i[0]:i;return s?.split(",")[0]?.trim()||o||"unknown"}startCleanupTasks(){this.stateCleanupInterval=setInterval(()=>{this.cleanupExpiredStates()},300*1e3),this.rateLimitCleanupInterval=setInterval(()=>{this.cleanupExpiredRateLimits()},600*1e3)}cleanupExpiredStates(){let e=Date.now(),r=0;for(let[s,i]of this.stateStore.entries())i.expires<e&&(this.stateStore.delete(s),r++);r>0&&console.log(`[OAuthSecurity] Cleaned up ${r} expired state tokens`)}cleanupExpiredRateLimits(){let e=Date.now(),r=0;for(let[s,i]of this.rateLimitStore.entries())i.resetAt<e&&(this.rateLimitStore.delete(s),r++);r>0&&console.log(`[OAuthSecurity] Cleaned up ${r} expired rate limit records`)}shutdown(){this.stateCleanupInterval&&clearInterval(this.stateCleanupInterval),this.rateLimitCleanupInterval&&clearInterval(this.rateLimitCleanupInterval)}getStats(){return{stateCount:this.stateStore.size,rateLimitCount:this.rateLimitStore.size}}};var zr={google:{id:"google",name:"Google",authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",userInfoUrl:"https://www.googleapis.com/oauth2/v2/userinfo",scopes:"openid email profile",authorizationParams:{access_type:"offline",prompt:"consent"},userMapping:t=>({id:t.sub,email:t.email,name:t.name,username:t.email.split("@")[0]})},github:{id:"github",name:"GitHub",authorizationUrl:"https://github.com/login/oauth/authorize",tokenUrl:"https://github.com/login/oauth/access_token",userInfoUrl:"https://api.github.com/user",scopes:"user:email read:user",tokenHeaders:{Accept:"application/json"},userInfoHeaders:{Accept:"application/vnd.github.v3+json"},userMapping:t=>({id:t.id.toString(),email:t.email,name:t.name||t.login,username:t.login})},microsoft:{id:"microsoft",name:"Microsoft",authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",userInfoUrl:"https://graph.microsoft.com/v1.0/me",scopes:"openid email profile User.Read",userMapping:t=>({id:t.id,email:t.mail||t.userPrincipalName,name:t.displayName,username:t.userPrincipalName?.split("@")[0]})},gitlab:{id:"gitlab",name:"GitLab",authorizationUrl:"https://gitlab.com/oauth/authorize",tokenUrl:"https://gitlab.com/oauth/token",userInfoUrl:"https://gitlab.com/api/v4/user",scopes:"read_user email",userMapping:t=>({id:t.id.toString(),email:t.email,name:t.name,username:t.username})}};function Wr(t){let e=[];if(t.presets)for(let[r,s]of Object.entries(t.presets)){let i=zr[r];if(!i){console.warn(`[OAuth] Unknown preset provider: ${r}`);continue}e.push({...i,clientId:s.clientId,clientSecret:s.clientSecret,redirectUri:s.redirectUri,scopes:s.scopes||i.scopes,authorizationParams:{...i.authorizationParams,...s.authorizationParams}})}return t.custom&&e.push(...t.custom),e}async function Gr(t,e){let r=await e(),s=r.headers||{};return s["X-Frame-Options"]="DENY",s["X-Content-Type-Options"]="nosniff",s["X-XSS-Protection"]="1; mode=block",s["Referrer-Policy"]="strict-origin-when-cross-origin",s["Content-Security-Policy"]="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",s["Permissions-Policy"]="geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()",process.env.NODE_ENV==="production"&&(s["Strict-Transport-Security"]="max-age=31536000; includeSubDomains"),{...r,headers:s}}async function ft(t,e){return process.env.NODE_ENV==="development"||process.env.NODE_ENV==="test"||(t.headers["x-forwarded-proto"]||t.headers["x-forwarded-protocol"])==="https"||t.req.url?.startsWith("https://")?e():t.json({error:"HTTPS required",message:"OAuth authentication requires HTTPS. Please use https:// instead of http://"},403)}function Kr(t,e,r){if(r.startsWith("/databases/")){r.includes("/table")||r.includes("/get")?g(t,"databases.table.get",{}):r.includes("/write")||r.includes("/update")||e==="PUT"||e==="PATCH"?g(t,"databases.table.update",{}):r.includes("/delete")||e==="DELETE"?g(t,"databases.table.delete",{}):e==="POST"&&g(t,"databases.table.create",{});return}if(r.startsWith("/functions/")){r.includes("/deploy")||e==="POST"?g(t,"functions.function.create",{}):r.includes("/run/")?g(t,"functions.function.execute",{}):e==="PUT"||e==="PATCH"?g(t,"functions.function.update",{}):e==="DELETE"?g(t,"functions.function.delete",{}):e==="GET"&&g(t,"functions.function.get",{});return}if(r.startsWith("/storage/")){let s=r.match(/^\/storage\/buckets\/[^/]+$/),i=r.includes("/objects");s?e==="POST"?g(t,"storage.bucket.create",{}):e==="PATCH"||e==="PUT"?g(t,"storage.bucket.update",{}):e==="DELETE"?g(t,"storage.bucket.delete",{}):e==="GET"&&g(t,"storage.bucket.get",{}):i||r.includes("/upload")||r.includes("/download")||r.includes("/get")?r.includes("/upload")||e==="POST"?g(t,"storage.object.create",{}):r.includes("/download")||r.includes("/get")?g(t,"storage.object.get",{}):e==="PUT"||e==="PATCH"?g(t,"storage.object.update",{}):e==="DELETE"?g(t,"storage.object.delete",{}):e==="GET"&&g(t,"storage.object.get",{}):e==="GET"&&g(t,"storage.bucket.get",{});return}if(r.startsWith("/sites/")){if(r.match(/^\/sites\/projects\/[^/]+/)&&e==="GET")return;r.includes("/deploy")||e==="POST"?g(t,"sites.site.create",{}):e==="PUT"||e==="PATCH"?g(t,"sites.site.update",{}):e==="DELETE"?g(t,"sites.site.delete",{}):e==="GET"&&g(t,"sites.site.get",{});return}if(r.startsWith("/observability/")){e==="POST"?g(t,"observability.metrics.create",{}):e==="GET"&&g(t,"observability.metrics.get",{});return}}var We=class{baseUrl;authToken;constructor(e,r){this.baseUrl=e.replace(/\/$/,""),this.authToken=r}async createCustomRole(e,r,s,i){let o=await fetch(`${this.baseUrl}/identity/roles`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({roleId:e,name:r,description:s,permissions:i})});if(!o.ok){let n=`Failed to create role: ${o.statusText}`;try{n=(await o.json()).error||n}catch{n=await o.text().catch(()=>o.statusText)||n}throw new Error(n)}}async updateRole(e,r){let s=await fetch(`${this.baseUrl}/identity/roles/${e}`,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(r)});if(!s.ok){let i=await s.json();throw new Error(i.error||`Failed to update role: ${s.statusText}`)}}async deleteRole(e){let r=await fetch(`${this.baseUrl}/identity/roles/${e}`,{method:"DELETE",headers:this.getHeaders()});if(!r.ok){let s=await r.json();throw new Error(s.error||`Failed to delete role: ${r.statusText}`)}}async addServiceAccount(e,r,s){let i=await fetch(`${this.baseUrl}/identity/service-accounts`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:e,description:r,roles:s})});if(!i.ok){let n=`Failed to create service account: ${i.statusText}`;try{n=(await i.json()).error||n}catch{n=await i.text().catch(()=>i.statusText)||n}throw new Error(n)}let o=await i.json();return{id:o.id,apiKey:o.apiKey}}async deleteIdentity(e){let r=await fetch(`${this.baseUrl}/identity/service-accounts/${e}`,{method:"DELETE",headers:this.getHeaders()});if(!r.ok){let s=await r.json();throw new Error(s.error||`Failed to delete service account: ${r.statusText}`)}}async getUserFromToken(e){try{let r=await fetch(`${this.baseUrl}/identity/whoami`,{method:"GET",headers:{Authorization:`Bearer ${e}`}});return r.ok?await r.json():null}catch{return null}}getHeaders(){let e={"Content-Type":"application/json"};return this.authToken&&(e.Authorization=`Bearer ${this.authToken}`),e}};function Jr(t){return t?new We(t):null}function Xr(t){return t&&typeof t=="number"&&t>0?t*1024*1024:0}async function Yr(t){let{auth:e,db:r,config:s,molnos:i,oauth:o}=t,n=new Ne(e,r,i.initialUser);await n.start();let c=`${s.useHttps||s.useHttp2?"https":"http"}://${s.host||"127.0.0.1"}:${s.port||3e3}`,l=Jr(c),p,u;if(o){p=new ze(o),u=new Map;let d=Wr(o);for(let k of d){let b=new _e(k,e);u.set(k.id,b)}}let h=gt(i.dataPath,"applications"),v=new Ve({dbPath:h});await v.start();let R=gt(i.dataPath,"management"),S=new de({dbPath:R}),Ge=gt(i.dataPath,".runtime-config.json");S.setEnvironmentVariables({MOLNOS_RUNTIME_CONFIG:Ge});let D=i.cluster;S.setClusterConfig(D),await S.start();let Y;D?.mode==="core"&&D.workers?(Y=new Ce,await Y.registerWorkers(D.workers),console.log("[Server] Cluster mode: core - registered remote workers")):D?.mode==="worker"&&console.log(`[Server] Cluster mode: worker - capabilities: ${D.capabilities?.join(", ")}`);let $=new qe(r);await $.start();let O=qr(),Z=d=>{let k=mt({serviceUrls:{databases:O.services.databases.url,storage:O.services.storage.url,functions:O.services.functions.url,sites:O.services.sites.url,identity:O.identity.apiUrl,applications:O.identity.apiUrl},authToken:d});return new Be($,k)},B=!1,f=new we({port:s.port||3e3,host:s.host||"127.0.0.1",allowedDomains:s.allowedDomains,maxBodySize:Xr(1e3),rateLimit:i.rateLimit?.global||{enabled:!1,requestsPerMinute:0}});f.use(async(d,k)=>B?d.text("Service Unavailable - Server is shutting down",503):k()),f.use(Gr),D?.mode==="worker"&&D.secret&&f.use(Se(D.secret)),f.get("/health",async d=>d.text("OK"));let A=async d=>d.text("Not Found",404);if(f.post("/auth/login",d=>_t(d,n,e,v)),f.get("/auth/verify",d=>zt(d,e,v)),f.post("/auth/refresh",d=>Wt(d,e)),u&&p){f.get("/auth/oauth/providers",d=>_r(d,u));for(let[d,k]of u.entries())f.get(`/auth/oauth/${d}`,ft,b=>Fr(b,k,p,d)),f.get(`/auth/oauth/${d}/callback`,ft,b=>Br(b,k,p,n,v,d))}f.post("/management/service",y,d=>yr(d,S)),f.get("/management/services",y,d=>mr(d,S)),f.get("/management/service/:serviceName",y,d=>fr(d,S)),f.put("/management/service/:serviceName",y,d=>wr(d,S)),f.delete("/management/service/:serviceName",y,d=>Sr(d,S)),f.get("/management/service/:serviceName/start",y,d=>br(d,S)),f.get("/management/service/:serviceName/stop",y,d=>xr(d,S)),f.get("/management/service/:serviceName/logs",y,d=>Cr(d,S)),f.get("/management/service/:serviceName/restart",y,d=>kr(d,S)),f.get("/identity/whoami",y,d=>Gt(d)),f.get("/identity/identities",y,d=>Kt(d,n)),f.post("/identity/users",y,d=>Xt(d,n)),f.get("/identity/users",y,d=>Yt(d,n)),f.get("/identity/users/:userId",y,d=>Zt(d,n)),f.patch("/identity/users/:userId",y,d=>er(d,n)),f.delete("/identity/users/:userId",y,d=>tr(d,n)),f.post("/identity/service-accounts",y,d=>rr(d,n)),f.get("/identity/service-accounts",y,d=>sr(d,n)),f.get("/identity/service-accounts/:serviceAccountId",y,d=>ir(d,n)),f.patch("/identity/service-accounts/:serviceAccountId",y,d=>nr(d,n)),f.delete("/identity/service-accounts/:serviceAccountId",y,d=>ar(d,n)),f.post("/identity/service-accounts/:serviceAccountId/rotate-key",y,d=>cr(d,n)),f.post("/identity/roles",y,d=>dr(d,n)),f.get("/identity/roles",y,d=>lr(d,n)),f.get("/identity/roles/:roleId",y,d=>ur(d,n)),f.patch("/identity/roles/:roleId",y,d=>pr(d,n)),f.delete("/identity/roles/:roleId",y,d=>hr(d,n)),f.post("/applications",y,d=>Ir(d,v,l)),f.get("/applications",y,d=>Pr(d,v,l)),f.get("/applications/:id",y,d=>Er(d,v,l)),f.patch("/applications/:id",y,d=>Tr(d,v,l)),f.delete("/applications/:id",y,d=>Rr(d,v,l)),f.get("/contexts",y,d=>jr(d,$,l)),f.post("/contexts",y,d=>Or(d,$,l)),f.get("/contexts/:contextName",y,d=>$r(d,$,l)),f.patch("/contexts/:contextName",y,d=>Mr(d,$,l)),f.delete("/contexts/:contextName",y,d=>Ur(d,$,l)),f.delete("/contexts/:contextName/resources",y,d=>Lr(d,$,l,k=>mt({serviceUrls:{databases:O.services.databases.url,storage:O.services.storage.url,functions:O.services.functions.url,sites:O.services.sites.url,identity:O.identity.apiUrl,applications:O.identity.apiUrl},authToken:k}))),f.post("/iac/validate",y,d=>Hr(d,Z,l)),f.post("/iac/apply",y,d=>Dr(d,Z,l)),f.post("/iac/diff",y,d=>Nr(d,Z,l)),f.get("/databases/*",y,T,A),f.post("/databases/*",y,T,A),f.put("/databases/*",y,T,A),f.patch("/databases/*",y,T,A),f.delete("/databases/*",y,T,A);async function pe(d,k){if(d.path.match(/^\/functions\/run\//)){let U=d.headers.authorization;if(U)try{let j=await n.getUserFromToken(U);j&&(d.state.user=j,d.state.requestingIdentity=j)}catch{}return k()}return y(d,k)}f.get("/functions/*",pe,T,A),f.post("/functions/*",pe,T,A),f.put("/functions/*",pe,T,A),f.patch("/functions/*",pe,T,A),f.delete("/functions/*",pe,T,A),f.get("/sites/projects/:projectId/*",T,async d=>d.text("Not Found",404)),f.get("/sites/*",y,T,A),f.post("/sites/*",y,T,A),f.put("/sites/*",y,T,A),f.patch("/sites/*",y,T,A),f.delete("/sites/*",y,T,A);async function he(d,k){let b=d.req.method;if(d.path.match(/^\/storage\/buckets\/[^/]+\/objects\/.+/)&&(b==="GET"||b==="HEAD")){let j=d.headers.authorization;if(j)try{let K=await n.getUserFromToken(j);K&&(d.state.user=K,d.state.requestingIdentity=K)}catch{}return k()}return y(d,k)}f.get("/storage/*",he,T,A),f.post("/storage/*",he,T,A),f.put("/storage/*",he,T,A),f.patch("/storage/*",he,T,A),f.delete("/storage/*",he,T,A),f.get("/observability/*",y,T,A),f.post("/observability/*",y,T,A),f.put("/observability/*",y,T,A),f.patch("/observability/*",y,T,A),f.delete("/observability/*",y,T,A);function ns(d,k,b,M){if(k!=="POST")return;let U=null,j=null;d==="/functions/deploy"&&M.function?.id?(U="function",j=M.function.id):d.match(/^\/databases\/tables\/[^/]+$/)&&M.name?(U="database",j=M.name):d.match(/^\/storage\/buckets\/[^/]+$/)&&M.bucket?(U="storage",j=M.bucket):d==="/sites/projects"&&M.projectId&&(U="site",j=M.projectId),U&&j&&$.registerResource(b,U,j).catch(K=>{console.error(`[Server] Failed to register ${U} '${j}' with context '${b}':`,K.message)})}async function T(d,k){try{let b=d.path,M=Object.keys(d.query).length>0?`?${new URLSearchParams(d.query).toString()}`:"",U=d.req.method||"",j,K=0,cs=await S.getServices();for(let L of cs)L.active&&b.startsWith(L.prefix)&&L.prefix.length>K&&(j=L,K=L.prefix.length);if(!j)return k();let wt=d.state.user;if(!(b.match(/^\/sites\/projects\/[^/]+.*/)&&U==="GET")&&wt&&Kr(wt,U,b),j.healthCheck&&j.healthCheck.healthy===!1)return d.json({error:"Service unavailable (unhealthy)"},503);let St=(b.substring(j.prefix.length)||"/")+M,N=null,Ke=null,Je=null;if(["POST","PUT","PATCH","DELETE"].includes(U)){let L=d.headers["content-type"]||"";if(L.includes("application/json"))try{let Q=await w(d);Je=Q,N=JSON.stringify(Q)}catch{N=null}else if(L.includes("multipart/form-data"))try{N=JSON.stringify(d.body),Ke="application/json"}catch{N=null}else try{N=Buffer.isBuffer(d.body)?d.body:Buffer.from(d.body)}catch{N=null}}let Ae=j.name,bt=D?.mode==="core"?D.workers?.[Ae]:void 0;if(bt&&Y){if(!Y.isHealthy(Ae))return d.json({error:`Worker for ${Ae} is unavailable`},503);try{let L=await it(bt,St,U,N,d.headers,D?.secret);return ot(d,L)}catch(L){return console.error(`[Server] Worker proxy error for ${Ae}:`,L.message),d.json({error:L.message},L.statusCode||503)}}return new Promise(L=>{let Q={...d.headers,host:`127.0.0.1:${j.port}`};Ke&&(Q["content-type"]=Ke),N&&(typeof N=="string"?Q["content-length"]=Buffer.byteLength(N).toString():Q["content-length"]=N.length.toString());let ls={method:U,hostname:"127.0.0.1",port:j.port,path:St,headers:Q},me=Ti.request(ls,q=>{let xt=[];q.on("data",ne=>{xt.push(ne)}),q.on("end",()=>{let ne=Buffer.concat(xt),Xe={};Object.entries(q.headers).forEach(([ge,J])=>{J!==void 0&&(Xe[ge]=Array.isArray(J)?J.join(", "):J)});let fe=q.headers["content-type"]||"",_;if(fe.includes("application/json"))try{let ge=JSON.parse(ne.toString("utf-8")),J=q.statusCode||200;ge.success&&J>=200&&J<300&&Je?.context&&ns(b,U,Je.context,ge),_=d.json(ge,J)}catch{_=d.text(ne.toString("utf-8"),q.statusCode||200)}else fe.startsWith("text/")||fe.includes("javascript")||fe.includes("xml")?_=d.text(ne.toString("utf-8"),q.statusCode||200):(_=d.binary(ne,fe||"application/octet-stream"),q.statusCode&&q.statusCode!==200&&(_.statusCode=q.statusCode));_.headers?_.headers={..._.headers,...Xe}:_.headers=Xe,L(_)})});me.on("error",q=>{L(d.json({error:"Proxy Error",message:q.message},502))}),me.on("timeout",()=>{me.destroy(),L(d.json({error:"Gateway Timeout"},504))}),N&&me.write(N),me.end()})}catch(b){return yt(d,b)}}async function y(d,k){try{let b=d.headers.authorization;if(!b)return d.text("Unauthorized",401);let M=await n.getUserFromToken(b);return M?(d.state.user=M,d.state.requestingIdentity=M,k()):d.text("Unauthorized",401)}catch(b){return yt(d,b)}}function yt(d,k){let b=k.message||k,M=k?.cause?.statusCode||400;return d.json({error:b},M)}let vt=f.start();async function as(){B||(B=!0,await new Promise((d,k)=>{vt.close(b=>{b?k(b):d()})}),console.log("[Server] Stopping managed services..."),await S.shutdown(),p&&p.shutdown(),await r.close())}return{server:vt,shutdown:as,processManager:S,identityService:n}}import Ri from"node:http";import{join as ji}from"node:path";async function Zr(t){let{config:e,dataPath:r,cluster:s}=t,i=new we({...e});if(s.secret){let l=Se(s.secret);i.use(l)}let o=new de({dbPath:ji(r,"molnosdb")});await o.start();let n=s.capabilities||[];console.log(`[Worker] Starting capabilities: ${n.join(", ")}`);for(let l of n)await o.startService(l);let a=async l=>{let p=l.path,u=Object.keys(l.query).length>0?`?${new URLSearchParams(l.query).toString()}`:"",h=l.req.method||"GET",R=(await o.getServices()).find($=>p.startsWith(`/${$.name}`)&&$.active);if(!R)return l.json({error:"Service not found"},404);let Ge=(p.substring(`/${R.name}`.length)||"/")+u,D=null;["POST","PUT","PATCH","DELETE"].includes(h)&&(l.headers["content-type"]||"").includes("application/json")&&l.body&&(D=JSON.stringify(l.body));let Y={};for(let[$,O]of Object.entries(l.headers))$.toLowerCase()!==le&&O&&(Y[$]=typeof O=="string"?O:O[0]);return new Promise($=>{let O={method:h,hostname:"127.0.0.1",port:R.port,path:Ge,headers:Y},Z=Ri.request(O,B=>{let f="";B.on("data",A=>{f+=A}),B.on("end",()=>{if((B.headers["content-type"]||"").includes("application/json"))try{$(l.json(JSON.parse(f),B.statusCode||200))}catch{$(l.text(f,B.statusCode||200))}else $(l.text(f,B.statusCode||200))})});Z.on("error",()=>{$(l.json({error:"Service unavailable"},503))}),D&&Z.write(D),Z.end()})};i.get("/health",l=>l.json({status:"ok",mode:"worker"}));for(let l of n)i.get(`/${l}/*`,a),i.post(`/${l}/*`,a),i.put(`/${l}/*`,a),i.patch(`/${l}/*`,a),i.delete(`/${l}/*`,a),i.options(`/${l}/*`,a);i.get("*",l=>l.json({error:"Not found",mode:"worker"},404)),await i.start();let c=e.useHttps?"https":"http";return console.log(`[Worker] Server running at ${c}://${e.host||"localhost"}:${e.port}`),{shutdown:async()=>{await o.shutdown()}}}var es=()=>{let t=Qr(process.env.DEBUG)||!1,e=Qr(process.env.RATE_LIMIT_ENABLED||!1);return{auth:{jwtSecret:process.env.AUTH_JWT_SECRET||"your-jwt-secret",magicLinkExpirySeconds:900,jwtExpirySeconds:900,refreshTokenExpirySeconds:10080*60,maxActiveSessions:3,consoleUrl:process.env.CONSOLE_URL||"http://localhost:8000",debug:t},email:{emailSubject:"Sign In To MolnOS",user:process.env.EMAIL_USER||"",host:process.env.EMAIL_HOST||"",password:process.env.EMAIL_PASSWORD||"",port:465,secure:!0,maxRetries:2,debug:t},storage:{databaseDirectory:"molnosdb",encryptionKey:process.env.STORAGE_KEY||"",debug:t},server:{port:Number(process.env.PORT)||3e3,host:process.env.HOST||"127.0.0.1",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",allowedDomains:["http://localhost:8000"],debug:t},molnos:{dataPath:process.env.DATA_PATH||"data",initialUser:{id:process.env.INITIAL_USER_ID||ke(),userName:process.env.INITIAL_USER_NAME||"",email:process.env.INITIAL_USER_EMAIL||""},rateLimit:{global:{enabled:e,requestsPerMinute:Number(process.env.RATE_LIMIT_RPS)||0}},signedUrlSecret:process.env.SIGNED_URL_SECRET||"molnos-default-signed-url-secret"}}};function Qr(t){return t==="true"||t===!0}var C=es(),ts={configFilePath:"molnos.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:C.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:C.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:C.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:C.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:C.auth.maxActiveSessions},{flag:"--consoleUrl",path:"auth.consoleUrl",defaultValue:C.auth.consoleUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:C.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:C.email.host},{flag:"--emailUser",path:"email.user",defaultValue:C.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:C.email.password},{flag:"--emailPort",path:"email.port",defaultValue:C.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:C.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:C.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:C.email.debug},{flag:"--db",path:"storage.databaseDirectory",defaultValue:C.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:C.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:C.storage.debug},{flag:"--port",path:"server.port",defaultValue:C.server.port},{flag:"--host",path:"server.host",defaultValue:C.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:C.server.useHttps},{flag:"--http2",path:"server.useHttp2",isFlag:!0,defaultValue:C.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:C.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:C.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:C.server.sslCa},{flag:"--allowed",path:"server.allowedDomains",defaultValue:C.server.allowedDomains,parser:te.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:C.server.debug},{flag:"--data-path",path:"dataPath",defaultValue:C.molnos.dataPath},{flag:"--initialUserId",path:"molnos.initialUser.id",defaultValue:C.molnos.initialUser.id},{flag:"--initialUserName",path:"molnos.initialUser.userName",defaultValue:C.molnos.initialUser.userName},{flag:"--initialUserEmail",path:"molnos.initialUser.email",defaultValue:C.molnos.initialUser.email}]};function rs(t){return{...t,auth:{...t.auth,templates:{textVersion:(e,r,s)=>{let i=new URL(e),o=i.searchParams.get("token")||"",n=i.searchParams.get("email")||"",a=s?.appName||"MolnOS",c=s?.redirectUrl&&s?.applicationId,l=c?`Sign in to ${a}`:"Sign in to MolnOS",p=c?`You're signing in to ${a}. Click the link below to complete the authentication process.`:"Click the link below to sign in to your account.";return`
114
+ `),a="",c="",l,p;for(let h of n){let v=h.toLowerCase();if(v.startsWith("content-disposition:")){a=h.substring(20).trim();let R=a.match(/name="([^"]+)"/);R&&(c=R[1]);let S=a.match(/filename="([^"]+)"/);S&&(l=S[1])}else v.startsWith("content-type:")&&(p=h.substring(13).trim())}if(!c)return null;let u=i;return u.length>=2&&u[u.length-2]===13&&u[u.length-1]===10&&(u=u.subarray(0,u.length-2)),{disposition:a,name:c,filename:l,contentType:p,data:u}}import{readFileSync as le}from"fs";import st from"http";import Xs from"http2";import Ys from"https";var we=class{config;rateLimiter;router;shutdownHandlers=[];constructor(t){let e=new ee(Dt(t||{})).get();e.debug&&console.log("Using configuration:",e),this.config=e,this.router=new Ht;let r=e.rateLimit.requestsPerMinute||Te().rateLimit.requestsPerMinute;this.rateLimiter=new Lt(r,60),e.rateLimit.enabled===!0&&this.use(this.rateLimitMiddleware.bind(this))}use(t){return this.router.use(t),this}get(t,...e){return this.router.get(t,...e),this}post(t,...e){return this.router.post(t,...e),this}put(t,...e){return this.router.put(t,...e),this}delete(t,...e){return this.router.delete(t,...e),this}patch(t,...e){return this.router.patch(t,...e),this}any(t,...e){return this.router.any(t,...e),this}options(t,...e){return this.router.options(t,...e),this}start(){let t=this.createServer(),{port:e,host:r}=this.config;return this.setupGracefulShutdown(t),t.listen(e,r,()=>{let s=t.address(),i=this.config.useHttps||this.config.useHttp2?"https":"http";console.log(`MikroServe running at ${i}://${s.address!=="::"?s.address:"localhost"}:${s.port}`)}),t}createServer(){let t=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 e={key:le(this.config.sslKey),cert:le(this.config.sslCert),...this.config.sslCa?{ca:le(this.config.sslCa)}:{}};return Xs.createSecureServer(e,t)}catch(e){throw e.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${e.message}`):e}}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 e={key:le(this.config.sslKey),cert:le(this.config.sslCert),...this.config.sslCa?{ca:le(this.config.sslCa)}:{}};return Ys.createServer(e,t)}catch(e){throw e.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${e.message}`):e}}return st.createServer(t)}async rateLimitMiddleware(t,e){let r=t.req.socket.remoteAddress||"unknown";return t.res.setHeader("X-RateLimit-Limit",this.rateLimiter.getLimit().toString()),t.res.setHeader("X-RateLimit-Remaining",this.rateLimiter.getRemainingRequests(r).toString()),t.res.setHeader("X-RateLimit-Reset",this.rateLimiter.getResetTime(r).toString()),this.rateLimiter.isAllowed(r)?e():{statusCode:429,body:{error:"Too Many Requests",message:"Rate limit exceeded, please try again later"},headers:{"Content-Type":"application/json"}}}async requestHandler(t,e){let r=Date.now(),s=t.method||"UNKNOWN",i=t.url||"/unknown",o=this.config.debug;try{if(this.setCorsHeaders(e,t),this.setSecurityHeaders(e,this.config.useHttps),o&&console.log(`${s} ${i}`),t.method==="OPTIONS"){if(e instanceof st.ServerResponse)e.statusCode=204,e.end();else{let a=e;a.writeHead(204),a.end()}return}try{t.body=await this.parseBody(t)}catch(a){return o&&console.error("Body parsing error:",a.message),this.respond(e,{statusCode:400,body:{error:"Bad Request",message:a.message}})}let n=await this.router.handle(t,e);return n?n._handled?void 0:this.respond(e,n):this.respond(e,{statusCode:404,body:{error:"Not Found",message:"The requested endpoint does not exist"}})}catch(n){return console.error("Server error:",n),this.respond(e,{statusCode:500,body:{error:"Internal Server Error",message:o?n.message:"An unexpected error occurred"}})}finally{o&&this.logDuration(r,s,i)}}logDuration(t,e,r){let s=Date.now()-t;console.log(`${e} ${r} completed in ${s}ms`)}async parseBody(t){return new Promise((e,r)=>{let s=[],i=0,o=this.config.maxBodySize,n=!1,a=null,c=this.config.debug,l=t.headers["content-type"]||"";c&&console.log("Content-Type:",l),this.config.requestTimeout>0&&(a=setTimeout(()=>{n||(n=!0,c&&console.log("Request timeout exceeded"),r(new Error("Request timeout")))},this.config.requestTimeout));let p=()=>{a&&(clearTimeout(a),a=null)};t.on("data",u=>{if(!n){if(i+=u.length,c&&console.log(`Received chunk: ${u.length} bytes, total size: ${i}`),i>o){n=!0,p(),c&&console.log(`Body size exceeded limit: ${i} > ${o}`),r(new Error("Request body too large"));return}s.push(u)}}),t.on("end",()=>{if(!n){n=!0,p(),c&&console.log(`Request body complete: ${i} bytes`);try{if(s.length>0){let u=Buffer.concat(s);if(l.includes("application/json"))try{let h=u.toString("utf8");e(JSON.parse(h))}catch(h){r(new Error(`Invalid JSON in request body: ${h.message}`))}else if(l.includes("application/x-www-form-urlencoded")){let h=u.toString("utf8"),v={};new URLSearchParams(h).forEach((R,S)=>{v[S]=R}),e(v)}else if(l.includes("multipart/form-data"))try{let h=Nt(u,l);e(h)}catch(h){r(new Error(`Invalid multipart form data: ${h.message}`))}else this.isBinaryContentType(l)?e(u):e(u.toString("utf8"))}else e({})}catch(u){r(new Error(`Invalid request body: ${u}`))}}}),t.on("error",u=>{n||(n=!0,p(),r(new Error(`Error reading request body: ${u.message}`)))}),t.on("close",()=>{p()})})}isBinaryContentType(t){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(r=>t.includes(r))}setCorsHeaders(t,e){let r=e.headers.origin,{allowedDomains:s=["*"]}=this.config;!r||s.length===0||s.includes("*")?t.setHeader("Access-Control-Allow-Origin","*"):s.includes(r)&&(t.setHeader("Access-Control-Allow-Origin",r),t.setHeader("Vary","Origin")),t.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),t.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),t.setHeader("Access-Control-Max-Age","86400")}setSecurityHeaders(t,e=!1){let r={"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((e||this.config.useHttp2)&&(r["Strict-Transport-Security"]="max-age=31536000; includeSubDomains"),t instanceof st.ServerResponse)Object.entries(r).forEach(([s,i])=>{t.setHeader(s,i)});else{let s=t;Object.entries(r).forEach(([i,o])=>{s.setHeader(i,o)})}}respond(t,e){let r={...e.headers||{}};(i=>typeof i.writeHead=="function"&&typeof i.end=="function")(t)?(t.writeHead(e.statusCode,r),e.body===null||e.body===void 0?t.end():e.isRaw||typeof e.body=="string"?t.end(e.body):t.end(JSON.stringify(e.body))):(console.warn("Unexpected response object type without writeHead/end methods"),t.writeHead?.(e.statusCode,r),e.body===null||e.body===void 0?t.end?.():e.isRaw||typeof e.body=="string"?t.end?.(e.body):t.end?.(JSON.stringify(e.body)))}setupGracefulShutdown(t){let e=n=>{console.log("Shutting down MikroServe server..."),n&&console.error("Error:",n),this.cleanupShutdownHandlers(),t.close(()=>{console.log("Server closed successfully"),process.env.NODE_ENV!=="test"&&process.env.VITEST!=="true"&&setImmediate(()=>process.exit(n?1:0))})},r=()=>e(),s=()=>e(),i=n=>e(n),o=n=>e(n);this.shutdownHandlers=[r,s,i,o],process.on("SIGINT",r),process.on("SIGTERM",s),process.on("uncaughtException",i),process.on("unhandledRejection",o)}cleanupShutdownHandlers(){if(this.shutdownHandlers.length>0){let[t,e,r,s]=this.shutdownHandlers;process.removeListener("SIGINT",t),process.removeListener("SIGTERM",e),process.removeListener("uncaughtException",r),process.removeListener("unhandledRejection",s),this.shutdownHandlers=[]}}};import{timingSafeEqual as Zs}from"node:crypto";var oe="x-molnos-cluster-secret";function Vt(t,e){if(!t)return!1;let r=Buffer.from(t),s=Buffer.from(e);return r.length!==s.length?!1:Zs(r,s)}function Se(t){return async(e,r)=>{let s=e.headers[oe];return s?Vt(s,t)?(e.state.isClusterRequest=!0,r()):e.json({success:!1,error:"Invalid cluster authentication"},403):r()}}function it(t,e){return{...t,[oe]:e}}var x=class extends Error{constructor(e){super(),this.name="ValidationError",this.message=e||"Invalid input",this.cause={statusCode:400}}},be=class extends Error{constructor(e){super(),this.name="IdentityAlreadyExistsError",this.message=e||"Identity already exists",this.cause={statusCode:400}}},F=class extends Error{constructor(e){super(),this.name="NotFoundError",this.message=e||"Resource not found",this.cause={statusCode:404}}},Re=class extends Error{constructor(e){super(),this.name="InvalidInputError",this.message=e||"Invalid input",this.cause={statusCode:400}}};var je=class extends Error{constructor(e){super(),this.name="ConfigurationError",this.message=e||"Invalid configuration",this.cause={statusCode:400}}};var ue=class extends Error{constructor(e){super(),this.name="PermissionDeniedError",this.message=e||"Permission denied",this.cause={statusCode:403}}},z=class extends Error{constructor(e){super(),this.name="AlreadyExistsError",this.message=e||"Resource already exists",this.cause={statusCode:409}}},$e=class extends Error{constructor(e){super(),this.name="PortInUseError",this.message=e||"Port already in use",this.cause={statusCode:409}}},xe=class extends Error{constructor(e){super(),this.name="RoleNotFoundError",this.message=e||"Role not found",this.cause={statusCode:404}}},Oe=class extends Error{constructor(e){super(),this.name="ProtectedResourceError",this.message=e||"Cannot modify protected resource",this.cause={statusCode:403}}},Ue=class extends Error{constructor(e){super(),this.name="ServiceRequestError",this.message=e||"Service request failed",this.cause={statusCode:502}}},Me=class extends Error{constructor(e){super(),this.name="WorkerUnavailableError",this.message=e||"Worker node is unavailable",this.cause={statusCode:503}}},Le=class extends Error{constructor(e){super(),this.name="WorkerTimeoutError",this.message=e||"Worker node did not respond in time",this.cause={statusCode:504}}};var Qs=5e3;async function ot(t,e,r,s,i,o){let n=new URL(e,t.url),a=new Headers;for(let[u,h]of Object.entries(i)){let v=u.toLowerCase();v==="host"||v==="connection"||v==="keep-alive"||v==="transfer-encoding"||a.set(u,h)}o&&a.set(oe,o);let c=t.timeoutMs||Qs,l=new AbortController,p=setTimeout(()=>l.abort(),c);try{let u;s&&(Buffer.isBuffer(s)?u=new Uint8Array(s):u=s);let h=await fetch(n.toString(),{method:r,headers:a,body:u,signal:l.signal});return clearTimeout(p),h}catch(u){throw clearTimeout(p),u.name==="AbortError"?new Le(`Worker at ${t.url} did not respond within ${c}ms`):new Me(`Worker at ${t.url} is unavailable: ${u.message}`)}}async function nt(t,e){let r=e.headers.get("content-type")||"",s=e.status;if(r.includes("application/json")){let n=await e.text();try{let a=JSON.parse(n);return t.json(a,s)}catch{return t.text(n,s)}}if(r.startsWith("text/")||r.includes("javascript")||r.includes("xml")){let n=await e.text();return t.text(n,s)}let i=await e.arrayBuffer(),o=t.binary(Buffer.from(i),r||"application/octet-stream");return s!==200?{...o,statusCode:s}:o}var He={healthCheckPath:"/health",healthCheckIntervalMs:3e4,timeoutMs:5e3,failureThreshold:3},Ce=class{workers=new Map;timers=new Map;async registerWorkers(e){let r=Object.keys(e);for(let s of r){let i=e[s];i&&await this.registerWorker(s,i)}}async registerWorker(e,r){let s={url:r.url,capability:e,healthy:!0,consecutiveFailures:0,timeoutMs:r.timeoutMs||He.timeoutMs};this.workers.set(e,s);let i=r.healthCheckIntervalMs||He.healthCheckIntervalMs,o=r.healthCheckPath||He.healthCheckPath,n=setInterval(()=>this.checkHealth(e,o),i);this.timers.set(e,n),await this.checkHealth(e,o)}async checkHealth(e,r){let s=this.workers.get(e);if(s){try{let i=new AbortController,o=setTimeout(()=>i.abort(),s.timeoutMs),n=await fetch(`${s.url}${r}`,{method:"GET",signal:i.signal});clearTimeout(o),n.ok?this.handleSuccess(s):this.handleFailure(s)}catch{this.handleFailure(s)}s.lastHealthCheck=new Date}}handleSuccess(e){e.healthy=!0,e.consecutiveFailures=0}handleFailure(e){e.consecutiveFailures++,e.consecutiveFailures>=He.failureThreshold&&(e.healthy&&console.error(`[WorkerHealthChecker] Worker ${e.capability} at ${e.url} is now unhealthy (${e.consecutiveFailures} consecutive failures)`),e.healthy=!1)}isHealthy(e){return this.workers.get(e)?.healthy??!1}getWorkerState(e){return this.workers.get(e)}getAllWorkerStates(){return new Map(this.workers)}hasWorker(e){return this.workers.has(e)}shutdown(){for(let e of this.timers.values())clearInterval(e);this.timers.clear(),this.workers.clear()}};import ni from"node:crypto";import{getRandomValues as ei}from"node:crypto";var at=class{options;defaultLength=16;defaultOnlyLowerCase=!1;defaultStyle="extended";defaultUrlSafe=!0;constructor(t){if(this.options={},t)for(let[e,r]of Object.entries(t))this.options[e]=this.generateConfig(r)}add(t){if(!t?.name)throw new Error("Missing name for the ID configuration");let e=this.generateConfig(t);this.options[t.name]=e}remove(t){if(!t?.name)throw new Error("Missing name for the ID configuration");delete this.options[t.name]}create(t,e,r,s){let i=this.generateConfig({length:t,style:e,onlyLowerCase:r,urlSafe:s});return this.generateId(i)}custom(t){if(this.options[t])return this.generateId(this.options[t]);throw new Error(`No configuration found with name: ${t}`)}generateConfig(t){return{name:t?.name||"",length:t?.length||this.defaultLength,onlyLowerCase:t?.onlyLowerCase??this.defaultOnlyLowerCase,style:t?.style||this.defaultStyle,urlSafe:t?.urlSafe??this.defaultUrlSafe}}getCharacterSet(t,e,r){if(t==="hex")return e?"0123456789abcdef":"0123456789ABCDEFabcdef";if(t==="alphanumeric")return e?"abcdefghijklmnopqrstuvwxyz0123456789":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";if(t==="extended")return r?e?"abcdefghijklmnopqrstuvwxyz0123456789-._~":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~":e?"abcdefghijklmnopqrstuvwxyz0123456789-._~!$()*+,;=:":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$()*+,;=:";throw new Error(`Unknown ID style "${t} provided. Must be one of "extended" (default), "alphanumeric", or "hex".`)}generateId(t){let{length:e,onlyLowerCase:r,style:s,urlSafe:i}=t;if(e<0||e===0)throw new Error("ID length cannot be negative");let o=this.getCharacterSet(s,r,i),n=(2<<Math.log(o.length-1)/Math.LN2)-1,a=Math.ceil(1.6*n*e/o.length),c="";for(;c.length<e;){let l=new Uint8Array(a);ei(l);for(let p=0;p<a;p++){let u=l[p]&n;if(u<o.length&&(c+=o[u],c.length===e))break}}return c}};var ti=8,ri=40,si=/^[a-zA-Z0-9_-]{1,40}$/;function ke(){return new at().create(ti,"alphanumeric",!1,!0)}function ii(t){return si.test(t)}function oi(t){if(!ii(t))throw new Error(`Invalid ID format: "${t}". IDs must be 1-${ri} characters using only alphanumeric characters, underscores, and hyphens.`)}function De(t){return t?(oi(t),t):ke()}function Ft(t,e,r){if(!r)return!1;let s=typeof t=="string"?[t]:t,i=typeof e=="string"?[e]:e;if(r.roles?.some(a=>a==="administrator"||a.id==="administrator"))return!0;let n=(r.roles||[]).flatMap(a=>typeof a=="string"?[]:(a.policies||[]).flatMap(l=>l?.permissions&&l?.targets?{permissions:l.permissions,targets:l.targets}:[]));for(let a of s)for(let c of i)if(!n.some(p=>qt(p?.permissions,a)&&qt(p?.targets,c)))return!1;return!0}function qt(t,e){return!t||t.length===0?!1:t.some(r=>{if(r==="*"||r===e)return!0;if(r.endsWith("*")&&r!=="*"){let s=r.slice(0,-1);return e.startsWith(s)}return!1})}var ne=class{id;name;type;roles;metadata;constructor(e){let{id:r,name:s,type:i,roles:o,metadata:n}=this.createIdentity(e);this.id=r,this.name=s,this.type=i,this.roles=o,this.metadata=n}createIdentity(e){let r=e?.id||this.createId(),s=e?.name||"",i=e?.type||"service_account",o=e?.metadata||{},n=e?.roles||["user"];return e&&this.validate({id:r,name:s,type:i,metadata:o,roles:n}),{id:r,name:s,type:i,metadata:{...o,createdAt:new Date().toISOString()},roles:n}}changeName(e){this.name=e}changeEmail(e){this.metadata||(this.metadata={}),this.metadata.email=e}updateMetadata(e){let r=this.metadata?JSON.parse(JSON.stringify(this.metadata)):{};this.metadata={...r,...e}}updateRoles(e){this.validateRoles(e),this.roles=e}createId(){return De()}isValidRoleId(e){return typeof e!="string"||e.length===0?!1:/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)}isValidType(e){return["user","service_account"].includes(e)}validate(e){let r=e.id||"",s=e.name||"",i=e.type||"",o=e.metadata||{},n=e.roles||[];if(!r)throw new x("Missing ID");if(!s)throw new x("Missing name");if(!i||!this.isValidType(i))throw new x("Missing or invalid type");if(i==="user"&&!o?.email)throw new x("Missing email for user identity");if(!n||n.length===0)throw new x("Must have at least one role");this.validateRoles(n)}validateRoles(e){(e||[]).forEach(r=>{let s=r.id||r;if(!this.isValidRoleId(s))throw new x(`Invalid role ID '${s}'`)})}can(e,r,s){return Ft(e,r,s)}fromDTO(e){return this.validate(e),this.id=e.id,this.name=e.name,this.type=e.type,this.metadata=e.metadata||{},this.roles=e.roles,this}toDTO(){return{id:this.id,name:this.name,type:this.type,metadata:this.metadata,roles:this.roles}}};function Bt(){return[{id:"administrator",name:"Administrator",description:"Full system administrator with all permissions",policies:[{permissions:["*"],targets:["*"]}],constraints:{assumable_by:{identities:[],roles:[],services:[]},assumption_constraints:{max_duration:3600,require_reason:!0,audit_level:"high"}}},{id:"user",name:"User",description:"Read-only access to resources",policies:[{permissions:["*.read"],targets:["*"]}],constraints:{assumable_by:{identities:[],roles:[],services:[]},assumption_constraints:{max_duration:3600,require_reason:!1,audit_level:"low"}}}]}var Ne=class{mikroAuth;db;tableName="identity_service";initialUser;roles;identities;serviceAccountTokens;constructor(e,r,s){this.mikroAuth=e,this.db=r,this.initialUser=s,this.roles=[],this.identities=[],this.serviceAccountTokens=new Map}async start(){await this.loadState(),this.roles.find(e=>e.id==="administrator")||this.createBaseRoles(),this.identities.length===0&&this.createInitialUser()}createBaseRoles(){let e=Bt();for(let r of e)this.roles.push(r)}async createInitialUser(){let e=this.initialUser.email,r=this.initialUser.userName,s=await this.addUser(e,r,["administrator"]);return await this.mikroAuth.createMagicLink({email:e}),s}async getUserByEmail(e){let r=this.identities.find(s=>s.type==="user"&&s.metadata?.email===e&&s.metadata?.active!==!1);if(r)return this.enrichIdentityWithRoles(r)}async addUser(e,r,s=["user"],i=!0,o){if((await this.getUsers()).find(l=>l.metadata.email===e))throw new be(`User with email ${e} already exists`);let c=new ne({id:o,name:r,type:"user",metadata:{email:e,active:i},roles:s}).toDTO();return this.identities.push(c),await this.saveState(),this.enrichIdentityWithRoles(c)}async addServiceAccount(e,r,s,i){if((await this.getServiceAccounts()).find(l=>l.name===e))throw new be(`Service account with name ${e} already exists`);let a=new ne({id:i,name:e,type:"service_account",metadata:{description:r},roles:s}).toDTO(),c=this.generateServiceAccountToken();return this.serviceAccountTokens.set(c,a.id),this.identities.push(a),await this.saveState(),{...this.enrichIdentityWithRoles(a),apiKey:c}}async rotateServiceAccountKey(e){let r=await this.getIdentityById(e);if(!r||r.type!=="service_account")return;for(let[i,o]of this.serviceAccountTokens.entries())o===e&&this.serviceAccountTokens.delete(i);let s=this.generateServiceAccountToken();return this.serviceAccountTokens.set(s,e),await this.saveState(),s}async deleteIdentity(e){for(let[s,i]of this.serviceAccountTokens.entries())i===e&&this.serviceAccountTokens.delete(s);let r=this.identities.filter(s=>s.id!==e);this.identities=r,await this.saveState()}async updateIdentity(e,r){let s=await this.getIdentityById(e);if(!s)return;let i=new ne().fromDTO(s);r?.name&&i.changeName(r.name),r?.email&&i.changeEmail(r.email),r?.roles&&i.updateRoles(r.roles),r?.metadata&&i.updateMetadata(r.metadata);let o=i.toDTO();return this.updateIdentityList(o),await this.saveState(),this.enrichIdentityWithRoles(o)}updateIdentityList(e){if(!e)throw new x("Cannot update identity list: updatedIdentity is null or undefined");let r=JSON.parse(JSON.stringify(this.identities)),s=r.find(i=>i.id===e.id);s&&Object.assign(s,e),this.identities=r}generateServiceAccountToken(){return`sa.${ke()}.${ni.randomBytes(32).toString("hex")}`}async getUserFromToken(e){if(e&&e.startsWith("Bearer ")){let r=e.split(" ")[1];if(r.startsWith("sa.")){let i=this.serviceAccountTokens.get(r);if(i){let o=this.identities.find(n=>n.id===i&&n.type==="service_account");if(o)return this.enrichIdentityWithRoles(o)}}else try{let i=this.mikroAuth.verify(r),o=i.email||i.sub;return this.getUserByEmail(o)}catch{let o=new Error("Invalid token");throw o.cause={statusCode:401},o}}}async getIdentityById(e){return this.identities.find(r=>r.id===e)}async getUserById(e){let r=await this.getIdentityById(e);if(!(!r||r.type!=="user"))return this.enrichIdentityWithRoles(r)}async getServiceAccountById(e){let r=await this.getIdentityById(e);if(!(!r||r.type!=="service_account"))return this.enrichIdentityWithRoles(r)}async updateUser(e,r){let s=await this.getIdentityById(e);if(!(!s||s.type!=="user"))return this.updateIdentity(e,r)}async updateServiceAccount(e,r){let s=await this.getIdentityById(e);if(!s||s.type!=="service_account")return;let i={...r};return r.description!==void 0&&(i.metadata={...i.metadata||{},description:r.description},delete i.description),this.updateIdentity(e,i)}async deleteUser(e){let r=await this.getIdentityById(e);return!r||r.type!=="user"?!1:(await this.deleteIdentity(e),!0)}async deleteServiceAccount(e){let r=await this.getIdentityById(e);return!r||r.type!=="service_account"?!1:(await this.deleteIdentity(e),!0)}enrichIdentityWithRoles(e){let r=JSON.parse(JSON.stringify(e));return e.roles?r.roles=e.roles.map(s=>this.roles.find(i=>i.id===s)).filter(Boolean):r.roles=[],r}async getIdentities(){return this.identities}async getUsers(){return this.identities.filter(e=>e.type==="user")}async getServiceAccounts(){return this.identities.filter(e=>e.type==="service_account")}can(e,r,s){return new ne(s).can(e,r,s)}async createCustomRole(e,r,s,i,o){if(this.roles.find(l=>l.id===e))throw new z(`Role with ID ${e} already exists`);let c={id:e,name:r,description:s,policies:[{permissions:i,targets:["*"]}],constraints:o||{assumable_by:{identities:[],roles:[],services:["functions"]},assumption_constraints:{max_duration:3600,require_reason:!1,audit_level:"medium"}}};this.roles.push(c),await this.saveState()}async updateRole(e,r){let s=this.roles.find(i=>i.id===e);if(!s)throw new xe(`Role with ID ${e} not found`);r.name!==void 0&&(s.name=r.name),r.description!==void 0&&(s.description=r.description),r.permissions!==void 0&&(s.policies=[{permissions:r.permissions,targets:["*"]}]),r.constraints!==void 0&&(s.constraints=r.constraints),await this.saveState()}async deleteRole(e){let r=this.roles.findIndex(s=>s.id===e);if(r===-1)throw new xe(`Role with ID ${e} not found`);if(e==="administrator"||e==="user")throw new Oe("Cannot delete base roles");this.roles.splice(r,1),await this.saveState()}async getRoles(){return this.roles}async getRole(e){return this.roles.find(r=>r.id===e)}async loadState(){let e=await this.load("identities");e&&(this.identities=e);let r=await this.load("roles");r&&(this.roles=r);let s=await this.load("serviceAccountTokens");if(s){let i=new Map(Object.entries(s));s&&Object.keys(s).length>0&&(this.serviceAccountTokens=i)}}async saveState(){let e=Object.fromEntries(this.serviceAccountTokens);await this.write("identities",this.identities),await this.write("roles",this.roles),await this.write("serviceAccountTokens",e)}async load(e){return await this.db.get(this.tableName,e)}async write(e,r){await this.db.write(this.tableName,e,r)}};import{existsSync as ai}from"node:fs";import{spawn as ci}from"node:child_process";import{createServer as li}from"node:net";var _t={storage:{name:"storage",path:"./storage.mjs",port:3001,prefix:"/storage",args:["--force"]},functions:{name:"functions",path:"./functions.mjs",port:3002,prefix:"/functions",args:["--force"]},sites:{name:"sites",path:"./sites.mjs",port:3003,prefix:"/sites",args:["--force"]},databases:{name:"databases",path:"./databases.mjs",port:3004,prefix:"/databases",args:["--force"]},observability:{name:"observability",path:"./observability.mjs",port:3005,prefix:"/observability",args:["--force"]}},de=class{db;services=new Map;tableName="molnosmanagement";environmentVariables={};clusterConfig;setEnvironmentVariables(e){this.environmentVariables={...this.environmentVariables,...e}}setClusterConfig(e){this.clusterConfig=e}shouldSpawnLocally(e){if(!this.clusterConfig||this.clusterConfig.mode==="standalone")return!0;let r=e;return this.clusterConfig.mode==="core"?!this.clusterConfig.workers?.[r]:this.clusterConfig.mode==="worker"?this.clusterConfig.capabilities?.includes(r)??!1:!0}getWorkerEndpoint(e){if(!this.clusterConfig||this.clusterConfig.mode!=="core")return null;let r=e;return this.clusterConfig.workers?.[r]?.url??null}async forwardToWorker(e,r){let s=this.getWorkerEndpoint(e);if(!s)return console.error(`[ManagementService] No worker configured for capability: ${e}`),!1;let i=this.clusterConfig?.secret;if(!i)return console.error("[ManagementService] Cannot forward to worker: no cluster secret configured"),!1;let o=`${s}/management/service/${e}/${r}`,n=it({"Content-Type":"application/json"},i);try{let a=await fetch(o,{method:"POST",headers:n});if(!a.ok){let l=await a.text();return console.error(`[ManagementService] Worker returned error for ${r} ${e}: ${l}`),!1}let c=await a.json();return c.isStarted??c.isStopped??c.isRestarted??!1}catch(a){return console.error(`[ManagementService] Failed to forward ${r} ${e} to worker:`,a),!1}}async isPortInUse(e){return new Promise(r=>{let s=li();s.once("error",i=>{i.code==="EADDRINUSE"?r(!0):r(!1)}),s.once("listening",()=>{s.close(),r(!1)}),s.listen(e,"127.0.0.1")})}constructor(e){this.db=new ie({databaseDirectory:e.dbPath})}getServiceDefinition(e){let r=e.toLowerCase(),s=_t[r];if(!s)throw new F(`Unknown service: ${e}. Valid services are: ${Object.keys(_t).join(", ")}`);return s}async start(){await this.db.start();let e=await this.db.get(this.tableName,"services")||[];for(let r of e)r.restartPolicy&&(r.restartPolicy.attempts=0),r.healthCheck&&(r.healthCheck.consecutiveFailures=0,r.healthCheck.consecutiveSuccesses=0,r.healthCheck.healthy=!0),this.services.set(r.name,r),this.shouldSpawnLocally(r.name)&&r.active&&await this.startService(r.name)}async stopAllServices(){let e=[];for(let[r,s]of this.services.entries())(s.active||s.process)&&e.push(this.stopService(r));await Promise.all(e)}async shutdown(){await this.stopAllServices()}validateServiceConfig(e){if(!e.name||e.name.trim()==="")throw new x("Service name is required");if(!e.path||e.path.trim()==="")throw new x("Service path is required");if(!ai(e.path))throw new je(`Service path does not exist: ${e.path}`);if(!e.port||e.port<1||e.port>65535)throw new x(`Invalid port: ${e.port}`);if(!e.prefix||!e.prefix.startsWith("/"))throw new x("Service prefix must start with /")}cleanServiceForStorage(e){let{process:r,...s}=e;if(s.healthCheck){let{timer:i,consecutiveFailures:o,consecutiveSuccesses:n,healthy:a,...c}=s.healthCheck;s.healthCheck=c}if(s.restartPolicy){let{attempts:i,...o}=s.restartPolicy;s.restartPolicy=o}return s}async registerService(e,r){let s;typeof e=="string"?s={...this.getServiceDefinition(e),...r}:s=e,this.validateServiceConfig(s);let i={...s,active:!1},o=await this.getServices(),n=[],a=[];if(o.forEach(l=>{n.push(l.name),a.push(l.port)}),a.includes(i.port))throw new $e(`Port ${i.port} already in use`);if(n.includes(i.name))throw new z(`Service with name '${i.name}' already exists`);i.restartPolicy&&(i.restartPolicy.attempts=0),i.healthCheck&&(i.healthCheck.consecutiveFailures=0,i.healthCheck.consecutiveSuccesses=0,i.healthCheck.healthy=!0),this.services.set(i.name,i);let c=await this.db.get(this.tableName,"services")||[];return c.push(this.cleanServiceForStorage(i)),await this.db.write(this.tableName,"services",c),i.name}async startService(e){if(!this.shouldSpawnLocally(e))return this.getWorkerEndpoint(e)?this.forwardToWorker(e,"start"):!1;let r=this.services.get(e);if(!r)return!1;if(r.process&&r.active)return!0;if(await this.isPortInUse(r.port))return console.error(`[ManagementService] Cannot start ${e}: Port ${r.port} is already in use. Please kill the process using this port.`),!1;try{let i={stdio:"pipe",detached:!1,env:{...process.env,...this.environmentVariables}},o=r.args||[],n=`--port=${r.port}`,a=ci("node",[r.path,n,...o],i);r.process=a,r.restartPolicy&&(r.restartPolicy.attempts=0);let c=!1;return a.stdout.on("data",l=>{let p=l.toString();console.log(`[${e}] ${p}`)}),a.stderr.on("data",l=>{let p=l.toString();console.error(`[${e}] ERROR: ${p}`),(p.includes("EADDRINUSE")||p.includes("address already in use"))&&(c=!0)}),a.on("exit",l=>{r.active=!1,r.process=void 0,c&&console.error(`[ManagementService] Service ${e} failed to start due to startup error`),this.handleServiceExit(r,l||0)}),await new Promise(l=>setTimeout(l,500)),r.process&&!r.process.killed?(r.active=!0,await this.updateServiceStatus(e,!0),r.healthCheck&&this.startHealthCheck(r),!0):(console.error(`[ManagementService] Service ${e} exited immediately after spawn`),!1)}catch(i){return console.error(`[ManagementService] Failed to start ${e}:`,i),!1}}startHealthCheck(e){let r=e.healthCheck;if(!r)return;let s=async()=>{if(e.healthCheck)try{let i=new AbortController,o=setTimeout(()=>i.abort(),e.healthCheck.timeoutMs),n=await fetch(`http://127.0.0.1:${e.port}${e.healthCheck.path}`,{signal:i.signal});clearTimeout(o),n.ok&&e.healthCheck?(e.healthCheck.consecutiveSuccesses=(e.healthCheck.consecutiveSuccesses||0)+1,e.healthCheck.consecutiveFailures=0,e.healthCheck.consecutiveSuccesses>=e.healthCheck.successThreshold&&(e.healthCheck.healthy=!0)):this.handleHealthCheckFailure(e)}catch{this.handleHealthCheckFailure(e)}};r.timer=setInterval(s,r.intervalMs)}handleHealthCheckFailure(e){e.healthCheck&&(e.healthCheck.consecutiveFailures=(e.healthCheck.consecutiveFailures||0)+1,e.healthCheck.consecutiveSuccesses=0,e.healthCheck.consecutiveFailures>=e.healthCheck.failureThreshold&&(e.healthCheck.healthy=!1,e.healthCheck.restartOnFailure&&this.restartService(e.name).catch(()=>{})))}async handleServiceExit(e,r){if(await this.updateServiceStatus(e.name,!1),!e.restartPolicy||e.restartPolicy.type==="never"||e.restartPolicy.type==="on-failure"&&r===0||e.restartPolicy.maxAttempts>0&&(e.restartPolicy.attempts||0)>=e.restartPolicy.maxAttempts)return;e.restartPolicy.attempts=(e.restartPolicy.attempts||0)+1;let s=e.restartPolicy.backoffMs;setTimeout(()=>{this.startService(e.name).catch(()=>{})},s)}async stopService(e){if(!this.shouldSpawnLocally(e))return this.getWorkerEndpoint(e)?this.forwardToWorker(e,"stop"):!1;let r=this.services.get(e);if(!r)return!1;if(r.healthCheck?.timer&&(clearInterval(r.healthCheck.timer),r.healthCheck.timer=void 0),!r.process)return r.active&&(r.active=!1,await this.updateServiceStatus(e,!1)),!0;try{let s=i=>{try{return process.kill(i,0),!0}catch{return!1}};if(r.process?.pid){let i=r.process.pid;if(s(i))try{process.kill(i,"SIGTERM");let o=setTimeout(()=>{try{s(i)&&process.kill(i,"SIGKILL")}catch{}},5*1e3);await new Promise(n=>{if(!r.process){clearTimeout(o),n();return}let a=setTimeout(()=>{clearTimeout(o),n()},6*1e3);r.process.once("exit",()=>{clearTimeout(o),clearTimeout(a),n()})})}catch(o){if(o.code!=="ESRCH")throw o}}return r.active=!1,r.process=void 0,await this.updateServiceStatus(e,!1),!0}catch{return r.active&&(r.active=!1,r.process=void 0,await this.updateServiceStatus(e,!1)),!1}}async restartService(e){return this.shouldSpawnLocally(e)?(await this.stopService(e),await new Promise(r=>setTimeout(r,500)),this.startService(e)):this.getWorkerEndpoint(e)?this.forwardToWorker(e,"restart"):!1}async updateServiceStatus(e,r){let s=await this.db.get(this.tableName,"services")||[],i=s.findIndex(o=>o.name===e);if(i>=0){let o=this.services.get(e);o?(o.active=r,s[i]=this.cleanServiceForStorage(o)):s[i].active=r,await this.db.write(this.tableName,"services",s)}}async getService(e){return(await this.getServices()).find(s=>s.name===e)}async getServices(){return(await this.db.get(this.tableName,"services")||[]).map(({process:r,...s})=>s)}async getServiceStats(e){let r=this.services.get(e);return r?{name:r.name,active:r.active,health:r.healthCheck?{healthy:r.healthCheck.healthy||!1,consecutiveSuccesses:r.healthCheck.consecutiveSuccesses||0,consecutiveFailures:r.healthCheck.consecutiveFailures||0}:null,restarts:r.restartPolicy&&r.restartPolicy.attempts||0}:null}async updateService(e,r){let s=this.services.get(e);if(!s)return!1;let i=s.active;Object.assign(s,r);let o=await this.db.get(this.tableName,"services")||[],n=o.findIndex(a=>a.name===e);return n>=0?(o[n]=this.cleanServiceForStorage(s),await this.db.write(this.tableName,"services",o),i!==s.active&&(s.active?await this.startService(e):await this.stopService(e)),!0):!1}async removeService(e){let r=this.services.get(e);r?.healthCheck?.timer&&(clearInterval(r.healthCheck.timer),r.healthCheck.timer=void 0),await this.stopService(e),this.services.delete(e);let i=(await this.db.get(this.tableName,"services")||[]).filter(o=>o.name!==e);return await this.db.write(this.tableName,"services",i),!0}};var W=class{id;name;description;redirectUris;metadata;owners;constructor(e){let r=this.createApplication(e);this.id=r.id,this.name=r.name,this.description=r.description,this.redirectUris=r.redirectUris,this.metadata=r.metadata,this.owners=r.owners}createApplication(e){let r=e?.id||this.createId(),s=e?.name||"",i=e?.description,o=e?.redirectUris||[],n=e?.owners||[],a=new Date().toISOString(),c={...e?.metadata||{},createdAt:e?.metadata?.createdAt||a,updatedAt:a,createdBy:e?.metadata?.createdBy||n[0]||""};return e&&this.validate({id:r,name:s,description:i,redirectUris:o,metadata:c,owners:n}),{id:r,name:s,description:i,redirectUris:o,metadata:c,owners:n}}update(e){e.name!==void 0&&(this.name=e.name),e.description!==void 0&&(this.description=e.description),e.redirectUris!==void 0&&(this.validateRedirectUris(e.redirectUris),this.redirectUris=e.redirectUris),e.owners!==void 0&&(this.owners=e.owners),e.metadata!==void 0?this.metadata={...this.metadata,...e.metadata,updatedAt:new Date().toISOString()}:this.metadata.updatedAt=new Date().toISOString(),this.validate(this.toDTO())}isValidRedirectUri(e){return this.redirectUris.includes(e)}isOwner(e){return this.owners.includes(e)}createId(){return De()}validate(e){let{id:r,name:s,redirectUris:i,metadata:o,owners:n}=e;if(!r)throw new x("Missing ID");if(!s||s.trim().length===0)throw new x("Missing or invalid name");if(!o)throw new x("Missing metadata");if(!n||n.length===0)throw new x("Application must have at least one owner");this.validateRedirectUris(i)}validateRedirectUris(e){if(!e||e.length===0)throw new x("At least one redirect URI is required");for(let r of e)try{let s=new URL(r);if(s.protocol!=="https:"&&s.protocol!=="http:"&&s.protocol!=="custom:")throw new x(`Invalid redirect URI protocol: ${r}. Must use https:, http: (localhost only), or custom: (for native apps)`);s.protocol==="http:"&&!s.hostname.match(/^(localhost|127\.0\.0\.1|\[::1\])$/)&&console.warn(`Warning: HTTP redirect URI detected for non-localhost: ${r}. HTTPS is recommended for production.`)}catch{throw new x(`Invalid redirect URI format: ${r}`)}}fromDTO(e){return this.validate(e),this.id=e.id,this.name=e.name,this.description=e.description,this.redirectUris=e.redirectUris,this.metadata=e.metadata,this.owners=e.owners,this}toDTO(){return{id:this.id,name:this.name,description:this.description,redirectUris:this.redirectUris,metadata:this.metadata,owners:this.owners}}};var Ve=class{db;tableName="molnosapplications";key="applications";applications;constructor(e){this.db=new ie({databaseDirectory:e.dbPath}),this.applications=[]}async start(){await this.db.start(),await this.loadState()}async loadState(){let e=await this.db.get(this.tableName,this.key)||[];this.applications=e}async saveState(){await this.db.write(this.tableName,this.key,this.applications)}async createApplication(e,r){let s=e.owners.includes(r)?e.owners:[...e.owners,r],o=new W({...e,owners:s,metadata:{...e.metadata,createdBy:r}}).toDTO();if(this.applications.find(a=>a.name===o.name))throw new z(`Application with name '${o.name}' already exists`);return this.applications.push(o),await this.saveState(),o}async getApplication(e,r){let s=this.applications.find(o=>o.id===e);if(!s)throw new F(`Application with ID '${e}' not found`);let i=new W().fromDTO(s);if(r&&!i.isOwner(r))throw new ue("Only application owners can view application details");return i.toDTO()}async getApplicationById(e){return this.applications.find(s=>s.id===e)||null}async listApplications(e){return this.applications.filter(r=>r.owners.includes(e)).map(r=>new W().fromDTO(r).toDTO())}async updateApplication(e,r,s){let i=this.applications.findIndex(a=>a.id===e);if(i===-1)throw new F(`Application with ID '${e}' not found`);let o=this.applications[i],n=new W().fromDTO(o);if(!n.isOwner(s))throw new ue("Only application owners can update the application");if(r.owners&&r.owners.length===0)throw new x("Application must have at least one owner");if(r.owners&&!r.owners.includes(s)&&o.owners.length===1&&o.owners[0]===s)throw new x("Cannot remove yourself as the last owner of the application");return n.update(r),this.applications[i]=n.toDTO(),await this.saveState(),this.applications[i]}async deleteApplication(e,r){let s=this.applications.findIndex(n=>n.id===e);if(s===-1)throw new F(`Application with ID '${e}' not found`);let i=this.applications[s];if(!new W().fromDTO(i).isOwner(r))throw new ue("Only application owners can delete the application");this.applications.splice(s,1),await this.saveState()}async validateRedirectUri(e,r){let s=await this.getApplicationById(e);return s?new W().fromDTO(s).isValidRedirectUri(r):!1}getAllApplicationsInternal(){return this.applications}};async function w(t){return t.body||{}}function m(t,e="An error occurred"){let r=t?.message||t||e,s=t?.cause?.statusCode||t?.statusCode||400;return{message:r,status:s}}async function zt(t,e,r,s){try{let i=await w(t),{email:o,redirectUrl:n,applicationId:a}=i;if(!o)return t.json({error:"Email is required"},400);let c=o.trim().toLowerCase(),l;if(n){if(!a)return t.json({error:"applicationId is required when redirectUrl is provided"},400);if(!await s.validateRedirectUri(a,n))return t.json({error:"Invalid redirectUrl or applicationId. The redirect URI must be registered for this application."},400);l=(await s.getApplicationById(a))?.name}let p=!1;return await e.getUserByEmail(c)&&(p=!0),p&&await r.createMagicLink({email:c,subject:`Sign In To ${l||"MolnOS"}`,appUrl:n,metadata:{appName:l,redirectUrl:n,applicationId:a}}),t.json({success:!0,message:"If a matching account was found, a magic link has been sent."})}catch(i){let{message:o,status:n}=m(i,"Error during login");return t.json({error:o},n)}}async function Wt(t,e,r){try{let s=t.query.token,i=t.query.email;if(!s)return t.json({error:"Token is required as query parameter"},400);if(!i)return t.json({error:"Email is required as query parameter"},400);try{let o=await e.verifyToken({token:s,email:i});if(!o)return t.json({error:"Invalid or expired token"},401);let n=o.metadata;if(n?.redirectUrl&&n?.applicationId)if(await r.validateRedirectUri(n.applicationId,n.redirectUrl)){let c=new URL(n.redirectUrl);return c.searchParams.set("access_token",o.accessToken),c.searchParams.set("refresh_token",o.refreshToken),c.searchParams.set("expires_in",o.expiresIn.toString()),t.redirect(c.toString(),302)}else return console.warn(`Redirect URL validation failed for applicationId: ${n.applicationId}`),t.json({...o,warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);return t.json(o,200)}catch{return t.json({error:"Invalid or expired token"},401)}}catch(s){let{message:i,status:o}=m(s,"Error verifying token");return t.json({error:i},o)}}async function Gt(t,e){try{let s=(await w(t)).refreshToken;if(!s)return t.json({error:"Value for refreshToken is required"},400);try{let i=await e.refreshAccessToken(s);return t.json(i,200)}catch{return t.json({error:"Invalid or expired token"},401)}}catch(r){let{message:s,status:i}=m(r,"Error refreshing token");return t.json({error:s},i)}}async function Kt(t){try{let e=t.state.user;return t.json(e)}catch(e){let{message:r,status:s}=m(e,"Error getting user info");return t.json({error:r},s)}}function g(t,e,r={}){let s=Array.isArray(e)?e:[e];if(!t||!t.roles||!Array.isArray(t.roles)){let n=new Error("Unauthorized: User or roles missing");throw n.cause={statusCode:403},n}let i=t.roles.flatMap(n=>n?.policies?.flatMap(a=>(a?.permissions||[]).flatMap(l=>typeof l=="string"?l:l&&typeof l=="object"&&l.actions?l.actions:[]))||[]);if(!s.every(n=>i.includes(n)||i.includes("*")?!0:i.some(a=>{if(a.endsWith(".*")){let c=a.slice(0,-2);return n.startsWith(`${c}.`)}return!1}))){let n=new Error("Unauthorized");throw n.cause={statusCode:403},n}return!0}async function Jt(t,e){try{let r=t.state.user;g(r,"identity.identities.get",{});let s=await e.getIdentities();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting identities");return t.json({error:s},i)}}var H=class{isSilent;propertyPath="";constructor(t=!1){this.isSilent=t}test(t,e){if(!e)throw new Error("Missing input!");this.updatePropertyPath();let{results:r,errors:s}=this.validate(t.properties,e),i=this.compileErrors(r,s),o=this.isSuccessful(r,i);return{errors:i,success:o}}compileErrors(t,e){let r=t.filter(s=>s.success===!1);return[...e,...r].flatMap(s=>s)}isSuccessful(t,e){return t.every(r=>r.success===!0)&&e.length===0}validate(t,e,r=[],s=[]){let i=t?.additionalProperties??!0,o=t?.required||[];s=this.checkForRequiredKeysErrors(o,e,s),s=this.checkForDisallowedProperties(Object.keys(e),Object.keys(t),s,i);for(let n in t){let a=o.includes(n)&&n!=="required",c=t[n],l=e[n],p=c.additionalProperties??!0;a&&(s=this.checkForRequiredKeysErrors(c.required||[],l,s)),this.isDefined(l)&&(this.handleValidation(n,l,c,r),s=this.checkForDisallowedProperties(Object.keys(l),Object.keys(c),s,p),this.handleNestedObject(l,c,r,s))}return{results:r,errors:s}}updatePropertyPath(t,e=""){if(!t){this.propertyPath="";return}e&&(this.propertyPath=e),this.propertyPath=`${this.propertyPath}.${t}`,this.propertyPath.startsWith(".")&&(this.propertyPath=this.propertyPath.substring(1,this.propertyPath.length))}isDefined(t){return!!(typeof t=="number"&&t===0||t||t===""||typeof t=="boolean")}checkForRequiredKeysErrors(t,e,r){if(!this.areRequiredKeysPresent(t,e)){let s=e?Object.keys(e):[],i=this.findNonOverlappingElements(t,s),o=i.length>0?`Missing the required key: '${i.join(", ")}'!`:`Missing values for required keys: '${s.filter(n=>!e[n]).join(", ")}'!`;r.push({key:"",value:e,success:!1,error:o})}return r}checkForDisallowedProperties(t,e,r,s){if(!s){let i=this.findNonOverlappingElements(t,e);i.length>0&&r.push({key:`${e}`,value:t,success:!1,error:`Has additional (disallowed) properties: '${i.join(", ")}'!`})}return r}handleValidation(t,e,r,s){this.updatePropertyPath(t);let i=this.validateProperty(this.propertyPath,r,e);s.push(...i);let o=(a,c)=>{a.forEach(l=>{let p=this.validateProperty(this.propertyPath,c.items,l);s.push(...p)}),this.updatePropertyPath()},n=a=>{let c=Object.keys(a),l=this.propertyPath;c.forEach(p=>{if(this.updatePropertyPath(p,l),this.isArray(a[p])&&r[p]?.items!=null)o(a[p],r[p]);else{let u=this.validateProperty(this.propertyPath,r[p],a[p]);s.push(...u)}})};this.isArray(e)&&r.items!=null?o(e,r):this.isObject(e)?n(e):this.updatePropertyPath()}handleNestedObject(t,e,r,s){if(this.isObject(t)){let i=this.getNestedObjects(t);for(let o of i){let n=e[o],a=t[o];n&&typeof a=="object"&&this.validate(n,a,r,s)}}}getNestedObjects(t){return Object.keys(t).filter(e=>{if(this.isObject(t))return e})}findNonOverlappingElements(t,e){return t.filter(r=>!e.includes(r))}areRequiredKeysPresent(t,e=[]){return t.every(r=>Object.keys(e).includes(r)?this.isDefined(e[r]):!1)}validateProperty(t,e,r){return this.validateInput(e,r).map(i=>{let{success:o,error:n}=i;return{key:t,value:r,success:o,error:n??""}})}validateInput(t,e){if(t){let r=[{condition:()=>t.type,validator:()=>this.isCorrectType(t.type,e),error:"Invalid type"},{condition:()=>t.format,validator:()=>this.isCorrectFormat(t.format,e),error:"Invalid format"},{condition:()=>t.minLength,validator:()=>this.isMinimumLength(t.minLength,e),error:"Length too short"},{condition:()=>t.maxLength,validator:()=>this.isMaximumLength(t.maxLength,e),error:"Length too long"},{condition:()=>t.minValue,validator:()=>this.isMinimumValue(t.minValue,e),error:"Value too small"},{condition:()=>t.maxValue,validator:()=>this.isMaximumValue(t.maxValue,e),error:"Value too large"},{condition:()=>t.matchesPattern,validator:()=>this.matchesPattern(t.matchesPattern,e),error:"Pattern does not match"}],s=[];for(let i of r)i.condition()&&!i.validator()&&s.push({success:!1,error:i.error});return s}else this.isSilent||console.warn(`Missing property '${t}' for match '${e}'. Skipping...`);return[{success:!0}]}isCorrectType(t,e){return Array.isArray(t)||(t=[t]),t.some(r=>{switch(r){case"string":return typeof e=="string";case"number":return typeof e=="number"&&!isNaN(e);case"boolean":return typeof e=="boolean";case"object":return this.isObject(e);case"array":return this.isArray(e)}})}isObject(t){return t!==null&&!this.isArray(t)&&typeof t=="object"&&t instanceof Object&&Object.prototype.toString.call(t)==="[object Object]"}isArray(t){return Array.isArray(t)}isCorrectFormat(t,e){switch(t){case"alphanumeric":return new RegExp(/^[a-zA-Z0-9]+$/).test(e);case"numeric":return new RegExp(/^-?\d+(\.\d+)?$/).test(e);case"email":return new RegExp(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/).test(e);case"date":return new RegExp(/^\d{4}-\d{2}-\d{2}$/).test(e);case"url":return new RegExp(/^(https?):\/\/[^\s$.?#].[^\s]*$/).test(e);case"hexColor":return new RegExp(/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i).test(e)}}isMinimumLength(t,e){return Array.isArray(e)?e.length>=t:e?.toString().length>=t}isMaximumLength(t,e){return Array.isArray(e)?e.length<=t:e.toString().length<=t}isMinimumValue(t,e){return e>=t}isMaximumValue(t,e){return e<=t}matchesPattern(t,e){return new RegExp(t).test(e)}schemaFrom(t){let e={properties:{additionalProperties:!1,required:[]}};for(let r in t){let s=t[r];e.properties.required.push(r),Array.isArray(s)?e.properties[r]=this.generateArraySchema(s):typeof s=="object"&&s!==null?e.properties[r]=this.generateNestedObjectSchema(s):e.properties[r]=this.generatePropertySchema(s)}return e}generateArraySchema(t){let e={type:"array"},r=t.filter(s=>s);if(r.length>0){let s=r[0];r.every(o=>typeof o==typeof s)?typeof s=="object"&&!Array.isArray(s)?e.items=this.generateNestedObjectSchema(s):e.items=this.generatePropertySchema(s):console.warn("All elements in array are not of the same type. Unable to generate a schema for these elements.")}return e}generateNestedObjectSchema(t){let e={type:"object",additionalProperties:!1,required:[]};for(let r in t){let s=t[r];e.required.push(r),typeof s=="object"&&!Array.isArray(s)&&s!==null?e[r]=this.generateNestedObjectSchema(s):e[r]=this.generatePropertySchema(s)}return e}generatePropertySchema(t){let e=typeof t,r={type:e};return e==="string"&&(r.minLength=1),r}};var Xt={properties:{id:{type:"string",minLength:1,maxLength:40,pattern:"^[a-zA-Z0-9_-]{1,40}$"},email:{type:"string",format:"email",minLength:3},name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}},verified:{type:"boolean"}},required:["email","name","roles"],additionalProperties:!1};var di=new H(!0);async function Yt(t,e){try{let r=t.state.user,s=await w(t),i=di.test(Xt,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);g(r,"identity.user.create",{});let{id:o,email:n,name:a,roles:c,verified:l}=s,p=await e.addUser(n,a,c,l,o);return t.json(p,201)}catch(r){let{message:s,status:i}=m(r,"Error creating user");return t.json({error:s},i)}}async function Zt(t,e){try{let r=t.state.user;g(r,"identity.user.get",{});let s=await e.getUsers();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting users");return t.json({error:s},i)}}function E(t){return t.params}async function Qt(t,e){try{let r=t.state.user,s=E(t),{userId:i}=s;g(r,"identity.user.get",{userId:i});let o=await e.getUserById(i);return o?t.json(o):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting user");return t.json({error:s},i)}}var er={properties:{name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var hi=new H(!0);async function tr(t,e){try{let r=t.state.user,s=E(t),{userId:i}=s,o=await w(t),n=hi.test(er,o);if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);g(r,"identity.user.update",{userId:i});let{name:a,roles:c}=o,l=await e.updateUser(i,{name:a,roles:c});return l?t.json(l):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error updating user");return t.json({error:s},i)}}async function rr(t,e){try{let r=t.state.user,s=E(t),{userId:i}=s;return g(r,"identity.user.delete",{userId:i}),await e.deleteUser(i)?t.body(null,204):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting user");return t.json({error:s},i)}}async function sr(t,e){try{let r=t.state.user,s=await w(t);if(!s.name||!s.description||!s.roles||!Array.isArray(s.roles))return t.json({error:"Invalid input: name, description, and roles are required"},400);if(!["user","administrator"].every(l=>s.roles.includes(l)||!s.roles.includes(l)))return t.json({error:"Invalid input: roles must be user or administrator"},400);g(r,"identity.service-account.create",{});let{id:i,name:o,description:n,roles:a}=s,c=await e.addServiceAccount(o,n,a,i);return t.json(c,201)}catch(r){let{message:s,status:i}=m(r,"Error creating service account");return t.json({error:s},i)}}async function ir(t,e){try{let r=t.state.user;g(r,"identity.service-account.get",{});let s=await e.getServiceAccounts();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting service accounts");return t.json({error:s},i)}}async function or(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s;g(r,"identity.service-account.get",{serviceAccountId:i});let o=await e.getServiceAccountById(i);return o?t.json(o):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting service account");return t.json({error:s},i)}}var nr={properties:{name:{type:"string",minLength:1,maxLength:100},description:{type:"string",minLength:1,maxLength:500},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var fi=new H(!0);async function ar(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s,o=await w(t),n=fi.test(nr,o);if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);g(r,"identity.service-account.update",{serviceAccountId:i});let{name:a,description:c,roles:l}=o,p=await e.updateServiceAccount(i,{name:a,description:c,roles:l});return p?t.json(p):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error updating service account");return t.json({error:s},i)}}async function cr(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s;return g(r,"identity.service-account.delete",{serviceAccountId:i}),await e.deleteServiceAccount(i)?t.body(null,204):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting service account");return t.json({error:s},i)}}async function lr(t,e){try{let r=t.state.user,s=E(t),{serviceAccountId:i}=s;g(r,"identity.service-account.update",{serviceAccountId:i});let o=await e.rotateServiceAccountKey(i);return o?t.json({apiKey:o}):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error rotating service account key");return t.json({error:s},i)}}async function ur(t,e){try{let r=t.state.user;g(r,"identity.role.get",{});let s=await e.getRoles();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting roles");return t.json({error:s},i)}}async function dr(t,e){try{let r=t.state.user;g(r,"identity.role.get",{});let s=t.params.roleId;if(!s)return t.text("Missing role ID",400);let i=await e.getRole(s);return i?t.json(i):t.text("Role not found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting role");return t.json({error:s},i)}}async function pr(t,e){try{let r=t.state.user;g(r,"identity.role.create",{});let s=await w(t),{roleId:i,name:o,description:n,permissions:a,constraints:c}=s;if(!i||!o||!n)return t.text("Missing required fields: roleId, name, description",400);if(!a||!Array.isArray(a))return t.text("Permissions must be a non-empty array",400);await e.createCustomRole(i,o,n,a,c);let l=await e.getRole(i);return t.json(l,201)}catch(r){let{message:s,status:i}=m(r,"Error creating role");return t.json({error:s},i)}}async function hr(t,e){try{let r=t.state.user;g(r,"identity.role.update",{});let s=t.params.roleId;if(!s)return t.text("Missing role ID",400);let i=await w(t),{name:o,description:n,permissions:a,constraints:c}=i;await e.updateRole(s,{name:o,description:n,permissions:a,constraints:c});let l=await e.getRole(s);return t.json(l)}catch(r){let{message:s,status:i}=m(r,"Error updating role");return t.json({error:s},i)}}async function mr(t,e){try{let r=t.state.user;g(r,"identity.role.delete",{});let s=t.params.roleId;return s?s==="administrator"||s==="user"?t.text("Cannot delete base roles",403):(await e.deleteRole(s),t.json({message:"Role deleted successfully"})):t.text("Missing role ID",400)}catch(r){let{message:s,status:i}=m(r,"Error deleting role");return t.json({error:s},i)}}async function fr(t,e){try{let r=t.state.user;g(r,"management.services.get",{});let s=await e.getServices();return t.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting services");return t.json({error:s},i)}}async function gr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;g(r,"management.service.get",{serviceName:i});let o=await e.getService(i);return o?t.json(o):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting service");return t.json({error:s},i)}}var yr={properties:{name:{type:"string",minLength:1},path:{type:"string"},port:{type:"number",minValue:1,maxValue:65535},prefix:{type:"string"},healthCheckPath:{type:"string"},healthCheckInterval:{type:"number",minValue:1e3}},required:["name"],additionalProperties:!0};var yi=new H(!0);async function vr(t,e){try{let r=t.state.user,s=await w(t),i=yi.test(yr,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);if(g(r,"management.service.create",{}),["storage","functions","sites","databases","observability"].includes(s.name.toLowerCase())){let{name:a,...c}=s;await e.registerService(a,c)}else{if(!s.path||!s.port||!s.prefix)return t.json({error:"Custom services require: name, path, port, and prefix"},400);await e.registerService(s)}return t.text("",201)}catch(r){let{message:s,status:i}=m(r,"Error creating service");return t.json({error:s},i)}}var wr={properties:{name:{type:"string",minLength:1},path:{type:"string"},port:{type:"number",minValue:1,maxValue:65535},prefix:{type:"string"},healthCheckPath:{type:"string"},healthCheckInterval:{type:"number",minValue:1e3}},required:["name"],additionalProperties:!0};var wi=new H(!0);async function Sr(t,e){try{let r=t.state.user,s=E(t),i=await w(t),o=i.name,n=wi.test(wr,i);return n.success?(g(r,"management.service.update",{serviceName:o}),o!==s.serviceName?t.json({error:"Service name in body must match path parameter"},400):(await e.updateService(o,i),t.body(null,204))):t.json({error:"Invalid input",details:n.errors},400)}catch(r){let{message:s,status:i}=m(r,"Error updating service");return t.json({error:s},i)}}async function br(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;return g(r,"management.service.delete",{serviceName:i}),await e.getService(i)?(await e.removeService(i),t.body(null,204)):t.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting service");return t.json({error:s},i)}}async function xr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.start",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=await e.startService(i);return t.json({serviceName:i,isStarted:n})}catch(r){let{message:s,status:i}=m(r,"Error starting service");return t.json({error:s},i)}}async function Cr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.stop",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=await e.stopService(i);return t.json({serviceName:i,isStopped:n})}catch(r){let{message:s,status:i}=m(r,"Error stopping service");return t.json({error:s},i)}}async function kr(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.get",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=new URL("http://127.0.0.1:3005/events");n.searchParams.set("service",i),t.query.startTime&&n.searchParams.set("startTime",t.query.startTime),t.query.endTime&&n.searchParams.set("endTime",t.query.endTime),t.query.level&&n.searchParams.set("level",t.query.level),t.query.limit&&n.searchParams.set("limit",t.query.limit),t.query.offset&&n.searchParams.set("offset",t.query.offset);let a=await fetch(n.toString());if(!a.ok)throw new Ue(`Observability service error: ${a.statusText}`);let c=await a.json();return t.json({serviceName:i,logs:c.events,count:c.count})}catch(r){let{message:s,status:i}=m(r,"Error getting service logs");return t.json({error:s},i)}}async function Ar(t,e){try{let r=t.state.user,s=E(t),{serviceName:i}=s;if(g(r,"management.service.start",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let n=await e.restartService(i);return t.json({serviceName:i,restarted:n})}catch(r){let{message:s,status:i}=m(r,"Error restarting service");return t.json({error:s},i)}}function Ir(t,e,r,s,i){let o=t.find(c=>c.service===e);if(!o){let c=new Error(`Function bindings do not include access to service: ${e}`);throw c.cause={statusCode:403},c}if(!o.permissions||o.permissions.length===0)return;for(let c of o.permissions)if(!(c.resource&&c.resource!==r)){if(!c.resource||!c.actions||c.actions.length===0)return;if(c.actions.includes(s)){if(c.targets&&c.targets.length>0){if(!i)return;if(!c.targets.includes(i))continue}return}}let n=i?`:${i}`:"",a=new Error(`Function bindings do not allow: ${e}.${r}.${s}${n}`);throw a.cause={statusCode:403},a}async function P(t,e,r,s,i,o,n){if(!e)return null;let a=t.state.user;if(!a){let l=t.headers.authorization;if(!l){let u=new Error("Unauthorized: No authentication provided");throw u.cause={statusCode:401},u}let p=l.replace(/^Bearer\s+/i,"");if(a=await e.getUserFromToken(p),!a){let u=new Error("Unauthorized: Invalid token");throw u.cause={statusCode:401},u}}g(a,r,{});let c=t.headers["x-function-bindings"];if(c)try{let l=Array.isArray(c)?c[0]:c,p=JSON.parse(l);Ir(p,s,i,o,n)}catch(l){if(l.cause?.statusCode===403)throw l;let p=new Error("Invalid function bindings header");throw p.cause={statusCode:400},p}return a}async function Er(t,e,r){try{let s=await w(t),i=t.state.requestingIdentity;if(!i)return t.json({error:"Authentication required"},401);let{id:o,name:n,description:a,redirectUris:c,metadata:l}=s;if(!n||!c)return t.json({error:"Missing required fields: name and redirectUris are required"},400);await P(t,r,"applications.application.create","applications","application","create",n);let p={id:o,name:n,description:a,redirectUris:Array.isArray(c)?c:[c],metadata:l,owners:[i.id]},u=await e.createApplication(p,i.id);return t.json(u,201)}catch(s){let{message:i,status:o}=m(s,"Error creating application");return t.json({error:i},o)}}async function Pr(t,e,r){try{let s=t.params.id,i=t.state.requestingIdentity;if(!s)return t.json({error:"Application ID is required"},400);await P(t,r,"applications.application.read","applications","application","read",s);let o=await e.getApplication(s,i?.id);return t.json(o,200)}catch(s){let{message:i,status:o}=m(s,"Error retrieving application");return t.json({error:i},o)}}async function Tr(t,e,r){try{let s=t.state.requestingIdentity;if(!s)return t.json({error:"Authentication required"},401);await P(t,r,"applications.application.list","applications","application","list");let i=await e.listApplications(s.id);return t.json({applications:i,total:i.length},200)}catch(s){let{message:i,status:o}=m(s,"Error listing applications");return t.json({error:i},o)}}async function Rr(t,e,r){try{let s=t.params.id,i=await w(t),o=t.state.requestingIdentity;if(!o)return t.json({error:"Authentication required"},401);if(!s)return t.json({error:"Application ID is required"},400);await P(t,r,"applications.application.update","applications","application","update",s);let n=await e.updateApplication(s,i,o.id);return t.json(n,200)}catch(s){let{message:i,status:o}=m(s,"Error updating application");return t.json({error:i},o)}}async function jr(t,e,r){try{let s=t.params.id,i=t.state.requestingIdentity;return i?s?(await P(t,r,"applications.application.delete","applications","application","delete",s),await e.deleteApplication(s,i.id),t.json({success:!0,message:"Application deleted"},200)):t.json({error:"Application ID is required"},400):t.json({error:"Authentication required"},401)}catch(s){let{message:i,status:o}=m(s,"Error deleting application");return t.json({error:i},o)}}async function $r(t,e,r){try{await P(t,r,"contexts.context.get","contexts","context","get");let i=e.listContexts().map(o=>{let n=e.getContextResources(o.name);return{...o,resourceCount:{functions:n.functions.length,databases:n.databases.length,storage:n.storage.length,sites:n.sites.length,users:n.users.length,serviceAccounts:n.serviceAccounts.length}}});return t.json({success:!0,contexts:i},200)}catch(s){let{message:i,status:o}=m(s,"Error listing contexts");return t.json({error:i},o)}}async function Or(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);await P(t,r,"contexts.context.get","contexts","context","get",s);let i=e.getContextWithResources(s);return t.json({success:!0,context:i},200)}catch(s){let{message:i,status:o}=m(s,"Error getting context");return t.json({error:i},o)}}var Si=new H(!0),bi={properties:{name:{type:"string",minLength:1,maxLength:64},intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},required:["name"],additionalProperties:!1};async function Ur(t,e,r){try{let s=await w(t),i=Si.test(bi,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);await P(t,r,"contexts.context.create","contexts","context","create");let{name:o,intent:n,attributes:a}=s,c=await e.createContext({name:o,intent:n,attributes:a});return t.json({success:!0,context:c},201)}catch(s){let{message:i,status:o}=m(s,"Error creating context");return t.json({error:i},o)}}var xi=new H(!0),Ci={properties:{intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},additionalProperties:!1};async function Mr(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);let i=await w(t),o=xi.test(Ci,i||{});if(!o.success)return t.json({error:"Invalid input",details:o.errors},400);await P(t,r,"contexts.context.update","contexts","context","update",s);let{intent:n,attributes:a}=i||{},c=await e.updateContext(s,{intent:n,attributes:a});return t.json({success:!0,context:c},200)}catch(s){let{message:i,status:o}=m(s,"Error updating context");return t.json({error:i},o)}}async function Lr(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);if(s==="default")return t.json({error:"Cannot delete the default context"},400);await P(t,r,"contexts.context.delete","contexts","context","delete",s);let i=e.getContextResources(s);return await e.deleteContext(s),t.json({success:!0,message:`Context '${s}' deleted`,orphanedResources:i},200)}catch(s){let{message:i,status:o}=m(s,"Error deleting context");return t.json({error:i},o)}}async function Hr(t,e,r,s){try{let i=t.params.contextName;if(!i)return t.json({error:"contextName parameter is required"},400);await P(t,r,"contexts.context.delete-resources","contexts","context","delete-resources",i);let o=t.headers.authorization,n=o?.startsWith("Bearer ")?o.slice(7):o,a=s(n),c=e.getContextResources(i),l={success:!0,context:i,deleted:[],errors:[],summary:{totalResources:0,deletedCount:0,failedCount:0}};if(l.summary.totalResources=c.functions.length+c.databases.length+c.storage.length+c.sites.length+c.applications.length+c.users.length+c.serviceAccounts.length,a.functions){let u=await a.functions.list();for(let h of c.functions)try{let v=u.find(R=>R.id===h);v&&(await a.functions.delete(h),await e.unregisterResource(i,"function",h),l.deleted.push({type:"function",name:v.name}))}catch(v){l.errors.push({type:"function",name:h,error:v.message||"Unknown error"}),l.success=!1}}if(a.databases)for(let u of c.databases)try{await a.databases.deleteTable(u),await e.unregisterResource(i,"database",u),l.deleted.push({type:"database",name:u})}catch(h){l.errors.push({type:"database",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.storage)for(let u of c.storage)try{await a.storage.deleteBucket(u),await e.unregisterResource(i,"storage",u),l.deleted.push({type:"storage",name:u})}catch(h){l.errors.push({type:"storage",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.sites)for(let u of c.sites)try{await a.sites.deleteProject(u),await e.unregisterResource(i,"site",u),l.deleted.push({type:"site",name:u})}catch(h){l.errors.push({type:"site",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.applications){let u=await a.applications.list();for(let h of c.applications)try{let v=u.find(R=>R.id===h);v&&(await a.applications.delete(h),await e.unregisterResource(i,"application",h),l.deleted.push({type:"application",name:v.name}))}catch(v){l.errors.push({type:"application",name:h,error:v.message||"Unknown error"}),l.success=!1}}if(a.identity)for(let u of c.users)try{let h=await a.identity.getUser(u);h&&(await a.identity.deleteUser(h.id),await e.unregisterResource(i,"user",u),l.deleted.push({type:"user",name:u}))}catch(h){l.errors.push({type:"user",name:u,error:h.message||"Unknown error"}),l.success=!1}if(a.identity)for(let u of c.serviceAccounts)try{let h=await a.identity.getServiceAccount(u);h&&(await a.identity.deleteServiceAccount(h.id),await e.unregisterResource(i,"serviceAccount",u),l.deleted.push({type:"serviceAccount",name:u}))}catch(h){l.errors.push({type:"serviceAccount",name:u,error:h.message||"Unknown error"}),l.success=!1}l.summary.deletedCount=l.deleted.length,l.summary.failedCount=l.errors.length;let p=l.success?200:207;return t.json(l,p)}catch(i){let{message:o,status:n}=m(i,"Error deleting context resources");return t.json({error:o},n)}}async function Dr(t,e,r){try{await P(t,r,"iac.config.get","iac","config","get");let s=await w(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,n=e().validate(i);return t.json({success:!0,valid:n.valid,errors:n.errors,warnings:n.warnings},200)}catch(s){let{message:i,status:o}=m(s,"Error validating IaC");return t.json({error:i},o)}}async function Nr(t,e,r){try{await P(t,r,"iac.config.create","iac","config","create");let s=await w(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,o=t.headers.authorization,n=o?.startsWith("Bearer ")?o.slice(7):o,a=e(n),c=t.query?.prune==="true",l=await a.apply(i,{prune:c}),p=l.success?200:207;return t.json({success:l.success,context:l.context,created:l.created,updated:l.updated,unchanged:l.unchanged,deleted:l.deleted,errors:l.errors},p)}catch(s){let{message:i,status:o}=m(s,"Error applying IaC");return t.json({error:i},o)}}var G="default",qe=class{db;tableName="context_service";contexts;resourceMappings;constructor(e){this.db=e,this.contexts=[],this.resourceMappings=[]}async start(){await this.loadState()}async loadState(){try{let e=await this.db.get(this.tableName,"state");e&&(this.contexts=e.contexts||[],this.resourceMappings=e.resourceMappings||[])}catch{this.contexts=[],this.resourceMappings=[]}}async saveState(){await this.db.write(this.tableName,"state",{contexts:this.contexts,resourceMappings:this.resourceMappings})}async createContext(e){let r=e.name;if(this.contexts.find(o=>o.name===r))throw new z(`Context '${r}' already exists`);let s=new Date().toISOString(),i={name:r,intent:e.intent,attributes:e.attributes,createdAt:s,updatedAt:s};return this.contexts.push(i),await this.saveState(),i}getContext(e){let r=this.contexts.find(s=>s.name===e);if(!r)throw new F(`Context '${e}' not found`);return r}getContextWithResources(e){let r=this.getContext(e),s=this.getContextResources(e);return{...r,resources:s}}async updateContext(e,r){let s=this.contexts.findIndex(n=>n.name===e);if(s===-1)throw new F(`Context '${e}' not found`);let i=this.contexts[s],o={...i,intent:r.intent??i.intent,attributes:r.attributes??i.attributes,updatedAt:new Date().toISOString()};return this.contexts[s]=o,await this.saveState(),o}async deleteContext(e){let r=this.contexts.findIndex(s=>s.name===e);if(r===-1)throw new F(`Context '${e}' not found`);this.contexts.splice(r,1),this.resourceMappings=this.resourceMappings.filter(s=>s.context!==e),await this.saveState()}contextExists(e){return this.contexts.some(r=>r.name===e)}listContexts(){return[...this.contexts].sort((e,r)=>e.name.localeCompare(r.name))}async ensureContext(e){let r=e||G;return this.contextExists(r)||await this.createContext({name:r,intent:r===G?"Default context for resources without explicit context assignment.":void 0}),r}async registerResource(e,r,s){await this.ensureContext(e),this.resourceMappings.find(o=>o.context===e&&o.resourceType===r&&o.resourceName===s)||(this.resourceMappings.push({context:e,resourceType:r,resourceName:s,createdAt:new Date().toISOString()}),await this.saveState())}async unregisterResource(e,r,s){this.resourceMappings=this.resourceMappings.filter(i=>!(i.context===e&&i.resourceType===r&&i.resourceName===s)),await this.saveState()}getContextResources(e){let r=this.resourceMappings.filter(i=>i.context===e),s={functions:[],databases:[],storage:[],sites:[],users:[],serviceAccounts:[],applications:[]};for(let i of r)switch(i.resourceType){case"function":s.functions.push(i.resourceName);break;case"database":s.databases.push(i.resourceName);break;case"storage":s.storage.push(i.resourceName);break;case"site":s.sites.push(i.resourceName);break;case"user":s.users.push(i.resourceName);break;case"serviceAccount":s.serviceAccounts.push(i.resourceName);break;case"application":s.applications.push(i.resourceName);break}return s}getResourceContext(e,r){return this.resourceMappings.find(i=>i.resourceType===e&&i.resourceName===r)?.context||G}async moveResource(e,r,s,i){await this.unregisterResource(s,e,r),await this.registerResource(i,e,r)}listResourcesByType(e,r){return this.resourceMappings.filter(s=>s.context===e&&s.resourceType===r).map(s=>s.resourceName)}};async function Vr(t,e,r){try{await P(t,r,"iac.config.get","iac","config","get");let s=await w(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,o=t.headers.authorization,n=o?.startsWith("Bearer ")?o.slice(7):o,a=e(n),c=a.validate(i);if(!c.valid)return t.json({success:!1,valid:!1,errors:c.errors,warnings:c.warnings},400);let l=await a.diff(i);return t.json({success:!0,context:i.context?.name||G,toCreate:l.toCreate,toUpdate:l.toUpdate,toDelete:l.toDelete,unchanged:l.unchanged,warnings:c.warnings},200)}catch(s){let{message:i,status:o}=m(s,"Error generating IaC diff");return t.json({error:i},o)}}import{promises as Fe}from"node:fs";import{join as ct,resolve as Ai}from"node:path";var qr={$schema:"https://json-schema.org/draft-07/schema#",$id:"https://schemas.molnos.cloud/schema-config-v1.json",title:"MolnOS IaC Configuration",description:"Infrastructure-as-Code configuration file for MolnOS contexts",type:"object",properties:{$schema:{type:"string",description:"JSON Schema reference for editor support"},version:{type:"string",enum:["1"],description:"IaC schema version"},context:{type:"object",description:"Context definition (optional, defaults to 'default' context)",properties:{name:{type:"string",minLength:1,maxLength:64,pattern:"^[a-z][a-z0-9-]*$",description:"Context name (lowercase, alphanumeric with hyphens)"},intent:{type:"string",maxLength:1e3,description:"Human-readable description of what this context does"},attributes:{type:"object",description:"Freeform intent attributes for policy hints and visualization"}},required:["name"]},resources:{type:"object",description:"Resource declarations",properties:{functions:{type:"object",description:"Function deployments"},databases:{type:"object",description:"Database table declarations"},storage:{type:"object",description:"Storage bucket declarations"},sites:{type:"object",description:"Static site declarations"}}},identities:{type:"object",description:"Identity declarations",properties:{users:{type:"object",description:"User declarations"},serviceAccounts:{type:"object",description:"Service account declarations"}}}},required:["version"]};var Ii=new H(!0),Be=class{contextService;clients;constructor(e,r){this.contextService=e,this.clients=r}async loadConfiguration(e){let r=Ai(e);try{let s=await Fe.readFile(r,"utf-8");return JSON.parse(s)}catch(s){throw s.code==="ENOENT"?new x(`IaC file not found: ${e}`):s instanceof SyntaxError?new x(`Invalid JSON in IaC file: ${s.message}`):s}}validate(e){let r=[],s=[],i=Ii.test(qr,e);if(!i.success)for(let o of i.errors||[])r.push({path:o.key||"",message:o.error||"Validation error"});if(e.version!=="1"&&r.push({path:"version",message:`Unsupported IaC version: ${e.version}. Only version "1" is supported.`}),e.resources?.functions){for(let[o,n]of Object.entries(e.resources.functions))if(n.bindings)for(let a of n.bindings){let c=a.resource;c.includes(":")||(a.service==="databases"?e.resources?.databases?.[c]||s.push({path:`resources.functions.${o}.bindings`,message:`Database '${c}' is not declared in this configuration`}):a.service==="storage"&&(e.resources?.storage?.[c]||s.push({path:`resources.functions.${o}.bindings`,message:`Storage bucket '${c}' is not declared in this configuration`})))}}return{valid:r.length===0,errors:r,warnings:s}}async apply(e,r={}){let s=this.validate(e);if(!s.valid)return{success:!1,context:e.context?.name||G,created:[],updated:[],unchanged:[],deleted:[],errors:s.errors.map(n=>({type:"validation",name:n.path,error:n.message}))};let i=e.context?.name||G,o={success:!0,context:i,created:[],updated:[],unchanged:[],deleted:[],errors:[]};if(await this.contextService.ensureContext(i),e.context)try{await this.contextService.contextExists(i)&&await this.contextService.updateContext(i,{intent:e.context.intent,attributes:e.context.attributes})}catch{}if(e.resources?.databases&&this.clients.databases)for(let[n]of Object.entries(e.resources.databases))try{await this.clients.databases.tableExists(n)?o.unchanged.push({type:"database",name:n}):(await this.clients.databases.createTable(n),await this.contextService.registerResource(i,"database",n),o.created.push({type:"database",name:n}))}catch(a){o.errors.push({type:"database",name:n,error:a.message||"Unknown error"}),o.success=!1}if(e.resources?.storage&&this.clients.storage)for(let[n,a]of Object.entries(e.resources.storage))try{await this.clients.storage.bucketExists(n)?await this.clients.storage.isBucketPublic(n)!==(a.public||!1)?(await this.clients.storage.updateBucket(n,{public:a.public}),o.updated.push({type:"storage",name:n})):o.unchanged.push({type:"storage",name:n}):(await this.clients.storage.createBucket(n,a.public||!1),await this.contextService.registerResource(i,"storage",n),o.created.push({type:"storage",name:n}))}catch(c){o.errors.push({type:"storage",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.resources?.functions&&this.clients.functions)for(let[n,a]of Object.entries(e.resources.functions))try{let c;if(a.code)c=a.code;else if(a.source){let p=r.basePath?ct(r.basePath,a.source):a.source;try{c=await Fe.readFile(p,"utf-8")}catch{throw new Error(`Cannot read function source: ${a.source}`)}}else throw new Error('Function must have either "code" or "source" defined');let l=await this.clients.functions.get(n);if(l)await this.clients.functions.update(l.id,{code:c,methods:a.methods,bindings:a.bindings,allowUnauthenticated:a.allowUnauthenticated,passAllHeaders:a.passAllHeaders}),o.updated.push({type:"function",name:n});else{let p=await this.clients.functions.deploy(n,c,{id:a.id,methods:a.methods,bindings:a.bindings,allowUnauthenticated:a.allowUnauthenticated,passAllHeaders:a.passAllHeaders});await this.contextService.registerResource(i,"function",p.id),o.created.push({type:"function",name:n})}}catch(c){o.errors.push({type:"function",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.resources?.sites&&this.clients.sites)for(let[n,a]of Object.entries(e.resources.sites))try{let c;if(a.files&&a.files.length>0)c=a.files;else if(a.source){let p=r.basePath?ct(r.basePath,a.source):a.source;if(c=await this.loadSiteFiles(p),c.length===0)throw new Error(`No files found in site source: ${a.source}`)}else throw new Error('Site must have either "files" or "source" defined');let l=await this.clients.sites.getProject(n);await this.clients.sites.uploadProject(c,n),await this.contextService.registerResource(i,"site",n),l?o.updated.push({type:"site",name:n}):o.created.push({type:"site",name:n})}catch(c){o.errors.push({type:"site",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.identities?.users&&this.clients.identity)for(let[n,a]of Object.entries(e.identities.users))try{let c=await this.clients.identity.getUser(a.email);c?(await this.clients.identity.updateUser(c.id,{roles:a.roles}),o.updated.push({type:"user",name:a.email})):(await this.clients.identity.createUser(a.email,n,a.roles,{id:a.id}),await this.contextService.registerResource(i,"user",a.email),o.created.push({type:"user",name:a.email}))}catch(c){o.errors.push({type:"user",name:a.email,error:c.message||"Unknown error"}),o.success=!1}if(e.identities?.serviceAccounts&&this.clients.identity)for(let[n,a]of Object.entries(e.identities.serviceAccounts))try{let c=await this.clients.identity.getServiceAccount(n);c?(await this.clients.identity.updateServiceAccount(c.id,{roles:a.roles,description:a.description}),o.updated.push({type:"serviceAccount",name:n})):(await this.clients.identity.createServiceAccount(n,a.roles,a.description,{id:a.id}),await this.contextService.registerResource(i,"serviceAccount",n),o.created.push({type:"serviceAccount",name:n}))}catch(c){o.errors.push({type:"serviceAccount",name:n,error:c.message||"Unknown error"}),o.success=!1}if(e.resources?.applications&&this.clients.applications)for(let[n,a]of Object.entries(e.resources.applications))try{let c=await this.clients.applications.get(n);if(c)await this.clients.applications.update(c.id,{description:a.description,redirectUris:a.redirectUris}),o.updated.push({type:"application",name:n});else{let l=await this.clients.applications.create(n,a.description,a.redirectUris,{id:a.id});await this.contextService.registerResource(i,"application",l.id),o.created.push({type:"application",name:n})}}catch(c){o.errors.push({type:"application",name:n,error:c.message||"Unknown error"}),o.success=!1}if(r.prune){let n=await this.contextService.getContextResources(i);if(this.clients.functions){let a=Object.keys(e.resources?.functions||{}),c=await this.clients.functions.list();for(let l of n.functions){let p=c.find(u=>u.id===l);if(p&&!a.includes(p.name))try{await this.clients.functions.delete(l),await this.contextService.unregisterResource(i,"function",l),o.deleted.push({type:"function",name:p.name})}catch(u){o.errors.push({type:"function",name:p.name,error:`Failed to delete: ${u.message||"Unknown error"}`}),o.success=!1}}}if(this.clients.databases){let a=Object.keys(e.resources?.databases||{});for(let c of n.databases)if(!a.includes(c))try{await this.clients.databases.deleteTable(c),await this.contextService.unregisterResource(i,"database",c),o.deleted.push({type:"database",name:c})}catch(l){o.errors.push({type:"database",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.storage){let a=Object.keys(e.resources?.storage||{});for(let c of n.storage)if(!a.includes(c))try{await this.clients.storage.deleteBucket(c),await this.contextService.unregisterResource(i,"storage",c),o.deleted.push({type:"storage",name:c})}catch(l){o.errors.push({type:"storage",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.sites){let a=Object.keys(e.resources?.sites||{});for(let c of n.sites)if(!a.includes(c))try{await this.clients.sites.deleteProject(c),await this.contextService.unregisterResource(i,"site",c),o.deleted.push({type:"site",name:c})}catch(l){o.errors.push({type:"site",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.applications){let a=Object.keys(e.resources?.applications||{}),c=await this.clients.applications.list();for(let l of n.applications){let p=c.find(u=>u.id===l);if(p&&!a.includes(p.name))try{await this.clients.applications.delete(l),await this.contextService.unregisterResource(i,"application",l),o.deleted.push({type:"application",name:p.name})}catch(u){o.errors.push({type:"application",name:p.name,error:`Failed to delete: ${u.message||"Unknown error"}`}),o.success=!1}}}if(this.clients.identity){let a=Object.values(e.identities?.users||{}).map(c=>c.email);for(let c of n.users)if(!a.includes(c))try{let l=await this.clients.identity.getUser(c);l&&(await this.clients.identity.deleteUser(l.id),await this.contextService.unregisterResource(i,"user",c),o.deleted.push({type:"user",name:c}))}catch(l){o.errors.push({type:"user",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}if(this.clients.identity){let a=Object.keys(e.identities?.serviceAccounts||{});for(let c of n.serviceAccounts)if(!a.includes(c))try{let l=await this.clients.identity.getServiceAccount(c);l&&(await this.clients.identity.deleteServiceAccount(l.id),await this.contextService.unregisterResource(i,"serviceAccount",c),o.deleted.push({type:"serviceAccount",name:c}))}catch(l){o.errors.push({type:"serviceAccount",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),o.success=!1}}}return o}async loadSiteFiles(e,r=""){let s=[];try{let i=await Fe.readdir(e,{withFileTypes:!0});for(let o of i){let n=ct(e,o.name),a=r?`${r}/${o.name}`:o.name;if(o.isDirectory()){let c=await this.loadSiteFiles(n,a);s.push(...c)}else if(o.isFile()){let l=(await Fe.readFile(n)).toString("base64");s.push({path:a,content:l})}}}catch(i){if(i.code!=="ENOENT")throw i}return s}async diff(e){let r=e.context?.name||G,s=[],i=[],o=[],n=[],a=await this.contextService.getContextResources(r);if(this.clients.databases){let c=Object.keys(e.resources?.databases||{});for(let l of c)await this.clients.databases.tableExists(l)?n.push({type:"database",name:l}):s.push({type:"database",name:l});for(let l of a.databases)c.includes(l)||o.push({type:"database",name:l})}if(this.clients.storage){let c=Object.keys(e.resources?.storage||{});for(let l of c)if(await this.clients.storage.bucketExists(l)){let u=e.resources?.storage?.[l];await this.clients.storage.isBucketPublic(l)!==(u?.public||!1)?i.push({type:"storage",name:l}):n.push({type:"storage",name:l})}else s.push({type:"storage",name:l});for(let l of a.storage)c.includes(l)||o.push({type:"storage",name:l})}if(this.clients.functions){let c=Object.keys(e.resources?.functions||{});for(let l of c)await this.clients.functions.get(l)?i.push({type:"function",name:l}):s.push({type:"function",name:l});for(let l of a.functions)c.includes(l)||o.push({type:"function",name:l})}if(this.clients.sites){let c=Object.keys(e.resources?.sites||{});for(let l of c)await this.clients.sites.getProject(l)?i.push({type:"site",name:l}):s.push({type:"site",name:l});for(let l of a.sites)c.includes(l)||o.push({type:"site",name:l})}if(this.clients.applications){let c=Object.keys(e.resources?.applications||{});for(let l of c)await this.clients.applications.get(l)?i.push({type:"application",name:l}):s.push({type:"application",name:l});for(let l of a.applications)c.includes(l)||o.push({type:"application",name:l})}return{toCreate:s,toUpdate:i,toDelete:o,unchanged:n}}};var X=class{constructor(e,r){this.baseUrl=e;this.authToken=r}async request(e,r,s,i){let o=`${this.baseUrl}${r}`;if(i){let u=new URLSearchParams(i);o+=`?${u.toString()}`}let n={"Content-Type":"application/json"};this.authToken&&(n.Authorization=`Bearer ${this.authToken}`);let a={method:e,headers:n};s&&(a.body=JSON.stringify(s));let c=await fetch(o,a),l=c.headers.get("content-type"),p;if(l?.includes("application/json")?p=await c.json():p=await c.text(),!c.ok){let u=typeof p=="object"&&p.error?p.error:typeof p=="string"?p:JSON.stringify(p);throw new Error(u)}return p}},lt=class extends X{async createTable(e){await this.request("POST",`/tables/${e}`)}async tableExists(e){try{return((await this.request("GET","/tables")).tables||[]).some(i=>i.name===e)}catch{return!1}}async deleteTable(e){await this.request("DELETE",`/tables/${e}`)}async listTables(){return((await this.request("GET","/tables")).tables||[]).map(s=>s.name)}},ut=class extends X{async createBucket(e,r){await this.request("POST",`/buckets/${e}`,{public:r})}async bucketExists(e){try{return await this.request("GET",`/buckets/${e}`),!0}catch{return!1}}async updateBucket(e,r){await this.request("PATCH",`/buckets/${e}`,r)}async deleteBucket(e){await this.request("DELETE",`/buckets/${e}`)}async listBuckets(){return(await this.request("GET","/buckets")).buckets||[]}async isBucketPublic(e){try{return(await this.request("GET",`/buckets/${e}`)).public===!0}catch{return!1}}},dt=class extends X{async deploy(e,r,s){let i=await this.request("POST","/deploy",{name:e,code:r,id:s.id,methods:s.methods,bindings:s.bindings,allowUnauthenticated:s.allowUnauthenticated,passAllHeaders:s.passAllHeaders,env:s.env});return i.function||i}async get(e){try{return((await this.request("GET","/list")).functions||[]).find(i=>i.name===e)||null}catch{return null}}async update(e,r){let s=await this.request("PUT",`/${e}`,r);return s.function||s}async delete(e){await this.request("DELETE",`/${e}`)}async list(){return(await this.request("GET","/list")).functions||[]}},pt=class extends X{async uploadProject(e,r){return await this.request("POST","/projects",{files:e,projectId:r})}async getProject(e){try{return((await this.request("GET","/projects")).projects||[]).find(i=>i.projectId===e)||null}catch{return null}}async deleteProject(e){await this.request("DELETE",`/projects/${e}`)}async listProjects(){return(await this.request("GET","/projects")).projects||[]}},ht=class extends X{async createUser(e,r,s,i){let o=await this.request("POST","/identity/users",{email:e,name:r,roles:s,id:i?.id});return o.user||o}async getUser(e){try{return((await this.request("GET","/identity/users")).users||[]).find(i=>i.metadata?.email===e)||null}catch{return null}}async updateUser(e,r){let s=await this.request("PATCH",`/identity/users/${e}`,r);return s.user||s}async deleteUser(e){await this.request("DELETE",`/identity/users/${e}`)}async listUsers(){return(await this.request("GET","/identity/users")).users||[]}async createServiceAccount(e,r,s,i){let o=await this.request("POST","/identity/service-accounts",{name:e,roles:r,description:s,id:i?.id});return o.serviceAccount||o}async getServiceAccount(e){try{return((await this.request("GET","/identity/service-accounts")).serviceAccounts||[]).find(i=>i.name===e)||null}catch{return null}}async updateServiceAccount(e,r){let s=await this.request("PATCH",`/identity/service-accounts/${e}`,r);return s.serviceAccount||s}async deleteServiceAccount(e){await this.request("DELETE",`/identity/service-accounts/${e}`)}async listServiceAccounts(){return(await this.request("GET","/identity/service-accounts")).serviceAccounts||[]}},mt=class extends X{async create(e,r,s,i){return await this.request("POST","/applications",{name:e,description:r,redirectUris:s,id:i?.id})}async get(e){try{return((await this.request("GET","/applications")).applications||[]).find(i=>i.name===e)||null}catch{return null}}async update(e,r){return await this.request("PATCH",`/applications/${e}`,r)}async delete(e){await this.request("DELETE",`/applications/${e}`)}async list(){return(await this.request("GET","/applications")).applications||[]}};function ft(t){let{serviceUrls:e,authToken:r}=t,s={};return e.databases&&(s.databases=new lt(e.databases,r)),e.storage&&(s.storage=new ut(e.storage,r)),e.functions&&(s.functions=new dt(e.functions,r)),e.sites&&(s.sites=new pt(e.sites,r)),e.identity&&(s.identity=new ht(e.identity,r)),e.applications&&(s.applications=new mt(e.applications,r)),s}import{readFileSync as Ei,existsSync as Pi}from"node:fs";function Fr(){let t=process.env.MOLNOS_RUNTIME_CONFIG,e={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:"http://127.0.0.1:3000"},context:{apiUrl:"http://127.0.0.1:3000"},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(!t||!Pi(t))return e;try{let r=Ei(t,"utf-8");return JSON.parse(r)}catch(r){return console.error("[loadRuntimeConfig] Failed to load runtime config:",r),e}}async function Br(t,e,r,s){try{let i=t.headers["x-forwarded-for"],o=(Array.isArray(i)?i[0]:i)?.split(",")[0]?.trim()||t.headers["x-real-ip"]||"unknown";if(!r.checkRateLimit(`oauth:${o}`)){let p=r.getRateLimitInfo(`oauth:${o}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((p.reset-Date.now())/1e3)},429)}let n=Array.isArray(t.query.redirect_uri)?t.query.redirect_uri[0]:t.query.redirect_uri,a=Array.isArray(t.query.application_id)?t.query.application_id[0]:t.query.application_id,c=r.generateState(t,s,n,a),l=e.getAuthorizationUrl(c);return t.redirect(l,302)}catch(i){let{message:o,status:n}=m(i,"Error initiating OAuth flow");return t.json({error:o},n)}}async function _r(t,e,r,s,i,o){try{let n=t.headers["x-forwarded-for"],a=Array.isArray(n)?n[0]:n,c=t.headers["x-real-ip"],l=Array.isArray(c)?c[0]:c,p=a?.split(",")[0]?.trim()||l||"unknown";if(!r.checkRateLimit(`oauth:${p}`)){let R=r.getRateLimitInfo(`oauth:${p}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((R.reset-Date.now())/1e3)},429)}let u=r.validateCallback(t,o);if(!u.valid)return t.json({error:u.error||"Invalid OAuth callback"},400);let h=await e.handleCallback(u.code,p),v=await s.getUserByEmail(h.user.email);if(!v)return t.json({error:"User not found. You must be invited before signing in with OAuth."},403);if(await s.updateUser(v.id,{lastLogin:new Date().toISOString()}),u.redirectUrl){if(u.applicationId&&!await i.validateRedirectUri(u.applicationId,u.redirectUrl))return console.warn(`Redirect URL validation failed for applicationId: ${u.applicationId}`),t.json({success:!0,accessToken:h.accessToken,refreshToken:h.refreshToken,expiresIn:h.expiresIn,tokenType:h.tokenType,user:{id:v.id,email:h.user.email,name:h.user.name,username:h.user.username},warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);let R=new URL(u.redirectUrl);return R.searchParams.set("access_token",h.accessToken),R.searchParams.set("refresh_token",h.refreshToken),R.searchParams.set("expires_in",h.expiresIn.toString()),t.redirect(R.toString(),302)}return t.json({success:!0,accessToken:h.accessToken,refreshToken:h.refreshToken,expiresIn:h.expiresIn,tokenType:h.tokenType,user:{id:v.id,email:h.user.email,name:h.user.name,username:h.user.username}})}catch(n){let{message:a,status:c}=m(n,"OAuth authentication failed");return t.json({error:a},c)}}async function zr(t,e){try{let r=Array.from(e.values()).map(s=>s.getPublicInfo());return t.json({providers:r,count:r.length})}catch(r){let{message:s,status:i}=m(r,"Error listing OAuth providers");return t.json({error:s},i)}}var _e=class{constructor(e,r){this.config=e;this.mikroAuth=r}getAuthorizationUrl(e){let r=Array.isArray(this.config.scopes)?this.config.scopes.join(" "):this.config.scopes,s=new URLSearchParams({client_id:this.config.clientId,redirect_uri:this.config.redirectUri,response_type:"code",scope:r,state:e,...this.config.authorizationParams});return`${this.config.authorizationUrl}?${s}`}async exchangeCodeForTokens(e){let r=new URLSearchParams({client_id:this.config.clientId,client_secret:this.config.clientSecret,code:e,grant_type:"authorization_code",redirect_uri:this.config.redirectUri}),s=await fetch(this.config.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json",...this.config.tokenHeaders},body:r.toString()});if(!s.ok){let i=await s.text();throw new Error(`Token exchange failed: ${s.status} ${s.statusText} - ${i}`)}return s.json()}async fetchUserInfo(e){let r=await fetch(this.config.userInfoUrl,{headers:{Authorization:`Bearer ${e}`,Accept:"application/json",...this.config.userInfoHeaders}});if(!r.ok){let s=await r.text();throw new Error(`User info fetch failed: ${r.status} ${r.statusText} - ${s}`)}return r.json()}mapUserInfo(e){return this.config.userMapping?this.config.userMapping(e):{id:e.sub||e.id?.toString(),email:e.email,name:e.name||e.preferred_username,username:e.preferred_username||e.username||e.email?.split("@")[0]}}async handleCallback(e,r){let s=await this.exchangeCodeForTokens(e),i=await this.fetchUserInfo(s.access_token),o=this.mapUserInfo(i);if(!o.email)throw new Error("OAuth provider did not return user email");let n=await this.mikroAuth.createToken({email:o.email,username:o.username||o.name,role:"user",ip:r});return{accessToken:n.accessToken,refreshToken:n.refreshToken,expiresIn:n.exp,tokenType:n.tokenType,user:o}}getPublicInfo(){return{id:this.config.id,name:this.config.name,loginUrl:`/auth/oauth/${this.config.id}`}}};import Ti from"node:crypto";var ze=class{stateStore=new Map;rateLimitStore=new Map;stateExpiryMs;rateLimitMaxAttempts;rateLimitWindowMs;stateCleanupInterval;rateLimitCleanupInterval;constructor(e){this.stateExpiryMs=(e?.stateExpirySeconds||600)*1e3,this.rateLimitMaxAttempts=e?.rateLimiting?.maxAttempts||10,this.rateLimitWindowMs=e?.rateLimiting?.windowMs||900*1e3,this.startCleanupTasks()}generateState(e,r,s,i){let o=Ti.randomBytes(32).toString("hex"),n=this.getClientIp(e),a=e.headers["user-agent"]||"";return this.stateStore.set(o,{expires:Date.now()+this.stateExpiryMs,providerId:r,ip:n,userAgent:a,redirectUrl:s,applicationId:i}),o}validateState(e,r,s,i){let o=this.stateStore.get(e);return o?o.expires<Date.now()?(this.stateStore.delete(e),!1):o.providerId!==r||o.ip!==s||i&&o.userAgent&&o.userAgent!==i?!1:(this.stateStore.delete(e),!0):!1}checkRateLimit(e){let r=Date.now(),s=this.rateLimitStore.get(e);return!s||s.resetAt<r?(this.rateLimitStore.set(e,{count:1,resetAt:r+this.rateLimitWindowMs}),!0):s.count>=this.rateLimitMaxAttempts?!1:(s.count++,!0)}getRateLimitInfo(e){let r=this.rateLimitStore.get(e),s=Date.now();return!r||r.resetAt<s?{limit:this.rateLimitMaxAttempts,remaining:this.rateLimitMaxAttempts-1,reset:s+this.rateLimitWindowMs}:{limit:this.rateLimitMaxAttempts,remaining:Math.max(0,this.rateLimitMaxAttempts-r.count),reset:r.resetAt}}validateCallback(e,r){let s=Array.isArray(e.query.code)?e.query.code[0]:e.query.code,i=Array.isArray(e.query.state)?e.query.state[0]:e.query.state,o=Array.isArray(e.query.error)?e.query.error[0]:e.query.error,n=Array.isArray(e.query.error_description)?e.query.error_description[0]:e.query.error_description;if(o)return{valid:!1,error:`OAuth provider error: ${n||o}`};if(!s||!i)return{valid:!1,error:"Missing code or state parameter"};let a=this.stateStore.get(i),c=this.getClientIp(e),l=e.headers["user-agent"];return this.validateState(i,r,c,l)?{valid:!0,code:s,state:i,redirectUrl:a?.redirectUrl,applicationId:a?.applicationId}:{valid:!1,error:"Invalid or expired state token (CSRF protection failed)"}}getClientIp(e){let r=e.headers["x-forwarded-for"],s=Array.isArray(r)?r[0]:r,i=e.headers["x-real-ip"],o=Array.isArray(i)?i[0]:i;return s?.split(",")[0]?.trim()||o||"unknown"}startCleanupTasks(){this.stateCleanupInterval=setInterval(()=>{this.cleanupExpiredStates()},300*1e3),this.rateLimitCleanupInterval=setInterval(()=>{this.cleanupExpiredRateLimits()},600*1e3)}cleanupExpiredStates(){let e=Date.now(),r=0;for(let[s,i]of this.stateStore.entries())i.expires<e&&(this.stateStore.delete(s),r++);r>0&&console.log(`[OAuthSecurity] Cleaned up ${r} expired state tokens`)}cleanupExpiredRateLimits(){let e=Date.now(),r=0;for(let[s,i]of this.rateLimitStore.entries())i.resetAt<e&&(this.rateLimitStore.delete(s),r++);r>0&&console.log(`[OAuthSecurity] Cleaned up ${r} expired rate limit records`)}shutdown(){this.stateCleanupInterval&&clearInterval(this.stateCleanupInterval),this.rateLimitCleanupInterval&&clearInterval(this.rateLimitCleanupInterval)}getStats(){return{stateCount:this.stateStore.size,rateLimitCount:this.rateLimitStore.size}}};var Wr={google:{id:"google",name:"Google",authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",userInfoUrl:"https://www.googleapis.com/oauth2/v2/userinfo",scopes:"openid email profile",authorizationParams:{access_type:"offline",prompt:"consent"},userMapping:t=>({id:t.sub,email:t.email,name:t.name,username:t.email.split("@")[0]})},github:{id:"github",name:"GitHub",authorizationUrl:"https://github.com/login/oauth/authorize",tokenUrl:"https://github.com/login/oauth/access_token",userInfoUrl:"https://api.github.com/user",scopes:"user:email read:user",tokenHeaders:{Accept:"application/json"},userInfoHeaders:{Accept:"application/vnd.github.v3+json"},userMapping:t=>({id:t.id.toString(),email:t.email,name:t.name||t.login,username:t.login})},microsoft:{id:"microsoft",name:"Microsoft",authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",userInfoUrl:"https://graph.microsoft.com/v1.0/me",scopes:"openid email profile User.Read",userMapping:t=>({id:t.id,email:t.mail||t.userPrincipalName,name:t.displayName,username:t.userPrincipalName?.split("@")[0]})},gitlab:{id:"gitlab",name:"GitLab",authorizationUrl:"https://gitlab.com/oauth/authorize",tokenUrl:"https://gitlab.com/oauth/token",userInfoUrl:"https://gitlab.com/api/v4/user",scopes:"read_user email",userMapping:t=>({id:t.id.toString(),email:t.email,name:t.name,username:t.username})}};function Gr(t){let e=[];if(t.presets)for(let[r,s]of Object.entries(t.presets)){let i=Wr[r];if(!i){console.warn(`[OAuth] Unknown preset provider: ${r}`);continue}e.push({...i,clientId:s.clientId,clientSecret:s.clientSecret,redirectUri:s.redirectUri,scopes:s.scopes||i.scopes,authorizationParams:{...i.authorizationParams,...s.authorizationParams}})}return t.custom&&e.push(...t.custom),e}async function Kr(t,e){let r=await e(),s=r.headers||{};return s["X-Frame-Options"]="DENY",s["X-Content-Type-Options"]="nosniff",s["X-XSS-Protection"]="1; mode=block",s["Referrer-Policy"]="strict-origin-when-cross-origin",s["Content-Security-Policy"]="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",s["Permissions-Policy"]="geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()",process.env.NODE_ENV==="production"&&(s["Strict-Transport-Security"]="max-age=31536000; includeSubDomains"),{...r,headers:s}}async function gt(t,e){return process.env.NODE_ENV==="development"||process.env.NODE_ENV==="test"||(t.headers["x-forwarded-proto"]||t.headers["x-forwarded-protocol"])==="https"||t.req.url?.startsWith("https://")?e():t.json({error:"HTTPS required",message:"OAuth authentication requires HTTPS. Please use https:// instead of http://"},403)}function Jr(t,e,r){if(r.startsWith("/databases/")){r.includes("/table")||r.includes("/get")?g(t,"databases.table.get",{}):r.includes("/write")||r.includes("/update")||e==="PUT"||e==="PATCH"?g(t,"databases.table.update",{}):r.includes("/delete")||e==="DELETE"?g(t,"databases.table.delete",{}):e==="POST"&&g(t,"databases.table.create",{});return}if(r.startsWith("/functions/")){r.includes("/deploy")||e==="POST"?g(t,"functions.function.create",{}):r.includes("/run/")?g(t,"functions.function.execute",{}):e==="PUT"||e==="PATCH"?g(t,"functions.function.update",{}):e==="DELETE"?g(t,"functions.function.delete",{}):e==="GET"&&g(t,"functions.function.get",{});return}if(r.startsWith("/storage/")){let s=r.match(/^\/storage\/buckets\/[^/]+$/),i=r.includes("/objects");s?e==="POST"?g(t,"storage.bucket.create",{}):e==="PATCH"||e==="PUT"?g(t,"storage.bucket.update",{}):e==="DELETE"?g(t,"storage.bucket.delete",{}):e==="GET"&&g(t,"storage.bucket.get",{}):i||r.includes("/upload")||r.includes("/download")||r.includes("/get")?r.includes("/upload")||e==="POST"?g(t,"storage.object.create",{}):r.includes("/download")||r.includes("/get")?g(t,"storage.object.get",{}):e==="PUT"||e==="PATCH"?g(t,"storage.object.update",{}):e==="DELETE"?g(t,"storage.object.delete",{}):e==="GET"&&g(t,"storage.object.get",{}):e==="GET"&&g(t,"storage.bucket.get",{});return}if(r.startsWith("/sites/")){if(r.match(/^\/sites\/projects\/[^/]+/)&&e==="GET")return;r.includes("/deploy")||e==="POST"?g(t,"sites.site.create",{}):e==="PUT"||e==="PATCH"?g(t,"sites.site.update",{}):e==="DELETE"?g(t,"sites.site.delete",{}):e==="GET"&&g(t,"sites.site.get",{});return}if(r.startsWith("/observability/")){e==="POST"?g(t,"observability.metrics.create",{}):e==="GET"&&g(t,"observability.metrics.get",{});return}}var We=class{baseUrl;authToken;constructor(e,r){this.baseUrl=e.replace(/\/$/,""),this.authToken=r}async createCustomRole(e,r,s,i){let o=await fetch(`${this.baseUrl}/identity/roles`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({roleId:e,name:r,description:s,permissions:i})});if(!o.ok){let n=`Failed to create role: ${o.statusText}`;try{n=(await o.json()).error||n}catch{n=await o.text().catch(()=>o.statusText)||n}throw new Error(n)}}async updateRole(e,r){let s=await fetch(`${this.baseUrl}/identity/roles/${e}`,{method:"PATCH",headers:this.getHeaders(),body:JSON.stringify(r)});if(!s.ok){let i=await s.json();throw new Error(i.error||`Failed to update role: ${s.statusText}`)}}async deleteRole(e){let r=await fetch(`${this.baseUrl}/identity/roles/${e}`,{method:"DELETE",headers:this.getHeaders()});if(!r.ok){let s=await r.json();throw new Error(s.error||`Failed to delete role: ${r.statusText}`)}}async addServiceAccount(e,r,s){let i=await fetch(`${this.baseUrl}/identity/service-accounts`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({name:e,description:r,roles:s})});if(!i.ok){let n=`Failed to create service account: ${i.statusText}`;try{n=(await i.json()).error||n}catch{n=await i.text().catch(()=>i.statusText)||n}throw new Error(n)}let o=await i.json();return{id:o.id,apiKey:o.apiKey}}async deleteIdentity(e){let r=await fetch(`${this.baseUrl}/identity/service-accounts/${e}`,{method:"DELETE",headers:this.getHeaders()});if(!r.ok){let s=await r.json();throw new Error(s.error||`Failed to delete service account: ${r.statusText}`)}}async getUserFromToken(e){try{let r=await fetch(`${this.baseUrl}/identity/whoami`,{method:"GET",headers:{Authorization:`Bearer ${e}`}});return r.ok?await r.json():null}catch{return null}}getHeaders(){let e={"Content-Type":"application/json"};return this.authToken&&(e.Authorization=`Bearer ${this.authToken}`),e}};function Xr(t){return t?new We(t):null}function Yr(t){return t&&typeof t=="number"&&t>0?t*1024*1024:0}async function Zr(t){let{auth:e,db:r,config:s,molnos:i,oauth:o}=t,n=new Ne(e,r,i.initialUser);await n.start();let c=`${s.useHttps||s.useHttp2?"https":"http"}://${s.host||"127.0.0.1"}:${s.port||3e3}`,l=Xr(c),p,u;if(o){p=new ze(o),u=new Map;let d=Gr(o);for(let k of d){let b=new _e(k,e);u.set(k.id,b)}}let h=yt(i.dataPath,"applications"),v=new Ve({dbPath:h});await v.start();let R=yt(i.dataPath,"management"),S=new de({dbPath:R}),Ge=yt(i.dataPath,".runtime-config.json");S.setEnvironmentVariables({MOLNOS_RUNTIME_CONFIG:Ge});let D=i.cluster;S.setClusterConfig(D),await S.start();let Y;D?.mode==="core"&&D.workers&&(Y=new Ce,await Y.registerWorkers(D.workers));let $=new qe(r);await $.start();let O=Fr(),Z=d=>{let k=ft({serviceUrls:{databases:O.services.databases.url,storage:O.services.storage.url,functions:O.services.functions.url,sites:O.services.sites.url,identity:O.identity.apiUrl,applications:O.identity.apiUrl},authToken:d});return new Be($,k)},B=!1,f=new we({port:s.port||3e3,host:s.host||"127.0.0.1",allowedDomains:s.allowedDomains,maxBodySize:Yr(1e3),rateLimit:i.rateLimit?.global||{enabled:!1,requestsPerMinute:0}});f.use(async(d,k)=>B?d.text("Service Unavailable - Server is shutting down",503):k()),f.use(Kr),D?.mode==="worker"&&D.secret&&f.use(Se(D.secret)),f.get("/health",async d=>d.text("OK"));let A=async d=>d.text("Not Found",404);if(f.post("/auth/login",d=>zt(d,n,e,v)),f.get("/auth/verify",d=>Wt(d,e,v)),f.post("/auth/refresh",d=>Gt(d,e)),u&&p){f.get("/auth/oauth/providers",d=>zr(d,u));for(let[d,k]of u.entries())f.get(`/auth/oauth/${d}`,gt,b=>Br(b,k,p,d)),f.get(`/auth/oauth/${d}/callback`,gt,b=>_r(b,k,p,n,v,d))}f.post("/management/service",y,d=>vr(d,S)),f.get("/management/services",y,d=>fr(d,S)),f.get("/management/service/:serviceName",y,d=>gr(d,S)),f.put("/management/service/:serviceName",y,d=>Sr(d,S)),f.delete("/management/service/:serviceName",y,d=>br(d,S)),f.get("/management/service/:serviceName/start",y,d=>xr(d,S)),f.get("/management/service/:serviceName/stop",y,d=>Cr(d,S)),f.get("/management/service/:serviceName/logs",y,d=>kr(d,S)),f.get("/management/service/:serviceName/restart",y,d=>Ar(d,S)),f.get("/identity/whoami",y,d=>Kt(d)),f.get("/identity/identities",y,d=>Jt(d,n)),f.post("/identity/users",y,d=>Yt(d,n)),f.get("/identity/users",y,d=>Zt(d,n)),f.get("/identity/users/:userId",y,d=>Qt(d,n)),f.patch("/identity/users/:userId",y,d=>tr(d,n)),f.delete("/identity/users/:userId",y,d=>rr(d,n)),f.post("/identity/service-accounts",y,d=>sr(d,n)),f.get("/identity/service-accounts",y,d=>ir(d,n)),f.get("/identity/service-accounts/:serviceAccountId",y,d=>or(d,n)),f.patch("/identity/service-accounts/:serviceAccountId",y,d=>ar(d,n)),f.delete("/identity/service-accounts/:serviceAccountId",y,d=>cr(d,n)),f.post("/identity/service-accounts/:serviceAccountId/rotate-key",y,d=>lr(d,n)),f.post("/identity/roles",y,d=>pr(d,n)),f.get("/identity/roles",y,d=>ur(d,n)),f.get("/identity/roles/:roleId",y,d=>dr(d,n)),f.patch("/identity/roles/:roleId",y,d=>hr(d,n)),f.delete("/identity/roles/:roleId",y,d=>mr(d,n)),f.post("/applications",y,d=>Er(d,v,l)),f.get("/applications",y,d=>Tr(d,v,l)),f.get("/applications/:id",y,d=>Pr(d,v,l)),f.patch("/applications/:id",y,d=>Rr(d,v,l)),f.delete("/applications/:id",y,d=>jr(d,v,l)),f.get("/contexts",y,d=>$r(d,$,l)),f.post("/contexts",y,d=>Ur(d,$,l)),f.get("/contexts/:contextName",y,d=>Or(d,$,l)),f.patch("/contexts/:contextName",y,d=>Mr(d,$,l)),f.delete("/contexts/:contextName",y,d=>Lr(d,$,l)),f.delete("/contexts/:contextName/resources",y,d=>Hr(d,$,l,k=>ft({serviceUrls:{databases:O.services.databases.url,storage:O.services.storage.url,functions:O.services.functions.url,sites:O.services.sites.url,identity:O.identity.apiUrl,applications:O.identity.apiUrl},authToken:k}))),f.post("/iac/validate",y,d=>Dr(d,Z,l)),f.post("/iac/apply",y,d=>Nr(d,Z,l)),f.post("/iac/diff",y,d=>Vr(d,Z,l)),f.get("/databases/*",y,T,A),f.post("/databases/*",y,T,A),f.put("/databases/*",y,T,A),f.patch("/databases/*",y,T,A),f.delete("/databases/*",y,T,A);async function pe(d,k){if(d.path.match(/^\/functions\/run\//)){let M=d.headers.authorization;if(M)try{let j=await n.getUserFromToken(M);j&&(d.state.user=j,d.state.requestingIdentity=j)}catch{}return k()}return y(d,k)}f.get("/functions/*",pe,T,A),f.post("/functions/*",pe,T,A),f.put("/functions/*",pe,T,A),f.patch("/functions/*",pe,T,A),f.delete("/functions/*",pe,T,A),f.get("/sites/projects/:projectId/*",T,async d=>d.text("Not Found",404)),f.get("/sites/*",y,T,A),f.post("/sites/*",y,T,A),f.put("/sites/*",y,T,A),f.patch("/sites/*",y,T,A),f.delete("/sites/*",y,T,A);async function he(d,k){let b=d.req.method;if(d.path.match(/^\/storage\/buckets\/[^/]+\/objects\/.+/)&&(b==="GET"||b==="HEAD")){let j=d.headers.authorization;if(j)try{let K=await n.getUserFromToken(j);K&&(d.state.user=K,d.state.requestingIdentity=K)}catch{}return k()}return y(d,k)}f.get("/storage/*",he,T,A),f.post("/storage/*",he,T,A),f.put("/storage/*",he,T,A),f.patch("/storage/*",he,T,A),f.delete("/storage/*",he,T,A),f.get("/observability/*",y,T,A),f.post("/observability/*",y,T,A),f.put("/observability/*",y,T,A),f.patch("/observability/*",y,T,A),f.delete("/observability/*",y,T,A);function as(d,k,b,U){if(k!=="POST")return;let M=null,j=null;d==="/functions/deploy"&&U.function?.id?(M="function",j=U.function.id):d.match(/^\/databases\/tables\/[^/]+$/)&&U.name?(M="database",j=U.name):d.match(/^\/storage\/buckets\/[^/]+$/)&&U.bucket?(M="storage",j=U.bucket):d==="/sites/projects"&&U.projectId&&(M="site",j=U.projectId),M&&j&&$.registerResource(b,M,j).catch(K=>{console.error(`[Server] Failed to register ${M} '${j}' with context '${b}':`,K.message)})}async function T(d,k){try{let b=d.path,U=Object.keys(d.query).length>0?`?${new URLSearchParams(d.query).toString()}`:"",M=d.req.method||"",j,K=0,ls=await S.getServices();for(let L of ls)L.active&&b.startsWith(L.prefix)&&L.prefix.length>K&&(j=L,K=L.prefix.length);if(!j)return k();let St=d.state.user;if(!(b.match(/^\/sites\/projects\/[^/]+.*/)&&M==="GET")&&St&&Jr(St,M,b),j.healthCheck&&j.healthCheck.healthy===!1)return d.json({error:"Service unavailable (unhealthy)"},503);let bt=(b.substring(j.prefix.length)||"/")+U,N=null,Ke=null,Je=null;if(["POST","PUT","PATCH","DELETE"].includes(M)){let L=d.headers["content-type"]||"";if(L.includes("application/json"))try{let Q=await w(d);Je=Q,N=JSON.stringify(Q)}catch{N=null}else if(L.includes("multipart/form-data"))try{N=JSON.stringify(d.body),Ke="application/json"}catch{N=null}else try{N=Buffer.isBuffer(d.body)?d.body:Buffer.from(d.body)}catch{N=null}}let Ae=j.name,xt=D?.mode==="core"?D.workers?.[Ae]:void 0;if(xt&&Y){if(!Y.isHealthy(Ae))return d.json({error:`Worker for ${Ae} is unavailable`},503);try{let L=await ot(xt,bt,M,N,d.headers,D?.secret);return nt(d,L)}catch(L){return console.error(`[Server] Worker proxy error for ${Ae}:`,L.message),d.json({error:L.message},L.statusCode||503)}}return new Promise(L=>{let Q={...d.headers,host:`127.0.0.1:${j.port}`};Ke&&(Q["content-type"]=Ke),N&&(typeof N=="string"?Q["content-length"]=Buffer.byteLength(N).toString():Q["content-length"]=N.length.toString());let us={method:M,hostname:"127.0.0.1",port:j.port,path:bt,headers:Q},me=Ri.request(us,q=>{let Ct=[];q.on("data",ae=>{Ct.push(ae)}),q.on("end",()=>{let ae=Buffer.concat(Ct),Xe={};Object.entries(q.headers).forEach(([ge,J])=>{J!==void 0&&(Xe[ge]=Array.isArray(J)?J.join(", "):J)});let fe=q.headers["content-type"]||"",_;if(fe.includes("application/json"))try{let ge=JSON.parse(ae.toString("utf-8")),J=q.statusCode||200;ge.success&&J>=200&&J<300&&Je?.context&&as(b,M,Je.context,ge),_=d.json(ge,J)}catch{_=d.text(ae.toString("utf-8"),q.statusCode||200)}else fe.startsWith("text/")||fe.includes("javascript")||fe.includes("xml")?_=d.text(ae.toString("utf-8"),q.statusCode||200):(_=d.binary(ae,fe||"application/octet-stream"),q.statusCode&&q.statusCode!==200&&(_.statusCode=q.statusCode));_.headers?_.headers={..._.headers,...Xe}:_.headers=Xe,L(_)})});me.on("error",q=>{L(d.json({error:"Proxy Error",message:q.message},502))}),me.on("timeout",()=>{me.destroy(),L(d.json({error:"Gateway Timeout"},504))}),N&&me.write(N),me.end()})}catch(b){return vt(d,b)}}async function y(d,k){try{let b=d.headers.authorization;if(!b)return d.text("Unauthorized",401);let U=await n.getUserFromToken(b);return U?(d.state.user=U,d.state.requestingIdentity=U,k()):d.text("Unauthorized",401)}catch(b){return vt(d,b)}}function vt(d,k){let b=k.message||k,U=k?.cause?.statusCode||400;return d.json({error:b},U)}let wt=f.start();async function cs(){B||(B=!0,await new Promise((d,k)=>{wt.close(b=>{b?k(b):d()})}),console.log("[Server] Stopping managed services..."),await S.shutdown(),p&&p.shutdown(),await r.close())}return{server:wt,shutdown:cs,processManager:S,identityService:n}}import ji from"node:http";import{join as $i}from"node:path";async function Qr(t){let{config:e,dataPath:r,cluster:s}=t,i=new we({...e});if(s.secret){let l=Se(s.secret);i.use(l)}let o=new de({dbPath:$i(r,"molnosdb")});await o.start();let n=s.capabilities||[];console.log(`[Worker] Starting capabilities: ${n.join(", ")}`);for(let l of n)await o.startService(l);let a=async l=>{let p=l.path,u=Object.keys(l.query).length>0?`?${new URLSearchParams(l.query).toString()}`:"",h=l.req.method||"GET",R=(await o.getServices()).find($=>p.startsWith(`/${$.name}`)&&$.active);if(!R)return l.json({error:"Service not found"},404);let Ge=(p.substring(`/${R.name}`.length)||"/")+u,D=null;["POST","PUT","PATCH","DELETE"].includes(h)&&(l.headers["content-type"]||"").includes("application/json")&&l.body&&(D=JSON.stringify(l.body));let Y={};for(let[$,O]of Object.entries(l.headers))$.toLowerCase()!==oe&&O&&(Y[$]=typeof O=="string"?O:O[0]);return new Promise($=>{let O={method:h,hostname:"127.0.0.1",port:R.port,path:Ge,headers:Y},Z=ji.request(O,B=>{let f="";B.on("data",A=>{f+=A}),B.on("end",()=>{if((B.headers["content-type"]||"").includes("application/json"))try{$(l.json(JSON.parse(f),B.statusCode||200))}catch{$(l.text(f,B.statusCode||200))}else $(l.text(f,B.statusCode||200))})});Z.on("error",()=>{$(l.json({error:"Service unavailable"},503))}),D&&Z.write(D),Z.end()})};i.get("/health",l=>l.json({status:"ok",mode:"worker"})),i.post("/management/service/:serviceName/start",async l=>{let p=l.params?.serviceName;if(!p)return l.json({error:"Service name required"},400);if(!n.includes(p))return l.json({error:`This worker does not handle capability: ${p}`},400);let u=await o.startService(p);return l.json({serviceName:p,isStarted:u})}),i.post("/management/service/:serviceName/stop",async l=>{let p=l.params?.serviceName;if(!p)return l.json({error:"Service name required"},400);if(!n.includes(p))return l.json({error:`This worker does not handle capability: ${p}`},400);let u=await o.stopService(p);return l.json({serviceName:p,isStopped:u})}),i.post("/management/service/:serviceName/restart",async l=>{let p=l.params?.serviceName;if(!p)return l.json({error:"Service name required"},400);if(!n.includes(p))return l.json({error:`This worker does not handle capability: ${p}`},400);let u=await o.restartService(p);return l.json({serviceName:p,isRestarted:u})});for(let l of n)i.get(`/${l}/*`,a),i.post(`/${l}/*`,a),i.put(`/${l}/*`,a),i.patch(`/${l}/*`,a),i.delete(`/${l}/*`,a),i.options(`/${l}/*`,a);i.get("/*",l=>l.json({error:"Not found",mode:"worker"},404)),await i.start();let c=e.useHttps?"https":"http";return console.log(`[Worker] Server running at ${c}://${e.host||"localhost"}:${e.port}`),{shutdown:async()=>{await o.shutdown()}}}var ts=()=>{let t=es(process.env.DEBUG)||!1,e=es(process.env.RATE_LIMIT_ENABLED||!1);return{auth:{jwtSecret:process.env.AUTH_JWT_SECRET||"your-jwt-secret",magicLinkExpirySeconds:900,jwtExpirySeconds:900,refreshTokenExpirySeconds:10080*60,maxActiveSessions:3,consoleUrl:process.env.CONSOLE_URL||"http://localhost:8000",debug:t},email:{emailSubject:"Sign In To MolnOS",user:process.env.EMAIL_USER||"",host:process.env.EMAIL_HOST||"",password:process.env.EMAIL_PASSWORD||"",port:465,secure:!0,maxRetries:2,debug:t},storage:{databaseDirectory:"molnosdb",encryptionKey:process.env.STORAGE_KEY||"",debug:t},server:{port:Number(process.env.PORT)||3e3,host:process.env.HOST||"127.0.0.1",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",allowedDomains:["http://localhost:8000"],debug:t},molnos:{dataPath:process.env.DATA_PATH||"data",initialUser:{id:process.env.INITIAL_USER_ID||ke(),userName:process.env.INITIAL_USER_NAME||"",email:process.env.INITIAL_USER_EMAIL||""},rateLimit:{global:{enabled:e,requestsPerMinute:Number(process.env.RATE_LIMIT_RPS)||0}},signedUrlSecret:process.env.SIGNED_URL_SECRET||"molnos-default-signed-url-secret"}}};function es(t){return t==="true"||t===!0}var C=ts(),rs={configFilePath:"molnos.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:C.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:C.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:C.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:C.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:C.auth.maxActiveSessions},{flag:"--consoleUrl",path:"auth.consoleUrl",defaultValue:C.auth.consoleUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:C.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:C.email.host},{flag:"--emailUser",path:"email.user",defaultValue:C.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:C.email.password},{flag:"--emailPort",path:"email.port",defaultValue:C.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:C.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:C.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:C.email.debug},{flag:"--db",path:"storage.databaseDirectory",defaultValue:C.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:C.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:C.storage.debug},{flag:"--port",path:"server.port",defaultValue:C.server.port},{flag:"--host",path:"server.host",defaultValue:C.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:C.server.useHttps},{flag:"--http2",path:"server.useHttp2",isFlag:!0,defaultValue:C.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:C.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:C.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:C.server.sslCa},{flag:"--allowed",path:"server.allowedDomains",defaultValue:C.server.allowedDomains,parser:te.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:C.server.debug},{flag:"--data-path",path:"dataPath",defaultValue:C.molnos.dataPath},{flag:"--initialUserId",path:"molnos.initialUser.id",defaultValue:C.molnos.initialUser.id},{flag:"--initialUserName",path:"molnos.initialUser.userName",defaultValue:C.molnos.initialUser.userName},{flag:"--initialUserEmail",path:"molnos.initialUser.email",defaultValue:C.molnos.initialUser.email}]};function ss(t){return{...t,auth:{...t.auth,templates:{textVersion:(e,r,s)=>{let i=new URL(e),o=i.searchParams.get("token")||"",n=i.searchParams.get("email")||"",a=s?.appName||"MolnOS",c=s?.redirectUrl&&s?.applicationId,l=c?`Sign in to ${a}`:"Sign in to MolnOS",p=c?`You're signing in to ${a}. Click the link below to complete the authentication process.`:"Click the link below to sign in to your account.";return`
115
115
  ${l}
116
116
 
117
117
  ${p}
@@ -147,5 +147,5 @@ ${u}
147
147
  </div>
148
148
  </body>
149
149
  </html>
150
- `}}}}}function ss(t){let e=[],r=i=>e.push(i);return t?.molnos?.cluster?.mode==="worker"||(t?.email?.host||r("Missing email.host value"),t?.email?.user||r("Missing email.user value"),t?.email?.password||r("Missing email.password value"),t?.molnos?.initialUser?.email||r("Missing molnos.initialUser.email value")),{success:e.length===0,errors:e}}import{writeFileSync as $i,mkdirSync as Oi,existsSync as Mi}from"node:fs";import{join as Ui}from"node:path";function is(t){let e=t.molnos.dataPath||"data";Mi(e)||Oi(e,{recursive:!0});let r=Ui(e,".runtime-config.json"),s=t.server.host||"127.0.0.1",i=t.molnos.services||{},o={storage:3001,functions:3002,sites:3003,databases:3004,observability:3005},n=l=>{let p=i[l]||{},u=p.host||s,h=p.port||o[l],v=p.secure?"https":"http";return{host:u,port:h,url:`${v}://${u}:${h}`}},a={storage:n("storage"),functions:n("functions"),sites:n("sites"),databases:n("databases"),observability:n("observability")},c={molnos:{dataPath:t.molnos.dataPath,rateLimit:t.molnos.rateLimit,signedUrlSecret:t.molnos.signedUrlSecret,cluster:t.molnos.cluster},server:{host:t.server.host,port:t.server.port},identity:{apiUrl:`${t.server.useHttps?"https":"http"}://${s}:${t.server.port}`},context:{apiUrl:`${t.server.useHttps?"https":"http"}://${s}:${t.server.port}`},services:a,storage:t.storage};return $i(r,JSON.stringify(c,null,2),"utf-8"),r}async function Hi(){let t=Di(),e=rs(t),r=ss(e);if(!r.success)throw console.error(`Found configuration validation errors: ${JSON.stringify(r.errors)}`),new Re("Invalid configuration provided. Please see the validation errors and fix these and then retry again.");is(e);let s=e.molnos.dataPath||"data",i=e.molnos?.cluster;if(i?.mode==="worker"){let u=await Zr({config:e.server,dataPath:s,cluster:i});os(u);return}let o=new ie({databaseDirectory:Li(s,"molnosdb")});await o.start();let n=new Rt(o),a=new jt(e.email),c={...e,auth:{...e.auth,appUrl:e.auth.consoleUrl}},l=new Tt(c,a,n),p=await Yr({config:e.server,molnos:e.molnos,auth:l,db:o,oauth:e.oauth});os(p)}function os(t){let e=async r=>{console.log(`
151
- [MolnOS] Received ${r}, initiating graceful shutdown...`);try{await t.shutdown(),console.log("[MolnOS] Shutdown complete"),process.exit(0)}catch(s){console.error("[MolnOS] Error during shutdown:",s),process.exit(1)}};process.on("SIGINT",()=>e("SIGINT")),process.on("SIGTERM",()=>e("SIGTERM")),process.on("SIGHUP",()=>e("SIGHUP")),process.on("uncaughtException",async r=>{console.error("[MolnOS] Uncaught exception:",r);try{await t.shutdown()}catch{}process.exit(1)}),process.on("unhandledRejection",async(r,s)=>{console.error("[MolnOS] Unhandled rejection at:",s,"reason:",r);try{await t.shutdown()}catch{}process.exit(1)})}function Di(){return new ee(ts).get()}Hi();export{Hi as start};
150
+ `}}}}}function is(t){let e=[],r=i=>e.push(i);return t?.molnos?.cluster?.mode==="worker"||(t?.email?.host||r("Missing email.host value"),t?.email?.user||r("Missing email.user value"),t?.email?.password||r("Missing email.password value"),t?.molnos?.initialUser?.email||r("Missing molnos.initialUser.email value")),{success:e.length===0,errors:e}}import{writeFileSync as Oi,mkdirSync as Ui,existsSync as Mi}from"node:fs";import{join as Li}from"node:path";function os(t){let e=t.molnos.dataPath||"data";Mi(e)||Ui(e,{recursive:!0});let r=Li(e,".runtime-config.json"),s=t.server.host||"127.0.0.1",i=t.molnos.services||{},o={storage:3001,functions:3002,sites:3003,databases:3004,observability:3005},n=l=>{let p=i[l]||{},u=p.host||s,h=p.port||o[l],v=p.secure?"https":"http";return{host:u,port:h,url:`${v}://${u}:${h}`}},a={storage:n("storage"),functions:n("functions"),sites:n("sites"),databases:n("databases"),observability:n("observability")},c={molnos:{dataPath:t.molnos.dataPath,rateLimit:t.molnos.rateLimit,signedUrlSecret:t.molnos.signedUrlSecret,cluster:t.molnos.cluster},server:{host:t.server.host,port:t.server.port},identity:{apiUrl:`${t.server.useHttps?"https":"http"}://${s}:${t.server.port}`},context:{apiUrl:`${t.server.useHttps?"https":"http"}://${s}:${t.server.port}`},services:a,storage:t.storage};return Oi(r,JSON.stringify(c,null,2),"utf-8"),r}async function Di(){let t=Ni(),e=ss(t),r=is(e);if(!r.success)throw console.error(`Found configuration validation errors: ${JSON.stringify(r.errors)}`),new Re("Invalid configuration provided. Please see the validation errors and fix these and then retry again.");os(e);let s=e.molnos.dataPath||"data",i=e.molnos?.cluster;if(i?.mode==="worker"){let u=await Qr({config:e.server,dataPath:s,cluster:i});ns(u);return}let o=new ie({databaseDirectory:Hi(s,"molnosdb")});await o.start();let n=new jt(o),a=new $t(e.email),c={...e,auth:{...e.auth,appUrl:e.auth.consoleUrl}},l=new Rt(c,a,n),p=await Zr({config:e.server,molnos:e.molnos,auth:l,db:o,oauth:e.oauth});ns(p)}function ns(t){let e=async r=>{console.log(`
151
+ [MolnOS] Received ${r}, initiating graceful shutdown...`);try{await t.shutdown(),console.log("[MolnOS] Shutdown complete"),process.exit(0)}catch(s){console.error("[MolnOS] Error during shutdown:",s),process.exit(1)}};process.on("SIGINT",()=>e("SIGINT")),process.on("SIGTERM",()=>e("SIGTERM")),process.on("SIGHUP",()=>e("SIGHUP")),process.on("uncaughtException",async r=>{console.error("[MolnOS] Uncaught exception:",r);try{await t.shutdown()}catch{}process.exit(1)}),process.on("unhandledRejection",async(r,s)=>{console.error("[MolnOS] Unhandled rejection at:",s,"reason:",r);try{await t.shutdown()}catch{}process.exit(1)})}function Ni(){return new ee(rs).get()}Di();export{Di as start};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "molnos",
3
3
  "description": "The core API for MolnOS.",
4
- "version": "1.2.1",
4
+ "version": "1.2.2",
5
5
  "author": "MolnOS",
6
6
  "license": "COMMERCIAL",
7
7
  "keywords": [],
package/sbom.json CHANGED
@@ -1 +1 @@
1
- {"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"package-lock.json","documentNamespace":"https://anchore.com/syft/file/package-lock.json-262cb528-e322-40dd-b920-3e42bb640e03","creationInfo":{"licenseListVersion":"3.27","creators":["Organization: Anchore, Inc","Tool: syft-1.40.1"],"created":"2026-01-25T14:58:23Z"},"packages":[{"name":"mikroauth","SPDXID":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","versionInfo":"1.1.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroauth/-/mikroauth-1.1.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroauth:mikroauth:1.1.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroauth@1.1.0"}]},{"name":"mikroconf","SPDXID":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroconf/-/mikroconf-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroconf:mikroconf:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroconf@1.0.0"}]},{"name":"mikroevent","SPDXID":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","versionInfo":"1.0.1","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroevent/-/mikroevent-1.0.1.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroevent:mikroevent:1.0.1:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroevent@1.0.1"}]},{"name":"mikroid","SPDXID":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroid/-/mikroid-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroid:mikroid:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroid@1.0.0"}]},{"name":"mikromail","SPDXID":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikromail/-/mikromail-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikromail:mikromail:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikromail@1.0.0"}]},{"name":"mikropermit","SPDXID":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikropermit/-/mikropermit-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikropermit:mikropermit:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikropermit@1.0.0"}]},{"name":"mikroserve","SPDXID":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","versionInfo":"1.1.1","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroserve/-/mikroserve-1.1.1.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroserve:mikroserve:1.1.1:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroserve@1.1.1"}]},{"name":"mikrovalid","SPDXID":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","versionInfo":"1.0.23","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikrovalid/-/mikrovalid-1.0.23.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikrovalid:mikrovalid:1.0.23:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikrovalid@1.0.23"}]},{"name":"molnos","SPDXID":"SPDXRef-Package-npm-molnos-caff56904b83171b","versionInfo":"1.2.1","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"LicenseRef-COMMERCIAL","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:molnos:molnos:1.2.1:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/molnos@1.2.1"}]},{"name":"pikodb","SPDXID":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","versionInfo":"1.0.1","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/pikodb/-/pikodb-1.0.1.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:pikodb:pikodb:1.0.1:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/pikodb@1.0.1"}]},{"name":"package-lock.json","SPDXID":"SPDXRef-DocumentRoot-File-package-lock.json","versionInfo":"sha256:d634a3773c4f40a1ccdc2c6167118eb5c5bdf79d349b578733162298e1619dab","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"checksums":[{"algorithm":"SHA256","checksumValue":"d634a3773c4f40a1ccdc2c6167118eb5c5bdf79d349b578733162298e1619dab"}],"licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","copyrightText":"NOASSERTION","primaryPackagePurpose":"FILE"}],"files":[{"fileName":"package-lock.json","SPDXID":"SPDXRef-File-package-lock.json-fd71c2238fc07657","fileTypes":["APPLICATION"],"checksums":[{"algorithm":"SHA1","checksumValue":"bf04b2b59828a3aa323899689872a055c7e53fd5"},{"algorithm":"SHA256","checksumValue":"d634a3773c4f40a1ccdc2c6167118eb5c5bdf79d349b578733162298e1619dab"}],"licenseConcluded":"NOASSERTION","licenseInfoInFiles":["NOASSERTION"],"copyrightText":"NOASSERTION"}],"hasExtractedLicensingInfos":[{"licenseId":"LicenseRef-COMMERCIAL","extractedText":"NOASSERTION","name":"COMMERCIAL"}],"relationships":[{"spdxElementId":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-molnos-caff56904b83171b","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-molnos-caff56904b83171b","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-File-package-lock.json","relationshipType":"DESCRIBES"}]}
1
+ {"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"package-lock.json","documentNamespace":"https://anchore.com/syft/file/package-lock.json-329a805e-d349-47cb-9fc5-932336f7aa03","creationInfo":{"licenseListVersion":"3.27","creators":["Organization: Anchore, Inc","Tool: syft-1.40.1"],"created":"2026-01-25T18:24:58Z"},"packages":[{"name":"mikroauth","SPDXID":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","versionInfo":"1.1.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroauth/-/mikroauth-1.1.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroauth:mikroauth:1.1.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroauth@1.1.0"}]},{"name":"mikroconf","SPDXID":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroconf/-/mikroconf-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroconf:mikroconf:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroconf@1.0.0"}]},{"name":"mikroevent","SPDXID":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","versionInfo":"1.0.1","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroevent/-/mikroevent-1.0.1.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroevent:mikroevent:1.0.1:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroevent@1.0.1"}]},{"name":"mikroid","SPDXID":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroid/-/mikroid-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroid:mikroid:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroid@1.0.0"}]},{"name":"mikromail","SPDXID":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikromail/-/mikromail-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikromail:mikromail:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikromail@1.0.0"}]},{"name":"mikropermit","SPDXID":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","versionInfo":"1.0.0","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikropermit/-/mikropermit-1.0.0.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikropermit:mikropermit:1.0.0:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikropermit@1.0.0"}]},{"name":"mikroserve","SPDXID":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","versionInfo":"1.1.1","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikroserve/-/mikroserve-1.1.1.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikroserve:mikroserve:1.1.1:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikroserve@1.1.1"}]},{"name":"mikrovalid","SPDXID":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","versionInfo":"1.0.23","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/mikrovalid/-/mikrovalid-1.0.23.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:mikrovalid:mikrovalid:1.0.23:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/mikrovalid@1.0.23"}]},{"name":"molnos","SPDXID":"SPDXRef-Package-npm-molnos-b3f06707af219f60","versionInfo":"1.2.2","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"LicenseRef-COMMERCIAL","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:molnos:molnos:1.2.2:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/molnos@1.2.2"}]},{"name":"pikodb","SPDXID":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","versionInfo":"1.0.1","supplier":"NOASSERTION","downloadLocation":"https://registry.npmjs.org/pikodb/-/pikodb-1.0.1.tgz","filesAnalyzed":false,"sourceInfo":"acquired package info from installed node module manifest file: /package-lock.json","licenseConcluded":"NOASSERTION","licenseDeclared":"MIT","copyrightText":"NOASSERTION","externalRefs":[{"referenceCategory":"SECURITY","referenceType":"cpe23Type","referenceLocator":"cpe:2.3:a:pikodb:pikodb:1.0.1:*:*:*:*:*:*:*"},{"referenceCategory":"PACKAGE-MANAGER","referenceType":"purl","referenceLocator":"pkg:npm/pikodb@1.0.1"}]},{"name":"package-lock.json","SPDXID":"SPDXRef-DocumentRoot-File-package-lock.json","versionInfo":"sha256:824c2430e597b10507a5a4cb858a660490fa82da7291e3c0b6f98b94b03bb827","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"checksums":[{"algorithm":"SHA256","checksumValue":"824c2430e597b10507a5a4cb858a660490fa82da7291e3c0b6f98b94b03bb827"}],"licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","copyrightText":"NOASSERTION","primaryPackagePurpose":"FILE"}],"files":[{"fileName":"package-lock.json","SPDXID":"SPDXRef-File-package-lock.json-fd71c2238fc07657","fileTypes":["APPLICATION"],"checksums":[{"algorithm":"SHA1","checksumValue":"32fb3ea53b3ab2cf684611a4f2cd8e9473e93337"},{"algorithm":"SHA256","checksumValue":"824c2430e597b10507a5a4cb858a660490fa82da7291e3c0b6f98b94b03bb827"}],"licenseConcluded":"NOASSERTION","licenseInfoInFiles":["NOASSERTION"],"copyrightText":"NOASSERTION"}],"hasExtractedLicensingInfos":[{"licenseId":"LicenseRef-COMMERCIAL","extractedText":"NOASSERTION","name":"COMMERCIAL"}],"relationships":[{"spdxElementId":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"DEPENDENCY_OF"},{"spdxElementId":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relatedSpdxElement":"SPDXRef-File-package-lock.json-fd71c2238fc07657","relationshipType":"OTHER","comment":"evident-by: indicates the package's existence is evident by the given file"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroauth-7520a9fae77ac01a","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroconf-b297d975cb09169c","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroevent-5bd10e41dccc0f47","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroid-505e62805cb5678f","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikromail-2f017138ed7f39a9","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikropermit-0f36ec54f335a15e","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikroserve-1c5cbf0685852d2c","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-mikrovalid-2873df526a8a0901","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-molnos-b3f06707af219f60","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DocumentRoot-File-package-lock.json","relatedSpdxElement":"SPDXRef-Package-npm-pikodb-2e1e5824d502124f","relationshipType":"CONTAINS"},{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-File-package-lock.json","relationshipType":"DESCRIBES"}]}