molnos 1.3.0 → 1.4.1

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.
@@ -1,14 +1,14 @@
1
1
  // MolnOS Core - See LICENSE file for copyright and license details.
2
- import ie,{createHash as mn,createHmac as hn,scryptSync as Vs,randomBytes as Gs,createCipheriv as zs,createDecipheriv as Ws}from"crypto";import{URL as Js}from"url";var lt=class extends Error{constructor(t){super(t),this.name="ValidationError",this.message=t||"Validation did not pass",this.cause={statusCode:400}}};import{existsSync as Ls,readFileSync as Hs}from"node:fs";var re=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&&Ls(t))try{let a=Hs(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 lt(t.message);if(typeof r=="string")throw new lt(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 ae,{createHash as Eo,createHmac as To,scryptSync as ti,randomBytes as ri,createCipheriv as si,createDecipheriv as ii}from"crypto";import{URL as ni}from"url";var ht=class extends Error{constructor(t){super(t),this.name="ValidationError",this.message=t||"Validation did not pass",this.cause={statusCode:400}}};import{existsSync as Ws,readFileSync as Js}from"node:fs";var ne=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 o=0;o<s.length-1;o++){let a=s[o];!(a in i)||i[a]===null?i[a]={}:typeof i[a]!="object"&&(i[a]={}),i=i[a]}let n=s[s.length-1];i[n]=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&&Ws(t))try{let a=Js(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 n=this.parseCliArgs(e),o=this.deepMerge({},s);return o=this.deepMerge(o,i),o=this.deepMerge(o,r),o=this.deepMerge(o,n),o}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(n=>n.flag===s);if(i)if(i.isFlag)this.setValueAtPath(e,i.path,!0);else if(r<t.length&&!t[r].startsWith("-")){let n=t[r++];if(i.parser)try{n=i.parser(n)}catch(o){console.error(`Error parsing value for ${i.flag}: ${o instanceof Error?o.message:String(o)}`);continue}if(i.validator){let o=i.validator(n);if(o!==!0&&typeof o=="string"){console.error(`Invalid value for ${i.flag}: ${o}`);continue}if(o===!1){console.error(`Invalid value for ${i.flag}`);continue}}this.setValueAtPath(e,i.path,n)}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 ht(t.message);if(typeof r=="string")throw new ht(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 se={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 Lt=class extends Error{constructor(t){super(),this.name="ValidationError",this.message=t,this.cause={statusCode:400}}};import{existsSync as Ds,readFileSync as Ns}from"fs";var Ht=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(Ds(t))try{let n=Ns(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 Lt("Host value not found")}get(){return this.validate(),this.config}};import{promises as Fs}from"dns";function Ce(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 _s(t){try{let e=await Fs.resolveMx(t);return!!e&&e.length>0}catch{return!1}}async function Dt(t){try{let e=t.split("@")[1];return e?await _s(e):!1}catch{return!1}}import{Buffer as Ie}from"buffer";import ut from"crypto";import qs from"net";import Bs from"os";import Nt from"tls";var Ft=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??Bs.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=Nt.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=qs.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=Nt.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
- `);if(l.length>0&&l[l.length-1]===""){let d=l[l.length-2]||"",u=/^(\d{3})(.?)/.exec(d);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
8
+ `;return t}};var oe={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 oi}from"events";var _t=class extends Error{constructor(t){super(),this.name="ValidationError",this.message=t,this.cause={statusCode:400}}};import{existsSync as Ks,readFileSync as Xs}from"fs";var Bt=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(Ks(t))try{let o=Xs(t,"utf8");i=JSON.parse(o),console.log(`Loaded configuration from ${t}`)}catch(o){console.error(`Error reading config file: ${o instanceof Error?o.message:String(o)}`)}let n=this.parseCliArgs(e);return{...s,...r,...i,...n}}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 _t("Host value not found")}get(){return this.validate(),this.config}};import{promises as Ys}from"dns";function Ie(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 Zs(t){try{let e=await Ys.resolveMx(t);return!!e&&e.length>0}catch{return!1}}async function Vt(t){try{let e=t.split("@")[1];return e?await Zs(e):!1}catch{return!1}}import{Buffer as Ae}from"buffer";import ft from"crypto";import Qs from"net";import ei from"os";import Gt from"tls";var zt=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??ei.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=Gt.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=Qs.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=Gt.connect(s);i.once("error",n=>{this.log(`TLS upgrade error: ${n.message}`,!0),e(new Error(`STARTTLS error: ${n.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 n=setTimeout(()=>{this.socket?.removeListener("data",a),i(new Error(`Command timeout after ${r}ms: ${t}`))},r),o="",a=c=>{o+=c.toString();let l=o.split(`\r
9
+ `);if(l.length>0&&l[l.length-1]===""){let u=l[l.length-2]||"",p=/^(\d{3})(.?)/.exec(u);p?.[1]&&p[2]!=="-"&&(this.socket?.removeListener("data",a),clearTimeout(n),this.log(`SMTP Response: ${o.trim()}`),p[1]===e.toString()?s(o.trim()):i(new Error(`SMTP Error: ${o.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
- `);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=Ie.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(Ie.from(this.config.user).toString("base64"),334),await this.sendCommand(Ie.from(this.config.password).toString("base64"),235)}async authenticateCramMD5(){let t=await this.sendCommand("AUTH CRAM-MD5",334),e=Ie.from(t.substr(4),"base64").toString("utf8"),r=ut.createHmac("md5",this.config.password);r.update(e);let s=r.digest("hex"),i=`${this.config.user} ${s}`,o=Ie.from(i).toString("base64");await this.sendCommand(o,235)}generateMessageId(){let t=ut.randomBytes(16).toString("hex"),e=this.config.user.split("@")[1]||"localhost";return`<${t}@${e}>`}generateBoundary(){return`----=_NextPart_${ut.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
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=Ae.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(Ae.from(this.config.user).toString("base64"),334),await this.sendCommand(Ae.from(this.config.password).toString("base64"),235)}async authenticateCramMD5(){let t=await this.sendCommand("AUTH CRAM-MD5",334),e=Ae.from(t.substr(4),"base64").toString("utf8"),r=ft.createHmac("md5",this.config.password);r.update(e);let s=r.digest("hex"),i=`${this.config.user} ${s}`,n=Ae.from(i).toString("base64");await this.sendCommand(n,235)}generateMessageId(){let t=ft.randomBytes(16).toString("hex"),e=this.config.user.split("@")[1]||"localhost";return`<${t}@${e}>`}generateBoundary(){return`----=_NextPart_${ft.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,n=[`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 o=Array.isArray(t.cc)?t.cc.join(", "):t.cc;n.push(`Cc: ${this.sanitizeHeader(o)}`)}if(t.replyTo&&n.push(`Reply-To: ${this.sanitizeHeader(t.replyTo)}`),t.headers)for(let[o,a]of Object.entries(t.headers))/^[a-zA-Z0-9-]+$/.test(o)&&(/^(from|to|cc|bcc|subject|date|message-id)$/i.test(o)||n.push(`${o}: ${this.sanitizeHeader(a)}`));return n}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
12
12
  `)}\r
13
13
  \r
14
14
  --${i}\r
@@ -28,8 +28,8 @@ ${r||""}\r
28
28
  ${r}`:`${s.join(`\r
29
29
  `)}\r
30
30
  \r
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(!Ce(e))return{success:!1,error:"Invalid email address format"};for(let a of n)if(!Ce(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(d=>setTimeout(d,this.config.retryDelay))),this.connected||(await this.connect(),await this.smtpHandshake()),await this.sendCommand(`MAIL FROM:<${e}>`,250);for(let d of n)await this.sendCommand(`RCPT TO:<${d}>`,250);if(t.cc){let d=Array.isArray(t.cc)?t.cc:[t.cc];for(let u of d)Ce(u)&&await this.sendCommand(`RCPT TO:<${u}>`,250)}if(t.bcc){let d=Array.isArray(t.bcc)?t.bcc:[t.bcc];for(let u of d)Ce(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 dt=class{smtpClient;config;constructor(t){let e=new Ht(t).get(),r=new Ft(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 Dt(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 pt=()=>{let t=Xs(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 Xs(t){return t==="true"||t===!0}var Ys=class{algorithm="HS256";secret="HS256";constructor(t){if(process.env.NODE_ENV==="production"&&(!t||t.length<32||t===pt().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=ie.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()}},Zs=class{templates;constructor(t){t?this.templates=t:this.templates=Qs}getText(t,e,r){return this.templates.textVersion(t,e,r).trim()}getHtml(t,e,r){return this.templates.htmlVersion(t,e,r).trim()}},Qs={textVersion:(t,e,r)=>`
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||"",n=t.html||"";if(!e||!r||!s||!i&&!n)return{success:!1,error:"Missing required email parameters (from, to, subject, and either text or html)"};let o=Array.isArray(t.to)?t.to:[t.to];if(this.config.skipEmailValidation)this.log("Email validation skipped (testing mode)");else{if(!Ie(e))return{success:!1,error:"Invalid email address format"};for(let a of o)if(!Ie(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(u=>setTimeout(u,this.config.retryDelay))),this.connected||(await this.connect(),await this.smtpHandshake()),await this.sendCommand(`MAIL FROM:<${e}>`,250);for(let u of o)await this.sendCommand(`RCPT TO:<${u}>`,250);if(t.cc){let u=Array.isArray(t.cc)?t.cc:[t.cc];for(let p of u)Ie(p)&&await this.sendCommand(`RCPT TO:<${p}>`,250)}if(t.bcc){let u=Array.isArray(t.bcc)?t.bcc:[t.bcc];for(let p of u)Ie(p)&&await this.sendCommand(`RCPT TO:<${p}>`,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 gt=class{smtpClient;config;constructor(t){let e=new Bt(t).get(),r=new zt(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 Vt(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 yt=()=>{let t=ai(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 ai(t){return t==="true"||t===!0}var ci=class{algorithm="HS256";secret="HS256";constructor(t){if(process.env.NODE_ENV==="production"&&(!t||t.length<32||t===yt().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 n=this.base64UrlEncode(JSON.stringify(r)),o=this.base64UrlEncode(JSON.stringify(i)),a=`${n}.${o}`,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("."),n=`${s}.${i}`;if(this.createSignature(n)!==r.signature)throw new Error("Invalid signature");let o=r.payload,a=Math.floor(Date.now()/1e3),c=e.clockTolerance||0;if(o.exp!==void 0&&o.exp+c<a)throw new Error("Token expired");if(o.nbf!==void 0&&o.nbf-c>a)throw new Error("Token not yet valid");if(e.issuer&&o.iss!==e.issuer)throw new Error("Invalid issuer");if(e.audience&&o.aud!==e.audience)throw new Error("Invalid audience");if(e.subject&&o.sub!==e.subject)throw new Error("Invalid subject");return o}decode(t){let e=t.split(".");if(e.length!==3)throw new Error("Invalid token format");try{let[r,s,i]=e,n=JSON.parse(this.base64UrlDecode(r)),o=JSON.parse(this.base64UrlDecode(s));return{header:n,payload:o,signature:i}}catch{throw new Error("Failed to decode token")}}createSignature(t){let e=ae.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()}},li=class{templates;constructor(t){t?this.templates=t:this.templates=ui}getText(t,e,r){return this.templates.textVersion(t,e,r).trim()}getHtml(t,e,r){return this.templates.htmlVersion(t,e,r).trim()}},ui={textVersion:(t,e,r)=>`
33
33
  Click this link to login: ${t}
34
34
 
35
35
  Security Information:
@@ -108,20 +108,20 @@ If you didn't request this link, please ignore this email.
108
108
  </div>
109
109
  </body>
110
110
  </html>
111
- `},ei=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=[]}},ti=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 _t(t){if(!t||t.trim()===""||(t.match(/@/g)||[]).length!==1)return!1;let[e,r]=t.split("@");return!(!e||!r||t.includes("..")||!ri(e)||!si(r))}function ri(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 si(t){if(t.startsWith("[")&&t.endsWith("]")){let r=t.slice(1,-1);return r.startsWith("IPv6:")?oi(r.slice(5)):ii(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 ii(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 oi(t){if(!/^[a-fA-F0-9:]+$/.test(t))return!1;let e=t.split(":");return!(e.length<2||e.length>8)}var k=pt(),ni=t=>{let e={configFilePath:"mikroauth.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:k.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:k.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:k.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:k.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:k.auth.maxActiveSessions},{flag:"--appUrl",path:"auth.appUrl",defaultValue:k.auth.appUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:k.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:k.email.host},{flag:"--emailUser",path:"email.user",defaultValue:k.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:k.email.password},{flag:"--emailPort",path:"email.port",defaultValue:k.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:k.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:k.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:k.email.debug},{flag:"--dir",path:"storage.databaseDirectory",defaultValue:k.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:k.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:k.storage.debug},{flag:"--port",path:"server.port",defaultValue:k.server.port},{flag:"--host",path:"server.host",defaultValue:k.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:k.server.useHttps},{flag:"--https",path:"server.useHttp2",isFlag:!0,defaultValue:k.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:k.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:k.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:k.server.sslCa},{flag:"--ratelimit",path:"server.rateLimit.enabled",defaultValue:k.server.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"server.rateLimit.requestsPerMinute",defaultValue:k.server.rateLimit.requestsPerMinute},{flag:"--allowed",path:"server.allowedDomains",defaultValue:k.server.allowedDomains,parser:se.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:k.server.debug}]};return t&&(e.config=t),e},Oe={linkSent:"If a matching account was found, a magic link has been sent.",revokedSuccess:"All other sessions revoked successfully.",logoutSuccess:"Logged out successfully."},qt=class{config;email;storage;jwtService;templates;constructor(t,e,r){let s=new re(ni({auth:t.auth,email:t.email})).get();s.auth.debug&&console.log("Using configuration:",s),this.config=s,this.email=e||new ei,this.storage=r||new ti,this.jwtService=new Ys(s.auth.jwtSecret),this.templates=new Zs(s?.auth.templates),this.checkIfUsingDefaultCredentialsInProduction()}checkIfUsingDefaultCredentialsInProduction(){process.env.NODE_ENV==="production"&&this.config.auth.jwtSecret===pt().auth.jwtSecret&&(console.error("WARNING: Using default secrets in production environment!"),process.exit(1))}generateToken(t){let e=Date.now().toString(),r=ie.randomBytes(32).toString("hex");return ie.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 ie.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 Js(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(!_t(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 m of l){if(m===a)continue;let v=await this.storage.get(m);if(v)try{JSON.parse(v).email===e&&await this.storage.delete(m)}catch{}}let d=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(d,u,s),html:this.templates.getHtml(d,u,s)}),{message:Oe.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(!_t(e))throw new Error("Valid email required");try{let o=ie.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}),d={email:e,username:r,role:s,ipAddress:i||"unknown",tokenId:o,createdAt:a,lastLogin:a};return await this.trackSession(e,n,d),{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=ie.randomBytes(16).toString("hex"),l=this.generateRefreshToken(),d={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(d,{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=ie.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:Oe.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:Oe.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:Oe.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)}}},ai=class{key;algorithm="aes-256-gcm";keyLength=32;constructor(t){this.key=Vs(t,"mikroauth-salt",this.keyLength)}encrypt(t){let e=Gs(12),r=zs(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=Ws(this.algorithm,this.key,o);return c.setAuthTag(n),Buffer.concat([c.update(a),c.final()]).toString("utf8")}},Bt=class{db;encryption;PREFIX_KV="kv:";PREFIX_COLLECTION="coll:";TABLE_NAME="mikroauth";constructor(t,e){this.db=t,e&&(this.encryption=new ai(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)):[]}},Vt=class{email;sender;constructor(t){this.sender=t.user,this.email=new dt({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 Me(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:Gt(t.deflate)}:{deflate:Gt(t.inflate),inflate:t.inflate}}function Gt(t){let e={};for(let[r,s]of Object.entries(t))e[s]=r;return e}function pe(t,e){if(t==null||typeof t!="object")return t;if(Array.isArray(t))return t.map(s=>pe(s,e));let r={};for(let[s,i]of Object.entries(t)){let o=e[s]||s;r[o]=pe(i,e)}return r}function oe(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 Ue(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 zt(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 mt,mkdirSync as ci,readdirSync as li,openSync as ui,closeSync as di}from"fs";import{readFile as pi,writeFile as mi,rename as hi,unlink as Wt,open as fi}from"fs/promises";import{join as ht,dirname as gi}from"path";var ne=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=Me(r);this.dictionaries.set(e,s)}),mt(this.databaseDirectory)||ci(this.databaseDirectory,{recursive:!0})}async start(){try{let t=li(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(oe(t),Ue(e),zt(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){oe(t),e!==void 0&&Ue(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){oe(t),Ue(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){oe(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){oe(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){oe(t);try{this.data.delete(t);let e=ht(this.databaseDirectory,t);return mt(e)&&await Wt(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=Me(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=ht(this.databaseDirectory,t);if(!mt(e)){this.data.set(t,new Map);return}try{let r=await pi(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=ht(this.databaseDirectory,t),i=`${s}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await mi(i,r),this.useFsync){let o=await fi(i,"r+");try{await o.sync()}finally{await o.close()}}if(await hi(i,s),this.useFsync){let o=gi(s),n=ui(o,"r");try{di(n)}catch{}}}catch(o){try{await Wt(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?pe(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?pe(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 wo}from"node:path";import po from"node:http";import{join as Tt}from"node:path";var Jt=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 yi}from"url";var Kt=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 yi(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,m)=>{c[m]=u});let l={req:t,res:e,params:a,query:c,body:t.body||{},headers:t.headers,path:i,state:{},raw:()=>e,binary:(u,m="application/octet-stream",v=200)=>({statusCode:v,body:u,headers:{"Content-Type":m,"Content-Length":u.length.toString()},isRaw:!0}),text:(u,m=200)=>({statusCode:m,body:u,headers:{"Content-Type":"text/plain"}}),form:(u,m=200)=>({statusCode:m,body:u,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),json:(u,m=200)=>({statusCode:m,body:u,headers:{"Content-Type":"application/json"}}),html:(u,m=200)=>({statusCode:m,body:u,headers:{"Content-Type":"text/html"}}),redirect:(u,m=302)=>({statusCode:m,body:null,headers:{Location:u}}),status:function(u){return{raw:()=>e,binary:(m,v="application/octet-stream")=>({statusCode:u,body:m,headers:{"Content-Type":v,"Content-Length":m.length.toString()},isRaw:!0}),text:m=>({statusCode:u,body:m,headers:{"Content-Type":"text/plain"}}),json:m=>({statusCode:u,body:m,headers:{"Content-Type":"application/json"}}),html:m=>({statusCode:u,body:m,headers:{"Content-Type":"text/html"}}),form:m=>({statusCode:u,body:m,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),redirect:(m,v=302)=>({statusCode:v,body:null,headers:{Location:m}}),status:m=>this.status(m)}}},d=[...this.globalMiddlewares,...n.middlewares];return this.executeMiddlewareChain(l,d,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 Le=()=>({port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",debug:vi(process.env.DEBUG)||!1,maxBodySize:1048576,requestTimeout:3e4,rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"]});function vi(t){return t==="true"||t===!0}var q=Le(),Xt=t=>({configFilePath:"mikroserve.config.json",args:process.argv,options:[{flag:"--port",path:"port",defaultValue:q.port},{flag:"--host",path:"host",defaultValue:q.host},{flag:"--https",path:"useHttps",defaultValue:q.useHttps,isFlag:!0},{flag:"--http2",path:"useHttp2",defaultValue:q.useHttp2,isFlag:!0},{flag:"--cert",path:"sslCert",defaultValue:q.sslCert},{flag:"--key",path:"sslKey",defaultValue:q.sslKey},{flag:"--ca",path:"sslCa",defaultValue:q.sslCa},{flag:"--ratelimit",path:"rateLimit.enabled",defaultValue:q.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"rateLimit.requestsPerMinute",defaultValue:q.rateLimit.requestsPerMinute},{flag:"--allowed",path:"allowedDomains",defaultValue:q.allowedDomains,parser:se.array},{flag:"--debug",path:"debug",defaultValue:q.debug,isFlag:!0},{flag:"--max-body-size",path:"maxBodySize",defaultValue:q.maxBodySize},{flag:"--request-timeout",path:"requestTimeout",defaultValue:q.requestTimeout}],config:t});function Yt(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=wi(t,i);for(let l of c){if(l.length===0||l.equals(o.subarray(i.length)))continue;let d=Si(l);if(!d)continue;let{name:u,filename:m,contentType:v,data:x}=d;if(m){let H={filename:m,contentType:v||"application/octet-stream",data:x,size:x.length};a[u]?Array.isArray(a[u])?a[u].push(H):a[u]=[a[u],H]:a[u]=H}else{let H=x.toString("utf8");n[u]?Array.isArray(n[u])?n[u].push(H):n[u]=[n[u],H]:n[u]=H}}return{fields:n,files:a}}function wi(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 Si(t){let e=Buffer.from(`\r
111
+ `},di=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=[]}},pi=class{data=new Map;collections=new Map;expiryEmitter=new oi;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(n=>r.test(n)),i=Array.from(this.collections.keys()).filter(n=>r.test(n));return[...new Set([...s,...i])]}};function Wt(t){if(!t||t.trim()===""||(t.match(/@/g)||[]).length!==1)return!1;let[e,r]=t.split("@");return!(!e||!r||t.includes("..")||!mi(e)||!hi(r))}function mi(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 hi(t){if(t.startsWith("[")&&t.endsWith("]")){let r=t.slice(1,-1);return r.startsWith("IPv6:")?gi(r.slice(5)):fi(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 fi(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 gi(t){if(!/^[a-fA-F0-9:]+$/.test(t))return!1;let e=t.split(":");return!(e.length<2||e.length>8)}var k=yt(),yi=t=>{let e={configFilePath:"mikroauth.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:k.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:k.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:k.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:k.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:k.auth.maxActiveSessions},{flag:"--appUrl",path:"auth.appUrl",defaultValue:k.auth.appUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:k.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:k.email.host},{flag:"--emailUser",path:"email.user",defaultValue:k.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:k.email.password},{flag:"--emailPort",path:"email.port",defaultValue:k.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:k.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:k.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:k.email.debug},{flag:"--dir",path:"storage.databaseDirectory",defaultValue:k.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:k.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:k.storage.debug},{flag:"--port",path:"server.port",defaultValue:k.server.port},{flag:"--host",path:"server.host",defaultValue:k.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:k.server.useHttps},{flag:"--https",path:"server.useHttp2",isFlag:!0,defaultValue:k.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:k.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:k.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:k.server.sslCa},{flag:"--ratelimit",path:"server.rateLimit.enabled",defaultValue:k.server.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"server.rateLimit.requestsPerMinute",defaultValue:k.server.rateLimit.requestsPerMinute},{flag:"--allowed",path:"server.allowedDomains",defaultValue:k.server.allowedDomains,parser:oe.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:k.server.debug}]};return t&&(e.config=t),e},Ue={linkSent:"If a matching account was found, a magic link has been sent.",revokedSuccess:"All other sessions revoked successfully.",logoutSuccess:"Logged out successfully."},Jt=class{config;email;storage;jwtService;templates;constructor(t,e,r){let s=new ne(yi({auth:t.auth,email:t.email})).get();s.auth.debug&&console.log("Using configuration:",s),this.config=s,this.email=e||new di,this.storage=r||new pi,this.jwtService=new ci(s.auth.jwtSecret),this.templates=new li(s?.auth.templates),this.checkIfUsingDefaultCredentialsInProduction()}checkIfUsingDefaultCredentialsInProduction(){process.env.NODE_ENV==="production"&&this.config.auth.jwtSecret===yt().auth.jwtSecret&&(console.error("WARNING: Using default secrets in production environment!"),process.exit(1))}generateToken(t){let e=Date.now().toString(),r=ae.randomBytes(32).toString("hex");return ae.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 ae.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 ni(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:n}=t;if(!Wt(e))throw new Error("Valid email required");try{let o=this.generateToken(e),a=`magic_link:${o}`,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 m of l){if(m===a)continue;let w=await this.storage.get(m);if(w)try{JSON.parse(w).email===e&&await this.storage.delete(m)}catch{}}let u=this.generateMagicLinkUrl({token:o,email:e,appUrl:i}),p=Math.ceil(this.config.auth.magicLinkExpirySeconds/60);return await this.email.sendMail({from:this.config.email.user,to:e,subject:n||this.config.email.emailSubject,text:this.templates.getText(u,p,s),html:this.templates.getHtml(u,p,s)}),{message:Ue.linkSent}}catch(o){throw console.error(`Failed to process magic link request: ${o}`),new Error("Failed to process magic link request")}}async createToken(t){let{email:e,username:r,role:s,ip:i}=t;if(!Wt(e))throw new Error("Valid email required");try{let n=ae.randomBytes(16).toString("hex"),o=this.generateRefreshToken(),a=Date.now(),c={sub:e,username:r,role:s,jti:n,lastLogin:a,metadata:{ip:i||"unknown"},exp:Math.floor(Date.now()/1e3)+3600*24},l=this.jwtService.sign(c,{exp:this.config.auth.jwtExpirySeconds}),u={email:e,username:r,role:s,ipAddress:i||"unknown",tokenId:n,createdAt:a,lastLogin:a};return await this.trackSession(e,o,u),{accessToken:l,refreshToken:o,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(n){throw console.error("Token creation error:",n),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 n=JSON.parse(i);if(n.email!==r)throw new Error("Email mismatch");let o=n.username,a=n.role;await this.storage.delete(s);let c=ae.randomBytes(16).toString("hex"),l=this.generateRefreshToken(),u={sub:r,username:o,role:a,jti:c,lastLogin:n.createdAt,metadata:{ip:n.ipAddress},exp:Math.floor(Date.now()/1e3)+3600*24},p=this.jwtService.sign(u,{exp:this.config.auth.jwtExpirySeconds});return await this.trackSession(r,l,{...n,tokenId:c,createdAt:Date.now()}),{accessToken:p,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,n=r.role,o=ae.randomBytes(16).toString("hex"),a={sub:s,username:i,role:n,jti:o,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:Ue.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:Ue.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 o=>{try{let a=await this.storage.get(`refresh:${o}`);if(!a)return await this.storage.removeFromCollection(s,o),null;let c=JSON.parse(a);return{id:`${o.substring(0,8)}...`,createdAt:c.createdAt||0,lastLogin:c.lastLogin||c.createdAt||0,lastUsed:c.lastUsed||c.createdAt||0,metadata:{ip:c.ipAddress},isCurrentSession:o===r}}catch{return await this.storage.removeFromCollection(s,o),null}}),n=(await Promise.all(i)).filter(Boolean);return n.sort((o,a)=>a.createdAt-o.createdAt),{sessions:n}}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 n of i)r&&n===r||await this.storage.delete(`refresh:${n}`);return await this.storage.delete(s),r&&await this.storage.get(`refresh:${r}`)&&await this.storage.addToCollection(s,r,this.config.auth.refreshTokenExpirySeconds),{message:Ue.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)}}},vi=class{key;algorithm="aes-256-gcm";keyLength=32;constructor(t){this.key=ti(t,"mikroauth-salt",this.keyLength)}encrypt(t){let e=ri(12),r=si(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,n=Buffer.from(r,"hex"),o=Buffer.from(s,"hex"),a=Buffer.from(i,"hex"),c=ii(this.algorithm,this.key,n);return c.setAuthTag(o),Buffer.concat([c.update(a),c.final()]).toString("utf8")}},Kt=class{db;encryption;PREFIX_KV="kv:";PREFIX_COLLECTION="coll:";TABLE_NAME="mikroauth";constructor(t,e){this.db=t,e&&(this.encryption=new vi(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,n=r?Date.now()+r*1e3:void 0;await this.db.write(this.TABLE_NAME,s,i,n)}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),n=[];if(i){let l=this.encryption?this.encryption.decrypt(i):i;n=JSON.parse(l)}n.includes(e)||n.push(e);let o=JSON.stringify(n),a=this.encryption?this.encryption.encrypt(o):o,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,n=JSON.parse(i);n=n.filter(c=>c!==e);let o=JSON.stringify(n),a=this.encryption?this.encryption.encrypt(o):o;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 n=i.shift(),o=JSON.stringify(i),a=this.encryption?this.encryption.encrypt(o):o;return await this.db.write(this.TABLE_NAME,e,a),n}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 n=i[0];return typeof n=="string"&&n.startsWith(this.PREFIX_KV)}).map(i=>i[0].substring(this.PREFIX_KV.length)).filter(i=>r.test(i)):[]}},Xt=class{email;sender;constructor(t){this.sender=t.user,this.email=new gt({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 He(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:Yt(t.deflate)}:{deflate:Yt(t.inflate),inflate:t.inflate}}function Yt(t){let e={};for(let[r,s]of Object.entries(t))e[s]=r;return e}function me(t,e){if(t==null||typeof t!="object")return t;if(Array.isArray(t))return t.map(s=>me(s,e));let r={};for(let[s,i]of Object.entries(t)){let n=e[s]||s;r[n]=me(i,e)}return r}function ce(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 De(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 Zt(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 vt,mkdirSync as wi,readdirSync as Si,openSync as xi,closeSync as bi}from"fs";import{readFile as Ci,writeFile as Ii,rename as Ai,unlink as Qt,open as ki}from"fs/promises";import{join as wt,dirname as Pi}from"path";var J=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=He(r);this.dictionaries.set(e,s)}),vt(this.databaseDirectory)||wi(this.databaseDirectory,{recursive:!0})}async start(){try{let t=Si(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(ce(t),De(e),Zt(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 n=this.data.get(t),a=(n.get(e)?.version||0)+1,c={value:r,version:a,timestamp:Date.now(),expiration:s||null,dictionaryName:i||void 0};return n.set(e,c),await this.persistTable(t),!0}catch(n){return console.error(`Write failed for ${t}:${e}:`,n),!1}}async get(t,e){ce(t),e!==void 0&&De(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 n=r.get(e);if(!n)return;if(this.isExpired(n)){r.delete(e),await this.persistTable(t);return}return n.value}let s=[],i=[];for(let[n,o]of r.entries())this.isExpired(o)?i.push(n):s.push([n,o.value]);if(i.length>0){for(let n of i)r.delete(n);await this.persistTable(t)}return s}catch(r){return console.error(`Read failed for ${t}:${e}:`,r),e?void 0:[]}}async delete(t,e){ce(t),De(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){ce(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,n]of e.entries())this.isExpired(n)?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){ce(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){ce(t);try{this.data.delete(t);let e=wt(this.databaseDirectory,t);return vt(e)&&await Qt(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=He(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=wt(this.databaseDirectory,t);if(!vt(e)){this.data.set(t,new Map);return}try{let r=await Ci(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=wt(this.databaseDirectory,t),i=`${s}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await Ii(i,r),this.useFsync){let n=await ki(i,"r+");try{await n.sync()}finally{await n.close()}}if(await Ai(i,s),this.useFsync){let n=Pi(s),o=xi(n,"r");try{bi(o)}catch{}}}catch(n){try{await Qt(i)}catch{}throw n}}serializeTable(t){let e=Array.from(t.entries()).map(([r,s])=>{let i=s.dictionaryName?this.dictionaries.get(s.dictionaryName):void 0,n={d:i?me(s.value,i.deflate):s.value,v:s.version,t:s.timestamp,x:s.expiration};return s.dictionaryName&&(n.n=s.dictionaryName),[r,n]});return Buffer.from(JSON.stringify(e),"utf8")}deserializeTable(t){let r=JSON.parse(t.toString("utf8")).map(([s,i])=>{let n=i.n,o=n?this.dictionaries.get(n):void 0;return[s,{value:o?me(i.d,o.inflate):i.d,version:i.v,timestamp:i.t,expiration:i.x,dictionaryName:n||void 0}]});return new Map(r)}};import{join as Mn}from"node:path";import An from"node:http";import{join as lt}from"node:path";var er=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 Ei}from"url";var tr=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 n={};return s.paramNames.forEach((o,a)=>{n[o]=i[a+1]||""}),{route:r,params:n}}return null}async handle(t,e){let r=t.method||"GET",s=new Ei(t.url||"/",`http://${t.headers.host}`),i=s.pathname,n=this.match(r,i);if(!n)return null;let{route:o,params:a}=n,c={};s.searchParams.forEach((p,m)=>{c[m]=p});let l={req:t,res:e,params:a,query:c,body:t.body||{},headers:t.headers,path:i,state:{},raw:()=>e,binary:(p,m="application/octet-stream",w=200)=>({statusCode:w,body:p,headers:{"Content-Type":m,"Content-Length":p.length.toString()},isRaw:!0}),text:(p,m=200)=>({statusCode:m,body:p,headers:{"Content-Type":"text/plain"}}),form:(p,m=200)=>({statusCode:m,body:p,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),json:(p,m=200)=>({statusCode:m,body:p,headers:{"Content-Type":"application/json"}}),html:(p,m=200)=>({statusCode:m,body:p,headers:{"Content-Type":"text/html"}}),redirect:(p,m=302)=>({statusCode:m,body:null,headers:{Location:p}}),status:function(p){return{raw:()=>e,binary:(m,w="application/octet-stream")=>({statusCode:p,body:m,headers:{"Content-Type":w,"Content-Length":m.length.toString()},isRaw:!0}),text:m=>({statusCode:p,body:m,headers:{"Content-Type":"text/plain"}}),json:m=>({statusCode:p,body:m,headers:{"Content-Type":"application/json"}}),html:m=>({statusCode:p,body:m,headers:{"Content-Type":"text/html"}}),form:m=>({statusCode:p,body:m,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),redirect:(m,w=302)=>({statusCode:w,body:null,headers:{Location:m}}),status:m=>this.status(m)}}},u=[...this.globalMiddlewares,...o.middlewares];return this.executeMiddlewareChain(l,u,o.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 n=e[s++];return n(t,i)}return r(t)};return i()}};var Le=()=>({port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",debug:Ti(process.env.DEBUG)||!1,maxBodySize:1048576,requestTimeout:3e4,rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"]});function Ti(t){return t==="true"||t===!0}var B=Le(),rr=t=>({configFilePath:"mikroserve.config.json",args:process.argv,options:[{flag:"--port",path:"port",defaultValue:B.port},{flag:"--host",path:"host",defaultValue:B.host},{flag:"--https",path:"useHttps",defaultValue:B.useHttps,isFlag:!0},{flag:"--http2",path:"useHttp2",defaultValue:B.useHttp2,isFlag:!0},{flag:"--cert",path:"sslCert",defaultValue:B.sslCert},{flag:"--key",path:"sslKey",defaultValue:B.sslKey},{flag:"--ca",path:"sslCa",defaultValue:B.sslCa},{flag:"--ratelimit",path:"rateLimit.enabled",defaultValue:B.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"rateLimit.requestsPerMinute",defaultValue:B.rateLimit.requestsPerMinute},{flag:"--allowed",path:"allowedDomains",defaultValue:B.allowedDomains,parser:oe.array},{flag:"--debug",path:"debug",defaultValue:B.debug,isFlag:!0},{flag:"--max-body-size",path:"maxBodySize",defaultValue:B.maxBodySize},{flag:"--request-timeout",path:"requestTimeout",defaultValue:B.requestTimeout}],config:t});function sr(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}`),n=Buffer.from(`--${s}--`),o={},a={},c=Ri(t,i);for(let l of c){if(l.length===0||l.equals(n.subarray(i.length)))continue;let u=ji(l);if(!u)continue;let{name:p,filename:m,contentType:w,data:b}=u;if(m){let N={filename:m,contentType:w||"application/octet-stream",data:b,size:b.length};a[p]?Array.isArray(a[p])?a[p].push(N):a[p]=[a[p],N]:a[p]=N}else{let N=b.toString("utf8");o[p]?Array.isArray(o[p])?o[p].push(N):o[p]=[o[p],N]:o[p]=N}}return{fields:o,files:a}}function Ri(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 ji(t){let e=Buffer.from(`\r
112
112
  \r
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,d;for(let m of n){let v=m.toLowerCase();if(v.startsWith("content-disposition:")){a=m.substring(20).trim();let x=a.match(/name="([^"]+)"/);x&&(c=x[1]);let H=a.match(/filename="([^"]+)"/);H&&(l=H[1])}else v.startsWith("content-type:")&&(d=m.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:d,data:u}}import{readFileSync as me}from"fs";import ft from"http";import xi from"http2";import bi from"https";var Ae=class{config;rateLimiter;router;shutdownHandlers=[];constructor(t){let e=new re(Xt(t||{})).get();e.debug&&console.log("Using configuration:",e),this.config=e,this.router=new Kt;let r=e.rateLimit.requestsPerMinute||Le().rateLimit.requestsPerMinute;this.rateLimiter=new Jt(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:me(this.config.sslKey),cert:me(this.config.sslCert),...this.config.sslCa?{ca:me(this.config.sslCa)}:{}};return xi.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:me(this.config.sslKey),cert:me(this.config.sslCert),...this.config.sslCa?{ca:me(this.config.sslCa)}:{}};return bi.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 ft.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 ft.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 d=()=>{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,d(),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,d(),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 m=u.toString("utf8");e(JSON.parse(m))}catch(m){r(new Error(`Invalid JSON in request body: ${m.message}`))}else if(l.includes("application/x-www-form-urlencoded")){let m=u.toString("utf8"),v={};new URLSearchParams(m).forEach((x,H)=>{v[H]=x}),e(v)}else if(l.includes("multipart/form-data"))try{let m=Yt(u,l);e(m)}catch(m){r(new Error(`Invalid multipart form data: ${m.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,d(),r(new Error(`Error reading request body: ${u.message}`)))}),t.on("close",()=>{d()})})}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 ft.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 Ci}from"node:crypto";var ae="x-molnos-cluster-secret";function Zt(t,e){if(!t)return!1;let r=Buffer.from(t),s=Buffer.from(e);return r.length!==s.length?!1:Ci(r,s)}function ke(t){return async(e,r)=>{let s=e.headers[ae];return s?Zt(s,t)?(e.state.isClusterRequest=!0,r()):e.json({success:!1,error:"Invalid cluster authentication"},403):r()}}function gt(t,e){return{...t,[ae]:e}}var C=class extends Error{constructor(e){super(),this.name="ValidationError",this.message=e||"Invalid input",this.cause={statusCode:400}}},Pe=class extends Error{constructor(e){super(),this.name="IdentityAlreadyExistsError",this.message=e||"Identity already exists",this.cause={statusCode:400}}},V=class extends Error{constructor(e){super(),this.name="NotFoundError",this.message=e||"Resource not found",this.cause={statusCode:404}}},He=class extends Error{constructor(e){super(),this.name="InvalidInputError",this.message=e||"Invalid input",this.cause={statusCode:400}}};var K=class extends Error{constructor(e){super(),this.name="ConfigurationError",this.message=e||"Invalid configuration",this.cause={statusCode:400}}};var he=class extends Error{constructor(e){super(),this.name="PermissionDeniedError",this.message=e||"Permission denied",this.cause={statusCode:403}}},J=class extends Error{constructor(e){super(),this.name="AlreadyExistsError",this.message=e||"Resource already exists",this.cause={statusCode:409}}},De=class extends Error{constructor(e){super(),this.name="PortInUseError",this.message=e||"Port already in use",this.cause={statusCode:409}}},Ee=class extends Error{constructor(e){super(),this.name="RoleNotFoundError",this.message=e||"Role not found",this.cause={statusCode:404}}},Ne=class extends Error{constructor(e){super(),this.name="ProtectedResourceError",this.message=e||"Cannot modify protected resource",this.cause={statusCode:403}}},Fe=class extends Error{constructor(e){super(),this.name="ServiceRequestError",this.message=e||"Service request failed",this.cause={statusCode:502}}},_e=class extends Error{constructor(e){super(),this.name="WorkerUnavailableError",this.message=e||"Worker node is unavailable",this.cause={statusCode:503}}},qe=class extends Error{constructor(e){super(),this.name="WorkerTimeoutError",this.message=e||"Worker node did not respond in time",this.cause={statusCode:504}}};var Ii=5e3;async function yt(t,e,r,s,i,o){let n=new URL(e,t.url),a=new Headers;for(let[u,m]of Object.entries(i)){let v=u.toLowerCase();v==="host"||v==="connection"||v==="keep-alive"||v==="transfer-encoding"||a.set(u,m)}o&&a.set(ae,o);let c=t.timeoutMs||Ii,l=new AbortController,d=setTimeout(()=>l.abort(),c);try{let u;s&&(Buffer.isBuffer(s)?u=new Uint8Array(s):u=s);let m=await fetch(n.toString(),{method:r,headers:a,body:u,signal:l.signal});return clearTimeout(d),m}catch(u){throw clearTimeout(d),u.name==="AbortError"?new qe(`Worker at ${t.url} did not respond within ${c}ms`):new _e(`Worker at ${t.url} is unavailable: ${u.message}`)}}async function vt(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 Be={healthCheckPath:"/health",healthCheckIntervalMs:3e4,timeoutMs:5e3,failureThreshold:3},Te=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||Be.timeoutMs};this.workers.set(e,s);let i=r.healthCheckIntervalMs||Be.healthCheckIntervalMs,o=r.healthCheckPath||Be.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>=Be.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 ji from"node:crypto";import{getRandomValues as Ai}from"node:crypto";var wt=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);Ai(l);for(let d=0;d<a;d++){let u=l[d]&n;if(u<o.length&&(c+=o[u],c.length===e))break}}return c}};var ki=8,Pi=40,Ei=/^[a-zA-Z0-9_-]{1,40}$/;function Re(){return new wt().create(ki,"alphanumeric",!1,!0)}function Ti(t){return Ei.test(t)}function Ri(t){if(!Ti(t))throw new Error(`Invalid ID format: "${t}". IDs must be 1-${Pi} characters using only alphanumeric characters, underscores, and hyphens.`)}function Ve(t){return t?(Ri(t),t):Re()}function er(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(d=>Qt(d?.permissions,a)&&Qt(d?.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 ce=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 Ve()}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 C("Missing ID");if(!s)throw new C("Missing name");if(!i||!this.isValidType(i))throw new C("Missing or invalid type");if(i==="user"&&!o?.email)throw new C("Missing email for user identity");if(!n||n.length===0)throw new C("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 C(`Invalid role ID '${s}'`)})}can(e,r,s){return er(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 tr(){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 Ge=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=tr();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 Pe(`User with email ${e} already exists`);let c=new ce({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 Pe(`Service account with name ${e} already exists`);let a=new ce({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 ce().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 C("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.${Re()}.${ji.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 ce(s).can(e,r,s)}async createCustomRole(e,r,s,i,o){if(this.roles.find(l=>l.id===e))throw new J(`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 Ee(`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 Ee(`Role with ID ${e} not found`);if(e==="administrator"||e==="user")throw new Ne("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 $i}from"node:fs";import{spawn as Oi}from"node:child_process";import{createServer as Mi}from"node:net";var rr={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"]}},fe=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=gt({"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=Mi();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 ne({databaseDirectory:e.dbPath})}getServiceDefinition(e){let r=e.toLowerCase(),s=rr[r];if(!s)throw new V(`Unknown service: ${e}. Valid services are: ${Object.keys(rr).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 C("Service name is required");if(!e.path||e.path.trim()==="")throw new C("Service path is required");if(!$i(e.path))throw new K(`Service path does not exist: ${e.path}`);if(!e.port||e.port<1||e.port>65535)throw new C(`Invalid port: ${e.port}`);if(!e.prefix||!e.prefix.startsWith("/"))throw new C("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 De(`Port ${i.port} already in use`);if(n.includes(i.name))throw new J(`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=Oi("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 d=l.toString();console.log(`[${e}] ${d}`)}),a.stderr.on("data",l=>{let d=l.toString();console.error(`[${e}] ERROR: ${d}`),(d.includes("EADDRINUSE")||d.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 X=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 Ve()}validate(e){let{id:r,name:s,redirectUris:i,metadata:o,owners:n}=e;if(!r)throw new C("Missing ID");if(!s||s.trim().length===0)throw new C("Missing or invalid name");if(!o)throw new C("Missing metadata");if(!n||n.length===0)throw new C("Application must have at least one owner");this.validateRedirectUris(i)}validateRedirectUris(e){if(!e||e.length===0)throw new C("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 C(`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 C(`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 ze=class{db;tableName="molnosapplications";key="applications";applications;constructor(e){this.db=new ne({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 X({...e,owners:s,metadata:{...e.metadata,createdBy:r}}).toDTO();if(this.applications.find(a=>a.name===o.name))throw new J(`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 V(`Application with ID '${e}' not found`);let i=new X().fromDTO(s);if(r&&!i.isOwner(r))throw new he("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 X().fromDTO(r).toDTO())}async updateApplication(e,r,s){let i=this.applications.findIndex(a=>a.id===e);if(i===-1)throw new V(`Application with ID '${e}' not found`);let o=this.applications[i],n=new X().fromDTO(o);if(!n.isOwner(s))throw new he("Only application owners can update the application");if(r.owners&&r.owners.length===0)throw new C("Application must have at least one owner");if(r.owners&&!r.owners.includes(s)&&o.owners.length===1&&o.owners[0]===s)throw new C("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 V(`Application with ID '${e}' not found`);let i=this.applications[s];if(!new X().fromDTO(i).isOwner(r))throw new he("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 X().fromDTO(s).isValidRedirectUri(r):!1}getAllApplicationsInternal(){return this.applications}};async function S(t){return t.body||{}}function h(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 sr(t,e,r,s){try{let i=await S(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 d=!1;return await e.getUserByEmail(c)&&(d=!0),d&&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}=h(i,"Error during login");return t.json({error:o},n)}}async function ir(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}=h(s,"Error verifying token");return t.json({error:i},o)}}async function or(t,e){try{let s=(await S(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}=h(r,"Error refreshing token");return t.json({error:s},i)}}async function nr(t){try{let e=t.state.user;return t.json(e)}catch(e){let{message:r,status:s}=h(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 ar(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}=h(r,"Error getting identities");return t.json({error:s},i)}}var j=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],d=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,d),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 d=this.validateProperty(this.propertyPath,c.items,l);s.push(...d)}),this.updatePropertyPath()},n=a=>{let c=Object.keys(a),l=this.propertyPath;c.forEach(d=>{if(this.updatePropertyPath(d,l),this.isArray(a[d])&&r[d]?.items!=null)o(a[d],r[d]);else{let u=this.validateProperty(this.propertyPath,r[d],a[d]);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 cr={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 Li=new j(!0);async function lr(t,e){try{let r=t.state.user,s=await S(t),i=Li.test(cr,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,d=await e.addUser(n,a,c,l,o);return t.json(d,201)}catch(r){let{message:s,status:i}=h(r,"Error creating user");return t.json({error:s},i)}}async function ur(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}=h(r,"Error getting users");return t.json({error:s},i)}}function P(t){return t.params}async function dr(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error getting user");return t.json({error:s},i)}}var pr={properties:{name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var Di=new j(!0);async function mr(t,e){try{let r=t.state.user,s=P(t),{userId:i}=s,o=await S(t),n=Di.test(pr,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}=h(r,"Error updating user");return t.json({error:s},i)}}async function hr(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error deleting user");return t.json({error:s},i)}}async function fr(t,e){try{let r=t.state.user,s=await S(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}=h(r,"Error creating service account");return t.json({error:s},i)}}async function gr(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}=h(r,"Error getting service accounts");return t.json({error:s},i)}}async function yr(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error getting service account");return t.json({error:s},i)}}var vr={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 j(!0);async function wr(t,e){try{let r=t.state.user,s=P(t),{serviceAccountId:i}=s,o=await S(t),n=Fi.test(vr,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,d=await e.updateServiceAccount(i,{name:a,description:c,roles:l});return d?t.json(d):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error updating service account");return t.json({error:s},i)}}async function Sr(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error deleting service account");return t.json({error:s},i)}}async function xr(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error rotating service account key");return t.json({error:s},i)}}async function br(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}=h(r,"Error getting roles");return t.json({error:s},i)}}async function Cr(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}=h(r,"Error getting role");return t.json({error:s},i)}}async function Ir(t,e){try{let r=t.state.user;g(r,"identity.role.create",{});let s=await S(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}=h(r,"Error creating role");return t.json({error:s},i)}}async function Ar(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 S(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}=h(r,"Error updating role");return t.json({error:s},i)}}async function kr(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}=h(r,"Error deleting role");return t.json({error:s},i)}}async function Pr(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}=h(r,"Error getting services");return t.json({error:s},i)}}async function Er(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error getting service");return t.json({error:s},i)}}var Tr={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 qi=new j(!0);async function Rr(t,e){try{let r=t.state.user,s=await S(t),i=qi.test(Tr,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}=h(r,"Error creating service");return t.json({error:s},i)}}var jr={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 j(!0);async function $r(t,e){try{let r=t.state.user,s=P(t),i=await S(t),o=i.name,n=Vi.test(jr,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}=h(r,"Error updating service");return t.json({error:s},i)}}async function Or(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error deleting service");return t.json({error:s},i)}}async function Mr(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error starting service");return t.json({error:s},i)}}async function Ur(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error stopping service");return t.json({error:s},i)}}async function Lr(t,e){try{let r=t.state.user,s=P(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 Fe(`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}=h(r,"Error getting service logs");return t.json({error:s},i)}}async function Hr(t,e){try{let r=t.state.user,s=P(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}=h(r,"Error restarting service");return t.json({error:s},i)}}function Dr(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 w(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 d=l.replace(/^Bearer\s+/i,"");if(a=await e.getUserFromToken(d),!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,d=JSON.parse(l);Dr(d,s,i,o,n)}catch(l){if(l.cause?.statusCode===403)throw l;let d=new Error("Invalid function bindings header");throw d.cause={statusCode:400},d}return a}async function Nr(t,e,r){try{let s=await S(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 w(t,r,"applications.application.create","applications","application","create",n);let d={id:o,name:n,description:a,redirectUris:Array.isArray(c)?c:[c],metadata:l,owners:[i.id]},u=await e.createApplication(d,i.id);return t.json(u,201)}catch(s){let{message:i,status:o}=h(s,"Error creating application");return t.json({error:i},o)}}async function Fr(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 w(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}=h(s,"Error retrieving application");return t.json({error:i},o)}}async function _r(t,e,r){try{let s=t.state.requestingIdentity;if(!s)return t.json({error:"Authentication required"},401);await w(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}=h(s,"Error listing applications");return t.json({error:i},o)}}async function qr(t,e,r){try{let s=t.params.id,i=await S(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 w(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}=h(s,"Error updating application");return t.json({error:i},o)}}async function Br(t,e,r){try{let s=t.params.id,i=t.state.requestingIdentity;return i?s?(await w(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}=h(s,"Error deleting application");return t.json({error:i},o)}}async function Vr(t,e,r){try{await w(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}=h(s,"Error listing contexts");return t.json({error:i},o)}}async function Gr(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);await w(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}=h(s,"Error getting context");return t.json({error:i},o)}}var Gi=new j(!0),zi={properties:{name:{type:"string",minLength:1,maxLength:64},intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},required:["name"],additionalProperties:!1};async function zr(t,e,r){try{let s=await S(t),i=Gi.test(zi,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);await w(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}=h(s,"Error creating context");return t.json({error:i},o)}}var Wi=new j(!0),Ji={properties:{intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},additionalProperties:!1};async function Wr(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);let i=await S(t),o=Wi.test(Ji,i||{});if(!o.success)return t.json({error:"Invalid input",details:o.errors},400);await w(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}=h(s,"Error updating context");return t.json({error:i},o)}}async function Jr(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 w(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}=h(s,"Error deleting context");return t.json({error:i},o)}}async function Kr(t,e,r,s){try{let i=t.params.contextName;if(!i)return t.json({error:"contextName parameter is required"},400);await w(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 m of c.functions)try{let v=u.find(x=>x.id===m);v&&(await a.functions.delete(m),await e.unregisterResource(i,"function",m),l.deleted.push({type:"function",name:v.name}))}catch(v){l.errors.push({type:"function",name:m,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(m){l.errors.push({type:"database",name:u,error:m.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(m){l.errors.push({type:"storage",name:u,error:m.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(m){l.errors.push({type:"site",name:u,error:m.message||"Unknown error"}),l.success=!1}if(a.applications){let u=await a.applications.list();for(let m of c.applications)try{let v=u.find(x=>x.id===m);v&&(await a.applications.delete(m),await e.unregisterResource(i,"application",m),l.deleted.push({type:"application",name:v.name}))}catch(v){l.errors.push({type:"application",name:m,error:v.message||"Unknown error"}),l.success=!1}}if(a.identity)for(let u of c.users)try{let m=await a.identity.getUser(u);m&&(await a.identity.deleteUser(m.id),await e.unregisterResource(i,"user",u),l.deleted.push({type:"user",name:u}))}catch(m){l.errors.push({type:"user",name:u,error:m.message||"Unknown error"}),l.success=!1}if(a.identity)for(let u of c.serviceAccounts)try{let m=await a.identity.getServiceAccount(u);m&&(await a.identity.deleteServiceAccount(m.id),await e.unregisterResource(i,"serviceAccount",u),l.deleted.push({type:"serviceAccount",name:u}))}catch(m){l.errors.push({type:"serviceAccount",name:u,error:m.message||"Unknown error"}),l.success=!1}l.summary.deletedCount=l.deleted.length,l.summary.failedCount=l.errors.length;let d=l.success?200:207;return t.json(l,d)}catch(i){let{message:o,status:n}=h(i,"Error deleting context resources");return t.json({error:o},n)}}async function Xr(t,e,r){try{await w(t,r,"iac.config.get","iac","config","get");let s=await S(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}=h(s,"Error validating IaC");return t.json({error:i},o)}}async function Yr(t,e,r){try{await w(t,r,"iac.config.create","iac","config","create");let s=await S(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}),d=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},d)}catch(s){let{message:i,status:o}=h(s,"Error applying IaC");return t.json({error:i},o)}}var Y="default",We=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 J(`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 V(`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 V(`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 V(`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||Y;return this.contextExists(r)||await this.createContext({name:r,intent:r===Y?"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||Y}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 Zr(t,e,r){try{await w(t,r,"iac.config.get","iac","config","get");let s=await S(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||Y,toCreate:l.toCreate,toUpdate:l.toUpdate,toDelete:l.toDelete,unchanged:l.unchanged,warnings:c.warnings},200)}catch(s){let{message:i,status:o}=h(s,"Error generating IaC diff");return t.json({error:i},o)}}var Ki=new j(!0),Xi={type:"object",properties:{intent:{type:"string",minLength:1,maxLength:1e4},intentAttributes:{type:"object"},resourceTypes:{type:"array",items:{type:"string",enum:["functions","sites"]}},files:{type:"array",items:{type:"object",properties:{path:{type:"string"},content:{type:"string"}},required:["path","content"]}},iacConfig:{type:"object"},iterationFeedback:{type:"string"},previousAttemptId:{type:"string"},providerOverride:{type:"string"},modelOverride:{type:"string"},userApiKey:{type:"string"}},additionalProperties:!1};async function Qr(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"Context name is required"},400);await w(t,r,"ai.generation.generate","ai","generation","generate",s);let i=await S(t),o=Ki.test(Xi,i);if(!o.success)return t.json({error:"Invalid input",details:o.errors},400);if(!e.isAvailable())return t.json({error:"AI generation is not enabled. Please configure AI in molnos.config.json or provide your own API key."},503);let n=null;if(i.previousAttemptId&&(n=e.getGeneration(i.previousAttemptId),!n))return t.json({error:"Previous generation not found"},404);let a=await e.generate({contextName:s,intent:i.intent,intentAttributes:i.intentAttributes,resourceTypes:i.resourceTypes,files:i.files,iacConfig:i.iacConfig,iterationFeedback:i.iterationFeedback,previousAttempt:n||void 0,providerOverride:i.providerOverride,modelOverride:i.modelOverride,userApiKey:i.userApiKey});return t.json({success:!0,generation:a},201)}catch(s){let{message:i,status:o}=h(s,"Error generating code");return t.json({error:i},o)}}async function es(t,e,r){try{let s=t.params.generationId;if(!s)return t.json({error:"Generation ID is required"},400);await w(t,r,"ai.generation.read","ai","generation","read",s);let i=e.getGeneration(s);return i?t.json({success:!0,generation:i}):t.json({error:"Generation not found or expired"},404)}catch(s){let{message:i,status:o}=h(s,"Error retrieving generation");return t.json({error:i},o)}}async function ts(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"Context name is required"},400);await w(t,r,"ai.generation.read","ai","generation","read",s);let i=e.listGenerations(s);return t.json({success:!0,generations:i})}catch(s){let{message:i,status:o}=h(s,"Error listing generations");return t.json({error:i},o)}}async function rs(t,e,r){try{let s=t.params.generationId;if(!s)return t.json({error:"Generation ID is required"},400);await w(t,r,"ai.generation.apply","ai","generation","apply",s);let i=t.headers.authorization?.replace("Bearer ",""),o=await e.applyGeneration(s,i);if(!o.success)return t.json({error:"Failed to apply IAC configuration",details:o.errors},400);let n=e.getGeneration(s);return t.json({success:!0,generation:n,applyResult:o})}catch(s){let{message:i,status:o}=h(s,"Error applying generation");return t.json({error:i},o)}}async function ss(t,e,r){try{let s=t.params.generationId;return s?(await w(t,r,"ai.generation.discard","ai","generation","discard",s),e.getGeneration(s)?e.discardGeneration(s)?t.json({success:!0,message:"Generation discarded"}):t.json({error:"Failed to discard generation"},500):t.json({error:"Generation not found or expired"},404)):t.json({error:"Generation ID is required"},400)}catch(s){let{message:i,status:o}=h(s,"Error discarding generation");return t.json({error:i},o)}}async function is(t,e,r){try{let s=t.params.generationId;return s?(await w(t,r,"ai.generation.delete","ai","generation","delete",s),e.getGeneration(s)?e.deleteGeneration(s)?t.json({success:!0,message:"Generation deleted"}):t.json({error:"Failed to delete generation"},500):t.json({error:"Generation not found or expired"},404)):t.json({error:"Generation ID is required"},400)}catch(s){let{message:i,status:o}=h(s,"Error deleting generation");return t.json({error:i},o)}}import{promises as Je}from"node:fs";import{join as St,resolve as Zi}from"node:path";var os={$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"],default:"1",description:'IaC schema version (defaults to "1" if not specified)'},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:[]};var Qi=new j(!0),Ke=class{contextService;clients;constructor(e,r){this.contextService=e,this.clients=r}async loadConfiguration(e){let r=Zi(e);try{let s=await Je.readFile(r,"utf-8");return JSON.parse(s)}catch(s){throw s.code==="ENOENT"?new C(`IaC file not found: ${e}`):s instanceof SyntaxError?new C(`Invalid JSON in IaC file: ${s.message}`):s}}validate(e){let r=[],s=[];e.version||(e.version="1");let i=Qi.test(os,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||Y,created:[],updated:[],unchanged:[],deleted:[],errors:s.errors.map(n=>({type:"validation",name:n.path,error:n.message}))};let i=e.context?.name||Y,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 d=r.basePath?St(r.basePath,a.source):a.source;try{c=await Je.readFile(d,"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 d=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",d.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 d=r.basePath?St(r.basePath,a.source):a.source;if(c=await this.loadSiteFiles(d),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 d=c.find(u=>u.id===l);if(d&&!a.includes(d.name))try{await this.clients.functions.delete(l),await this.contextService.unregisterResource(i,"function",l),o.deleted.push({type:"function",name:d.name})}catch(u){o.errors.push({type:"function",name:d.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 d=c.find(u=>u.id===l);if(d&&!a.includes(d.name))try{await this.clients.applications.delete(l),await this.contextService.unregisterResource(i,"application",l),o.deleted.push({type:"application",name:d.name})}catch(u){o.errors.push({type:"application",name:d.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 Je.readdir(e,{withFileTypes:!0});for(let o of i){let n=St(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 Je.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||Y,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 ee=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"),d;if(l?.includes("application/json")?d=await c.json():d=await c.text(),!c.ok){let u=typeof d=="object"&&d.error?d.error:typeof d=="string"?d:JSON.stringify(d);throw new Error(u)}return d}},xt=class extends ee{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)}},bt=class extends ee{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}}},Ct=class extends ee{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||[]}},It=class extends ee{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||[]}},At=class extends ee{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||[]}},kt=class extends ee{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 Pt(t){let{serviceUrls:e,authToken:r}=t,s={};return e.databases&&(s.databases=new xt(e.databases,r)),e.storage&&(s.storage=new bt(e.storage,r)),e.functions&&(s.functions=new Ct(e.functions,r)),e.sites&&(s.sites=new It(e.sites,r)),e.identity&&(s.identity=new At(e.identity,r)),e.applications&&(s.applications=new kt(e.applications,r)),s}import{readFileSync as eo,existsSync as to}from"node:fs";function ns(){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||!to(t))return e;try{let r=eo(t,"utf-8");return JSON.parse(r)}catch(r){return console.error("[loadRuntimeConfig] Failed to load runtime config:",r),e}}import cs from"crypto";var as="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var ro=128,le,ge,so=t=>{!le||le.length<t?(le=Buffer.allocUnsafe(t*ro),cs.randomFillSync(le),ge=0):ge+t>le.length&&(cs.randomFillSync(le),ge=0),ge+=t};var ls=(t=21)=>{so(t|=0);let e="";for(let r=ge-t;r<ge;r++)e+=as[le[r]&63];return e};var Xe=class{generations=new Map;cleanupInterval=null;ttlHours;constructor(e=24){this.ttlHours=e}start(){this.cleanupInterval||(this.cleanupInterval=setInterval(()=>{this.cleanup()},3600*1e3))}stop(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null)}store(e){let r=ls(12),s=new Date().toISOString(),i=new Date(Date.now()+this.ttlHours*60*60*1e3).toISOString(),o={id:r,timestamp:s,expiresAt:i,...e};return this.generations.set(r,o),o}get(e){let r=this.generations.get(e);return r?new Date(r.expiresAt)<new Date?(this.generations.delete(e),null):r:null}updateStatus(e,r){let s=this.get(e);return s?(s.status=r,this.generations.set(e,s),!0):!1}delete(e){return this.generations.delete(e)}listByContext(e){let r=[];for(let s of this.generations.values())s.contextId===e&&new Date(s.expiresAt)>=new Date&&r.push(s);return r.sort((s,i)=>new Date(i.timestamp).getTime()-new Date(s.timestamp).getTime())}listPendingByContext(e){return this.listByContext(e).filter(r=>r.status==="pending")}getStats(){let e=0,r=0,s=0,i={};for(let o of this.generations.values())new Date(o.expiresAt)<new Date||(o.status==="pending"?e++:o.status==="applied"?r++:o.status==="discarded"&&s++,i[o.contextId]=(i[o.contextId]||0)+1);return{total:e+r+s,pending:e,applied:r,discarded:s,byContext:i}}cleanup(){let e=new Date,r=[];for(let[s,i]of this.generations.entries())new Date(i.expiresAt)<e&&r.push(s);for(let s of r)this.generations.delete(s);r.length>0&&console.log(`[GenerationStorage] Cleaned up ${r.length} expired generations`)}clear(){this.generations.clear()}size(){return this.generations.size}};var Ye=class{constructor(e){this.config=e;if(!e.apiKey)throw new Error("Anthropic API key is required");e.model||(this.config.model="claude-sonnet-4-5"),e.baseUrl||(this.config.baseUrl="https://api.anthropic.com"),e.maxTokens||(this.config.maxTokens=32e3)}name="anthropic";async validateConfig(){try{let e=await fetch(`${this.config.baseUrl}/v1/messages`,{method:"POST",headers:{"x-api-key":this.config.apiKey,"anthropic-version":"2023-06-01","content-type":"application/json"},body:JSON.stringify({model:this.config.model,max_tokens:1,messages:[{role:"user",content:"test"}]})});return e.ok||e.status===400}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:o}=e,n={...this.config,...o},a=this.transformMessages(r),c={model:n.model,max_tokens:n.maxTokens||32e3,messages:a};i&&(c.system=i),s&&s.length>0&&(c.tools=this.transformTools(s)),n.temperature!==void 0&&(c.temperature=n.temperature);let l=await fetch(`${n.baseUrl}/v1/messages`,{method:"POST",headers:{"x-api-key":n.apiKey,"anthropic-version":"2023-06-01","content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let u=await l.text();throw new Error(`Anthropic API error (${l.status}): ${u}`)}let d=await l.json();return this.transformResponse(d)}transformMessages(e){return e.map(r=>Array.isArray(r.content)?{role:r.role==="system"?"user":r.role,content:r.content}:{role:r.role==="system"?"user":r.role,content:r.content})}transformTools(e){return e.map(r=>({name:r.name,description:r.description,input_schema:r.input_schema}))}transformResponse(e){let r={content:"",stopReason:e.stop_reason},s=e.content.filter(o=>o.type==="text");r.content=s.map(o=>o.text).join(`
115
- `);let i=e.content.filter(o=>o.type==="tool_use");return i.length>0&&(r.toolCalls=i.map(o=>({id:o.id,name:o.name,input:o.input}))),e.usage&&(r.usage={inputTokens:e.usage.input_tokens||0,outputTokens:e.usage.output_tokens||0,totalTokens:(e.usage.input_tokens||0)+(e.usage.output_tokens||0)}),r}};var Ze=class{constructor(e){this.config=e;if(!e.apiKey)throw new Error("OpenAI API key is required");e.model||(this.config.model="gpt-4-turbo"),e.baseUrl||(this.config.baseUrl="https://api.openai.com/v1"),e.maxTokens||(this.config.maxTokens=32e3)}name="openai";async validateConfig(){try{return(await fetch(`${this.config.baseUrl}/models`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`}})).ok}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:o}=e,n={...this.config,...o},a=this.transformMessages(r,i),c={model:n.model,max_tokens:n.maxTokens||32e3,messages:a};s&&s.length>0&&(c.tools=this.transformTools(s),c.tool_choice="auto"),n.temperature!==void 0&&(c.temperature=n.temperature);let l=await fetch(`${n.baseUrl}/chat/completions`,{method:"POST",headers:{Authorization:`Bearer ${n.apiKey}`,"content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let u=await l.text();throw new Error(`OpenAI API error (${l.status}): ${u}`)}let d=await l.json();return this.transformResponse(d)}transformMessages(e,r){let s=[];r&&s.push({role:"system",content:r});for(let i of e)if(Array.isArray(i.content)){let o=i.content.filter(c=>c.type==="tool_use");if(o.length>0&&i.role==="assistant"){s.push({role:"assistant",content:null,tool_calls:o.map(c=>({id:c.tool_use_id||`call_${Date.now()}`,type:"function",function:{name:c.tool_name||"",arguments:JSON.stringify(c.tool_input||{})}}))});continue}let n=i.content.filter(c=>c.type==="tool_result");if(n.length>0&&i.role==="user"){for(let c of n)s.push({role:"tool",tool_call_id:c.tool_use_id||"",content:c.content||""});continue}let a=i.content.filter(c=>c.type==="text");a.length>0&&s.push({role:i.role==="system"?"system":i.role,content:a.map(c=>c.text).join(`
116
- `)})}else s.push({role:i.role==="system"?"system":i.role,content:i.content});return s}transformTools(e){return e.map(r=>({type:"function",function:{name:r.name,description:r.description,parameters:r.input_schema}}))}transformResponse(e){let r=e.choices[0],s=r.message,i={content:s.content||"",stopReason:r.finish_reason};return s.tool_calls&&s.tool_calls.length>0&&(i.toolCalls=s.tool_calls.map(o=>({id:o.id,name:o.function.name,input:JSON.parse(o.function.arguments)}))),e.usage&&(i.usage={inputTokens:e.usage.prompt_tokens||0,outputTokens:e.usage.completion_tokens||0,totalTokens:e.usage.total_tokens||0}),i}};var Qe=class{constructor(e){this.config=e;e.endpoint||(this.config.endpoint="http://localhost:11434"),e.model||(this.config.model="codellama:13b"),e.maxTokens||(this.config.maxTokens=32e3)}name="ollama";async validateConfig(){try{let e=await fetch(`${this.config.endpoint}/api/tags`);return e.ok?((await e.json()).models||[]).some(o=>o.name===this.config.model||o.name.startsWith(this.config.model)):!1}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:o}=e,n={...this.config,...o},a=this.transformMessages(r,i),c={model:n.model,messages:a,stream:!1};n.maxTokens&&(c.options={num_predict:n.maxTokens}),n.temperature!==void 0&&(c.options={...c.options,temperature:n.temperature}),s&&s.length>0&&(c.tools=this.transformTools(s));let l=await fetch(`${n.endpoint}/api/chat`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let u=await l.text();throw new Error(`Ollama API error (${l.status}): ${u}`)}let d=await l.json();return this.transformResponse(d)}transformMessages(e,r){let s=[];r&&s.push({role:"system",content:r});for(let i of e)if(Array.isArray(i.content)){let o=i.content.filter(c=>c.type==="tool_use");if(o.length>0&&i.role==="assistant"){let c=o.map(l=>`Calling tool: ${l.tool_name}
113
+ `),r=t.indexOf(e);if(r===-1)return null;let s=t.subarray(0,r),i=t.subarray(r+4),o=s.toString("utf8").split(`\r
114
+ `),a="",c="",l,u;for(let m of o){let w=m.toLowerCase();if(w.startsWith("content-disposition:")){a=m.substring(20).trim();let b=a.match(/name="([^"]+)"/);b&&(c=b[1]);let N=a.match(/filename="([^"]+)"/);N&&(l=N[1])}else w.startsWith("content-type:")&&(u=m.substring(13).trim())}if(!c)return null;let p=i;return p.length>=2&&p[p.length-2]===13&&p[p.length-1]===10&&(p=p.subarray(0,p.length-2)),{disposition:a,name:c,filename:l,contentType:u,data:p}}import{readFileSync as he}from"fs";import St from"http";import $i from"http2";import Oi from"https";var ke=class{config;rateLimiter;router;shutdownHandlers=[];constructor(t){let e=new ne(rr(t||{})).get();e.debug&&console.log("Using configuration:",e),this.config=e,this.router=new tr;let r=e.rateLimit.requestsPerMinute||Le().rateLimit.requestsPerMinute;this.rateLimiter=new er(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:he(this.config.sslKey),cert:he(this.config.sslCert),...this.config.sslCa?{ca:he(this.config.sslCa)}:{}};return $i.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:he(this.config.sslKey),cert:he(this.config.sslCert),...this.config.sslCa?{ca:he(this.config.sslCa)}:{}};return Oi.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",n=this.config.debug;try{if(this.setCorsHeaders(e,t),this.setSecurityHeaders(e,this.config.useHttps),n&&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 n&&console.error("Body parsing error:",a.message),this.respond(e,{statusCode:400,body:{error:"Bad Request",message:a.message}})}let o=await this.router.handle(t,e);return o?o._handled?void 0:this.respond(e,o):this.respond(e,{statusCode:404,body:{error:"Not Found",message:"The requested endpoint does not exist"}})}catch(o){return console.error("Server error:",o),this.respond(e,{statusCode:500,body:{error:"Internal Server Error",message:n?o.message:"An unexpected error occurred"}})}finally{n&&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,n=this.config.maxBodySize,o=!1,a=null,c=this.config.debug,l=t.headers["content-type"]||"";c&&console.log("Content-Type:",l),this.config.requestTimeout>0&&(a=setTimeout(()=>{o||(o=!0,c&&console.log("Request timeout exceeded"),r(new Error("Request timeout")))},this.config.requestTimeout));let u=()=>{a&&(clearTimeout(a),a=null)};t.on("data",p=>{if(!o){if(i+=p.length,c&&console.log(`Received chunk: ${p.length} bytes, total size: ${i}`),i>n){o=!0,u(),c&&console.log(`Body size exceeded limit: ${i} > ${n}`),r(new Error("Request body too large"));return}s.push(p)}}),t.on("end",()=>{if(!o){o=!0,u(),c&&console.log(`Request body complete: ${i} bytes`);try{if(s.length>0){let p=Buffer.concat(s);if(l.includes("application/json"))try{let m=p.toString("utf8");e(JSON.parse(m))}catch(m){r(new Error(`Invalid JSON in request body: ${m.message}`))}else if(l.includes("application/x-www-form-urlencoded")){let m=p.toString("utf8"),w={};new URLSearchParams(m).forEach((b,N)=>{w[N]=b}),e(w)}else if(l.includes("multipart/form-data"))try{let m=sr(p,l);e(m)}catch(m){r(new Error(`Invalid multipart form data: ${m.message}`))}else this.isBinaryContentType(l)?e(p):e(p.toString("utf8"))}else e({})}catch(p){r(new Error(`Invalid request body: ${p}`))}}}),t.on("error",p=>{o||(o=!0,u(),r(new Error(`Error reading request body: ${p.message}`)))}),t.on("close",()=>{u()})})}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,n])=>{s.setHeader(i,n)})}}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=o=>{console.log("Shutting down MikroServe server..."),o&&console.error("Error:",o),this.cleanupShutdownHandlers(),t.close(()=>{console.log("Server closed successfully"),process.env.NODE_ENV!=="test"&&process.env.VITEST!=="true"&&setImmediate(()=>process.exit(o?1:0))})},r=()=>e(),s=()=>e(),i=o=>e(o),n=o=>e(o);this.shutdownHandlers=[r,s,i,n],process.on("SIGINT",r),process.on("SIGTERM",s),process.on("uncaughtException",i),process.on("unhandledRejection",n)}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 Mi}from"node:crypto";var le="x-molnos-cluster-secret";function ir(t,e){if(!t)return!1;let r=Buffer.from(t),s=Buffer.from(e);return r.length!==s.length?!1:Mi(r,s)}function Pe(t){return async(e,r)=>{let s=e.headers[le];return s?ir(s,t)?(e.state.isClusterRequest=!0,r()):e.json({success:!1,error:"Invalid cluster authentication"},403):r()}}function xt(t,e){return{...t,[le]:e}}var x=class extends Error{constructor(e){super(),this.name="ValidationError",this.message=e||"Invalid input",this.cause={statusCode:400}}},Ee=class extends Error{constructor(e){super(),this.name="IdentityAlreadyExistsError",this.message=e||"Identity already exists",this.cause={statusCode:400}}},q=class extends Error{constructor(e){super(),this.name="NotFoundError",this.message=e||"Resource not found",this.cause={statusCode:404}}},Ne=class extends Error{constructor(e){super(),this.name="InvalidInputError",this.message=e||"Invalid input",this.cause={statusCode:400}}};var K=class extends Error{constructor(e){super(),this.name="ConfigurationError",this.message=e||"Invalid configuration",this.cause={statusCode:400}}};var fe=class extends Error{constructor(e){super(),this.name="PermissionDeniedError",this.message=e||"Permission denied",this.cause={statusCode:403}}},G=class extends Error{constructor(e){super(),this.name="AlreadyExistsError",this.message=e||"Resource already exists",this.cause={statusCode:409}}},qe=class extends Error{constructor(e){super(),this.name="PortInUseError",this.message=e||"Port already in use",this.cause={statusCode:409}}},Te=class extends Error{constructor(e){super(),this.name="RoleNotFoundError",this.message=e||"Role not found",this.cause={statusCode:404}}},Fe=class extends Error{constructor(e){super(),this.name="ProtectedResourceError",this.message=e||"Cannot modify protected resource",this.cause={statusCode:403}}},_e=class extends Error{constructor(e){super(),this.name="ServiceRequestError",this.message=e||"Service request failed",this.cause={statusCode:502}}},Be=class extends Error{constructor(e){super(),this.name="WorkerUnavailableError",this.message=e||"Worker node is unavailable",this.cause={statusCode:503}}},Ve=class extends Error{constructor(e){super(),this.name="WorkerTimeoutError",this.message=e||"Worker node did not respond in time",this.cause={statusCode:504}}};var Ui=5e3;async function bt(t,e,r,s,i,n){let o=new URL(e,t.url),a=new Headers;for(let[p,m]of Object.entries(i)){let w=p.toLowerCase();w==="host"||w==="connection"||w==="keep-alive"||w==="transfer-encoding"||a.set(p,m)}n&&a.set(le,n);let c=t.timeoutMs||Ui,l=new AbortController,u=setTimeout(()=>l.abort(),c);try{let p;s&&(Buffer.isBuffer(s)?p=new Uint8Array(s):p=s);let m=await fetch(o.toString(),{method:r,headers:a,body:p,signal:l.signal});return clearTimeout(u),m}catch(p){throw clearTimeout(u),p.name==="AbortError"?new Ve(`Worker at ${t.url} did not respond within ${c}ms`):new Be(`Worker at ${t.url} is unavailable: ${p.message}`)}}async function Ct(t,e){let r=e.headers.get("content-type")||"",s=e.status;if(r.includes("application/json")){let o=await e.text();try{let a=JSON.parse(o);return t.json(a,s)}catch{return t.text(o,s)}}if(r.startsWith("text/")||r.includes("javascript")||r.includes("xml")){let o=await e.text();return t.text(o,s)}let i=await e.arrayBuffer(),n=t.binary(Buffer.from(i),r||"application/octet-stream");return s!==200?{...n,statusCode:s}:n}var Ge={healthCheckPath:"/health",healthCheckIntervalMs:3e4,timeoutMs:5e3,failureThreshold:3},Re=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||Ge.timeoutMs};this.workers.set(e,s);let i=r.healthCheckIntervalMs||Ge.healthCheckIntervalMs,n=r.healthCheckPath||Ge.healthCheckPath,o=setInterval(()=>this.checkHealth(e,n),i);this.timers.set(e,o),await this.checkHealth(e,n)}async checkHealth(e,r){let s=this.workers.get(e);if(s){try{let i=new AbortController,n=setTimeout(()=>i.abort(),s.timeoutMs),o=await fetch(`${s.url}${r}`,{method:"GET",signal:i.signal});clearTimeout(n),o.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>=Ge.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 _i from"node:crypto";import{getRandomValues as Hi}from"node:crypto";var It=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 n=this.getCharacterSet(s,r,i),o=(2<<Math.log(n.length-1)/Math.LN2)-1,a=Math.ceil(1.6*o*e/n.length),c="";for(;c.length<e;){let l=new Uint8Array(a);Hi(l);for(let u=0;u<a;u++){let p=l[u]&o;if(p<n.length&&(c+=n[p],c.length===e))break}}return c}};var Di=8,Li=40,Ni=/^[a-zA-Z0-9_-]{1,40}$/;function je(){return new It().create(Di,"alphanumeric",!1,!0)}function qi(t){return Ni.test(t)}function Fi(t){if(!qi(t))throw new Error(`Invalid ID format: "${t}". IDs must be 1-${Li} characters using only alphanumeric characters, underscores, and hyphens.`)}function ze(t){return t?(Fi(t),t):je()}function or(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 o=(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(!o.some(u=>nr(u?.permissions,a)&&nr(u?.targets,c)))return!1;return!0}function nr(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 ue=class{id;name;type;roles;metadata;constructor(e){let{id:r,name:s,type:i,roles:n,metadata:o}=this.createIdentity(e);this.id=r,this.name=s,this.type=i,this.roles=n,this.metadata=o}createIdentity(e){let r=e?.id||this.createId(),s=e?.name||"",i=e?.type||"service_account",n=e?.metadata||{},o=e?.roles||["user"];return e&&this.validate({id:r,name:s,type:i,metadata:n,roles:o}),{id:r,name:s,type:i,metadata:{...n,createdAt:new Date().toISOString()},roles:o}}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 ze()}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||"",n=e.metadata||{},o=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"&&!n?.email)throw new x("Missing email for user identity");if(!o||o.length===0)throw new x("Must have at least one role");this.validateRoles(o)}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 or(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 ar(){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 We=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=ar();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,n){if((await this.getUsers()).find(l=>l.metadata.email===e))throw new Ee(`User with email ${e} already exists`);let c=new ue({id:n,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 Ee(`Service account with name ${e} already exists`);let a=new ue({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,n]of this.serviceAccountTokens.entries())n===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 ue().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 n=i.toDTO();return this.updateIdentityList(n),await this.saveState(),this.enrichIdentityWithRoles(n)}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.${je()}.${_i.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 n=this.identities.find(o=>o.id===i&&o.type==="service_account");if(n)return this.enrichIdentityWithRoles(n)}}else try{let i=this.mikroAuth.verify(r),n=i.email||i.sub;return this.getUserByEmail(n)}catch{let n=new Error("Invalid token");throw n.cause={statusCode:401},n}}}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 ue(s).can(e,r,s)}async createCustomRole(e,r,s,i,n){if(this.roles.find(l=>l.id===e))throw new G(`Role with ID ${e} already exists`);let c={id:e,name:r,description:s,policies:[{permissions:i,targets:["*"]}],constraints:n||{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 Te(`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 Te(`Role with ID ${e} not found`);if(e==="administrator"||e==="user")throw new Fe("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 Bi}from"node:fs";import{spawn as Vi}from"node:child_process";import{createServer as Gi}from"node:net";var cr={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"]}},ge=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 n=`${s}/management/service/${e}/${r}`,o=xt({"Content-Type":"application/json"},i);try{let a=await fetch(n,{method:"POST",headers:o});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=Gi();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 J({databaseDirectory:e.dbPath})}getServiceDefinition(e){let r=e.toLowerCase(),s=cr[r];if(!s)throw new q(`Unknown service: ${e}. Valid services are: ${Object.keys(cr).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(!Bi(e.path))throw new K(`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:n,consecutiveSuccesses:o,healthy:a,...c}=s.healthCheck;s.healthCheck=c}if(s.restartPolicy){let{attempts:i,...n}=s.restartPolicy;s.restartPolicy=n}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},n=await this.getServices(),o=[],a=[];if(n.forEach(l=>{o.push(l.name),a.push(l.port)}),a.includes(i.port))throw new qe(`Port ${i.port} already in use`);if(o.includes(i.name))throw new G(`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}},n=r.args||[],o=`--port=${r.port}`,a=Vi("node",[r.path,o,...n],i);r.process=a,r.restartPolicy&&(r.restartPolicy.attempts=0);let c=!1;return a.stdout.on("data",l=>{let u=l.toString();console.log(`[${e}] ${u}`)}),a.stderr.on("data",l=>{let u=l.toString();console.error(`[${e}] ERROR: ${u}`),(u.includes("EADDRINUSE")||u.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,n=setTimeout(()=>i.abort(),e.healthCheck.timeoutMs),o=await fetch(`http://127.0.0.1:${e.port}${e.healthCheck.path}`,{signal:i.signal});clearTimeout(n),o.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 n=setTimeout(()=>{try{s(i)&&process.kill(i,"SIGKILL")}catch{}},5*1e3);await new Promise(o=>{if(!r.process){clearTimeout(n),o();return}let a=setTimeout(()=>{clearTimeout(n),o()},6*1e3);r.process.once("exit",()=>{clearTimeout(n),clearTimeout(a),o()})})}catch(n){if(n.code!=="ESRCH")throw n}}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(n=>n.name===e);if(i>=0){let n=this.services.get(e);n?(n.active=r,s[i]=this.cleanServiceForStorage(n)):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 n=await this.db.get(this.tableName,"services")||[],o=n.findIndex(a=>a.name===e);return o>=0?(n[o]=this.cleanServiceForStorage(s),await this.db.write(this.tableName,"services",n),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(n=>n.name!==e);return await this.db.write(this.tableName,"services",i),!0}};var X=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,n=e?.redirectUris||[],o=e?.owners||[],a=new Date().toISOString(),c={...e?.metadata||{},createdAt:e?.metadata?.createdAt||a,updatedAt:a,createdBy:e?.metadata?.createdBy||o[0]||""};return e&&this.validate({id:r,name:s,description:i,redirectUris:n,metadata:c,owners:o}),{id:r,name:s,description:i,redirectUris:n,metadata:c,owners:o}}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 ze()}validate(e){let{id:r,name:s,redirectUris:i,metadata:n,owners:o}=e;if(!r)throw new x("Missing ID");if(!s||s.trim().length===0)throw new x("Missing or invalid name");if(!n)throw new x("Missing metadata");if(!o||o.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 Je=class{db;tableName="molnosapplications";key="applications";applications;constructor(e){this.db=new J({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],n=new X({...e,owners:s,metadata:{...e.metadata,createdBy:r}}).toDTO();if(this.applications.find(a=>a.name===n.name))throw new G(`Application with name '${n.name}' already exists`);return this.applications.push(n),await this.saveState(),n}async getApplication(e,r){let s=this.applications.find(n=>n.id===e);if(!s)throw new q(`Application with ID '${e}' not found`);let i=new X().fromDTO(s);if(r&&!i.isOwner(r))throw new fe("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 X().fromDTO(r).toDTO())}async updateApplication(e,r,s){let i=this.applications.findIndex(a=>a.id===e);if(i===-1)throw new q(`Application with ID '${e}' not found`);let n=this.applications[i],o=new X().fromDTO(n);if(!o.isOwner(s))throw new fe("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)&&n.owners.length===1&&n.owners[0]===s)throw new x("Cannot remove yourself as the last owner of the application");return o.update(r),this.applications[i]=o.toDTO(),await this.saveState(),this.applications[i]}async deleteApplication(e,r){let s=this.applications.findIndex(o=>o.id===e);if(s===-1)throw new q(`Application with ID '${e}' not found`);let i=this.applications[s];if(!new X().fromDTO(i).isOwner(r))throw new fe("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 X().fromDTO(s).isValidRedirectUri(r):!1}getAllApplicationsInternal(){return this.applications}};var zi=/^[a-z0-9][a-z0-9-]*[a-z0-9]$/,$e=class{name;version;description;schema;createdAt;updatedAt;constructor(e){let r=this.createSchema(e);this.name=r.name,this.version=r.version,this.description=r.description,this.schema=r.schema,this.createdAt=r.createdAt,this.updatedAt=r.updatedAt}createSchema(e){let r=e?.name||"",s=e?.version||1,i=e?.description,n=e?.schema||{properties:{}},o=new Date().toISOString(),a=e?.createdAt||o,c=o;return e&&this.validate({name:r,schema:n}),{name:r,version:s,description:i,schema:n,createdAt:a,updatedAt:c}}update(e){e.schema&&(this.validateSchemaDefinition(e.schema),this.schema=e.schema),e.description!==void 0&&(this.description=e.description),this.version+=1,this.updatedAt=new Date().toISOString()}validate(e){let{name:r,schema:s}=e;if(!r||r.trim().length===0)throw new x("Missing or invalid schema name");if(r.length<2||r.length>100)throw new x("Schema name must be between 2 and 100 characters");if(!zi.test(r))throw new x("Schema name must be kebab-case (lowercase alphanumeric and hyphens, cannot start or end with hyphen)");this.validateSchemaDefinition(s)}validateSchemaDefinition(e){if(!e||!e.properties)throw new x("Schema must have a properties object");if(Object.keys(e.properties).length===0)throw new x("Schema must define at least one property");let r=["string","number","boolean","array","object"];for(let[s,i]of Object.entries(e.properties))if(!i.type||!r.includes(i.type))throw new x(`Property '${s}' has invalid type. Must be one of: ${r.join(", ")}`)}fromDTO(e){return this.validate({name:e.name,schema:e.schema}),this.name=e.name,this.version=e.version,this.description=e.description,this.schema=e.schema,this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this}toDTO(){return{name:this.name,version:this.version,description:this.description,schema:this.schema,createdAt:this.createdAt,updatedAt:this.updatedAt}}};var Ke=class{db;tableName="molnosschemas";key="schemas";schemas;constructor(e){this.db=new J({databaseDirectory:e.dbPath}),this.schemas=[]}async start(){await this.db.start(),await this.loadState()}async loadState(){let e=await this.db.get(this.tableName,this.key)||[];this.schemas=e}async saveState(){await this.db.write(this.tableName,this.key,this.schemas)}async createSchema(e){if(this.schemas.find(n=>n.name===e.name))throw new G(`Schema with name '${e.name}' already exists`);let i=new $e(e).toDTO();return this.schemas.push(i),await this.saveState(),i}async getSchema(e,r){let s=this.findSchema(e,r);if(!s){let i=r?` version ${r}`:"";throw new q(`Schema '${e}'${i} not found`)}return s}async listSchemas(){return[...this.schemas]}async updateSchema(e,r){let s=this.schemas.findIndex(o=>o.name===e);if(s===-1)throw new q(`Schema '${e}' not found`);if(!r.schema)throw new x("Schema definition is required for update");let i=this.schemas[s],n=new $e().fromDTO(i);return n.update(r),this.schemas[s]=n.toDTO(),await this.saveState(),this.schemas[s]}async deleteSchema(e){let r=this.schemas.findIndex(s=>s.name===e);if(r===-1)throw new q(`Schema '${e}' not found`);this.schemas.splice(r,1),await this.saveState()}validate(e,r,s){let i=this.findSchema(r,s);return i?this.validateAgainstDefinition(e,i.schema):{valid:!1,errors:[{path:"",message:`Schema '${r}' not found in registry`}]}}findSchema(e,r){return r?this.schemas.find(s=>s.name===e&&s.version===r):this.schemas.find(s=>s.name===e)}validateAgainstDefinition(e,r){let s=[];if(typeof e!="object"||e===null||Array.isArray(e))return{valid:!1,errors:[{path:"",message:"Data must be a non-null object"}]};let i=e;if(r.required)for(let n of r.required)n in i||s.push({path:n,message:`Missing required field '${n}'`});for(let[n,o]of Object.entries(r.properties))o.required&&!(n in i)&&(r.required?.includes(n)||s.push({path:n,message:`Missing required field '${n}'`}));for(let[n,o]of Object.entries(i)){let a=r.properties[n];if(!a){r.additionalProperties===!1&&s.push({path:n,message:`Unexpected property '${n}'`});continue}let c=this.validatePropertyType(n,o,a);c&&s.push(c)}return{valid:s.length===0,errors:s.length>0?s:void 0}}validatePropertyType(e,r,s){if(r==null)return null;let i=Array.isArray(r)?"array":typeof r;if(s.type==="array"){if(!Array.isArray(r))return{path:e,message:`Expected type 'array', got '${typeof r}'`}}else if(s.type==="object"){if(typeof r!="object"||Array.isArray(r))return{path:e,message:`Expected type 'object', got '${i}'`}}else if(i!==s.type)return{path:e,message:`Expected type '${s.type}', got '${i}'`};return null}};async function S(t){return t.body||{}}function h(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 lr(t,e,r,s){try{let i=await S(t),{email:n,redirectUrl:o,applicationId:a}=i;if(!n)return t.json({error:"Email is required"},400);let c=n.trim().toLowerCase(),l;if(o){if(!a)return t.json({error:"applicationId is required when redirectUrl is provided"},400);if(!await s.validateRedirectUri(a,o))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 u=!1;return await e.getUserByEmail(c)&&(u=!0),u&&await r.createMagicLink({email:c,subject:`Sign In To ${l||"MolnOS"}`,appUrl:o,metadata:{appName:l,redirectUrl:o,applicationId:a}}),t.json({success:!0,message:"If a matching account was found, a magic link has been sent."})}catch(i){let{message:n,status:o}=h(i,"Error during login");return t.json({error:n},o)}}async function ur(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 n=await e.verifyToken({token:s,email:i});if(!n)return t.json({error:"Invalid or expired token"},401);let o=n.metadata;if(o?.redirectUrl&&o?.applicationId)if(await r.validateRedirectUri(o.applicationId,o.redirectUrl)){let c=new URL(o.redirectUrl);return c.searchParams.set("access_token",n.accessToken),c.searchParams.set("refresh_token",n.refreshToken),c.searchParams.set("expires_in",n.expiresIn.toString()),t.redirect(c.toString(),302)}else return console.warn(`Redirect URL validation failed for applicationId: ${o.applicationId}`),t.json({...n,warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);return t.json(n,200)}catch{return t.json({error:"Invalid or expired token"},401)}}catch(s){let{message:i,status:n}=h(s,"Error verifying token");return t.json({error:i},n)}}async function dr(t,e){try{let s=(await S(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}=h(r,"Error refreshing token");return t.json({error:s},i)}}async function pr(t){try{let e=t.state.user;return t.json(e)}catch(e){let{message:r,status:s}=h(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 o=new Error("Unauthorized: User or roles missing");throw o.cause={statusCode:403},o}let i=t.roles.flatMap(o=>o?.policies?.flatMap(a=>(a?.permissions||[]).flatMap(l=>typeof l=="string"?l:l&&typeof l=="object"&&l.actions?l.actions:[]))||[]);if(!s.every(o=>i.includes(o)||i.includes("*")?!0:i.some(a=>{if(a.endsWith(".*")){let c=a.slice(0,-2);return o.startsWith(`${c}.`)}return!1}))){let o=new Error("Unauthorized");throw o.cause={statusCode:403},o}return!0}async function mr(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}=h(r,"Error getting identities");return t.json({error:s},i)}}var $=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),n=this.isSuccessful(r,i);return{errors:i,success:n}}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,n=t?.required||[];s=this.checkForRequiredKeysErrors(n,e,s),s=this.checkForDisallowedProperties(Object.keys(e),Object.keys(t),s,i);for(let o in t){let a=n.includes(o)&&o!=="required",c=t[o],l=e[o],u=c.additionalProperties??!0;a&&(s=this.checkForRequiredKeysErrors(c.required||[],l,s)),this.isDefined(l)&&(this.handleValidation(o,l,c,r),s=this.checkForDisallowedProperties(Object.keys(l),Object.keys(c),s,u),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),n=i.length>0?`Missing the required key: '${i.join(", ")}'!`:`Missing values for required keys: '${s.filter(o=>!e[o]).join(", ")}'!`;r.push({key:"",value:e,success:!1,error:n})}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 n=(a,c)=>{a.forEach(l=>{let u=this.validateProperty(this.propertyPath,c.items,l);s.push(...u)}),this.updatePropertyPath()},o=a=>{let c=Object.keys(a),l=this.propertyPath;c.forEach(u=>{if(this.updatePropertyPath(u,l),this.isArray(a[u])&&r[u]?.items!=null)n(a[u],r[u]);else{let p=this.validateProperty(this.propertyPath,r[u],a[u]);s.push(...p)}})};this.isArray(e)&&r.items!=null?n(e,r):this.isObject(e)?o(e):this.updatePropertyPath()}handleNestedObject(t,e,r,s){if(this.isObject(t)){let i=this.getNestedObjects(t);for(let n of i){let o=e[n],a=t[n];o&&typeof a=="object"&&this.validate(o,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:n,error:o}=i;return{key:t,value:r,success:n,error:o??""}})}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(n=>typeof n==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 hr={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 Ji=new $(!0);async function fr(t,e){try{let r=t.state.user,s=await S(t),i=Ji.test(hr,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);g(r,"identity.user.create",{});let{id:n,email:o,name:a,roles:c,verified:l}=s,u=await e.addUser(o,a,c,l,n);return t.json(u,201)}catch(r){let{message:s,status:i}=h(r,"Error creating user");return t.json({error:s},i)}}async function gr(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}=h(r,"Error getting users");return t.json({error:s},i)}}function P(t){return t.params}async function yr(t,e){try{let r=t.state.user,s=P(t),{userId:i}=s;g(r,"identity.user.get",{userId:i});let n=await e.getUserById(i);return n?t.json(n):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error getting user");return t.json({error:s},i)}}var vr={properties:{name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var Xi=new $(!0);async function wr(t,e){try{let r=t.state.user,s=P(t),{userId:i}=s,n=await S(t),o=Xi.test(vr,n);if(!o.success)return t.json({error:"Invalid input",details:o.errors},400);g(r,"identity.user.update",{userId:i});let{name:a,roles:c}=n,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}=h(r,"Error updating user");return t.json({error:s},i)}}async function Sr(t,e){try{let r=t.state.user,s=P(t),{userId:i}=s;return g(r,"identity.user.delete",{userId:i}),await e.deleteUser(i)?t.text("",204):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error deleting user");return t.json({error:s},i)}}async function xr(t,e){try{let r=t.state.user,s=await S(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:n,description:o,roles:a}=s,c=await e.addServiceAccount(n,o,a,i);return t.json(c,201)}catch(r){let{message:s,status:i}=h(r,"Error creating service account");return t.json({error:s},i)}}async function br(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}=h(r,"Error getting service accounts");return t.json({error:s},i)}}async function Cr(t,e){try{let r=t.state.user,s=P(t),{serviceAccountId:i}=s;g(r,"identity.service-account.get",{serviceAccountId:i});let n=await e.getServiceAccountById(i);return n?t.json(n):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error getting service account");return t.json({error:s},i)}}var Ir={properties:{name:{type:"string",minLength:1,maxLength:100},description:{type:"string",minLength:1,maxLength:500},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var Zi=new $(!0);async function Ar(t,e){try{let r=t.state.user,s=P(t),{serviceAccountId:i}=s,n=await S(t),o=Zi.test(Ir,n);if(!o.success)return t.json({error:"Invalid input",details:o.errors},400);g(r,"identity.service-account.update",{serviceAccountId:i});let{name:a,description:c,roles:l}=n,u=await e.updateServiceAccount(i,{name:a,description:c,roles:l});return u?t.json(u):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error updating service account");return t.json({error:s},i)}}async function kr(t,e){try{let r=t.state.user,s=P(t),{serviceAccountId:i}=s;return g(r,"identity.service-account.delete",{serviceAccountId:i}),await e.deleteServiceAccount(i)?t.text("",204):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error deleting service account");return t.json({error:s},i)}}async function Pr(t,e){try{let r=t.state.user,s=P(t),{serviceAccountId:i}=s;g(r,"identity.service-account.update",{serviceAccountId:i});let n=await e.rotateServiceAccountKey(i);return n?t.json({apiKey:n}):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error rotating service account key");return t.json({error:s},i)}}async function Er(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}=h(r,"Error getting roles");return t.json({error:s},i)}}async function Tr(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}=h(r,"Error getting role");return t.json({error:s},i)}}async function Rr(t,e){try{let r=t.state.user;g(r,"identity.role.create",{});let s=await S(t),{roleId:i,name:n,description:o,permissions:a,constraints:c}=s;if(!i||!n||!o)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,n,o,a,c);let l=await e.getRole(i);return t.json(l,201)}catch(r){let{message:s,status:i}=h(r,"Error creating role");return t.json({error:s},i)}}async function jr(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 S(t),{name:n,description:o,permissions:a,constraints:c}=i;await e.updateRole(s,{name:n,description:o,permissions:a,constraints:c});let l=await e.getRole(s);return t.json(l)}catch(r){let{message:s,status:i}=h(r,"Error updating role");return t.json({error:s},i)}}async function $r(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}=h(r,"Error deleting role");return t.json({error:s},i)}}async function Or(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}=h(r,"Error getting services");return t.json({error:s},i)}}async function Mr(t,e){try{let r=t.state.user,s=P(t),{serviceName:i}=s;g(r,"management.service.get",{serviceName:i});let n=await e.getService(i);return n?t.json(n):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error getting service");return t.json({error:s},i)}}var Ur={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 en=new $(!0);async function Hr(t,e){try{let r=t.state.user,s=await S(t),i=en.test(Ur,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}=h(r,"Error creating service");return t.json({error:s},i)}}var Dr={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 rn=new $(!0);async function Lr(t,e){try{let r=t.state.user,s=P(t),i=await S(t),n=i.name,o=rn.test(Dr,i);return o.success?(g(r,"management.service.update",{serviceName:n}),n!==s.serviceName?t.json({error:"Service name in body must match path parameter"},400):(await e.updateService(n,i),t.text("",204))):t.json({error:"Invalid input",details:o.errors},400)}catch(r){let{message:s,status:i}=h(r,"Error updating service");return t.json({error:s},i)}}async function Nr(t,e){try{let r=t.state.user,s=P(t),{serviceName:i}=s;return g(r,"management.service.delete",{serviceName:i}),await e.getService(i)?(await e.removeService(i),t.text("",204)):t.text("Not Found",404)}catch(r){let{message:s,status:i}=h(r,"Error deleting service");return t.json({error:s},i)}}async function qr(t,e){try{let r=t.state.user,s=P(t),{serviceName:i}=s;if(g(r,"management.service.start",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let o=await e.startService(i);return t.json({serviceName:i,isStarted:o})}catch(r){let{message:s,status:i}=h(r,"Error starting service");return t.json({error:s},i)}}async function Fr(t,e){try{let r=t.state.user,s=P(t),{serviceName:i}=s;if(g(r,"management.service.stop",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let o=await e.stopService(i);return t.json({serviceName:i,isStopped:o})}catch(r){let{message:s,status:i}=h(r,"Error stopping service");return t.json({error:s},i)}}async function _r(t,e){try{let r=t.state.user,s=P(t),{serviceName:i}=s;if(g(r,"management.service.get",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let o=new URL("http://127.0.0.1:3005/events");o.searchParams.set("service",i),t.query.startTime&&o.searchParams.set("startTime",t.query.startTime),t.query.endTime&&o.searchParams.set("endTime",t.query.endTime),t.query.level&&o.searchParams.set("level",t.query.level),t.query.limit&&o.searchParams.set("limit",t.query.limit),t.query.offset&&o.searchParams.set("offset",t.query.offset);let a=await fetch(o.toString());if(!a.ok)throw new _e(`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}=h(r,"Error getting service logs");return t.json({error:s},i)}}async function Br(t,e){try{let r=t.state.user,s=P(t),{serviceName:i}=s;if(g(r,"management.service.start",{serviceName:i}),!await e.getService(i))return t.text("Not Found",404);let o=await e.restartService(i);return t.json({serviceName:i,restarted:o})}catch(r){let{message:s,status:i}=h(r,"Error restarting service");return t.json({error:s},i)}}function Vr(t,e,r,s,i){let n=t.find(c=>c.service===e);if(!n){let c=new Error(`Function bindings do not include access to service: ${e}`);throw c.cause={statusCode:403},c}if(!n.permissions||n.permissions.length===0)return;for(let c of n.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 o=i?`:${i}`:"",a=new Error(`Function bindings do not allow: ${e}.${r}.${s}${o}`);throw a.cause={statusCode:403},a}import{readFileSync as sn,existsSync as nn}from"node:fs";function Xe(){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||!nn(t))return e;try{let r=sn(t,"utf-8");return JSON.parse(r)}catch(r){return console.error("[loadRuntimeConfig] Failed to load runtime config:",r),e}}async function v(t,e,r,s,i,n,o){if(!e)return null;let a=t.headers["x-molnos-service-token"];if(a){let u=Xe();if(u.internalServiceSecret&&a===u.internalServiceSecret)return null}let c=t.state.user;if(!c){let u=t.headers.authorization;if(!u){let m=new Error("Unauthorized: No authentication provided");throw m.cause={statusCode:401},m}let p=u.replace(/^Bearer\s+/i,"");if(c=await e.getUserFromToken(p),!c){let m=new Error("Unauthorized: Invalid token");throw m.cause={statusCode:401},m}}g(c,r,{});let l=t.headers["x-function-bindings"];if(l)try{let u=Array.isArray(l)?l[0]:l,p=JSON.parse(u);Vr(p,s,i,n,o)}catch(u){if(u.cause?.statusCode===403)throw u;let p=new Error("Invalid function bindings header");throw p.cause={statusCode:400},p}return c}async function Gr(t,e,r){try{let s=await S(t),i=t.state.requestingIdentity;if(!i)return t.json({error:"Authentication required"},401);let{id:n,name:o,description:a,redirectUris:c,metadata:l}=s;if(!o||!c)return t.json({error:"Missing required fields: name and redirectUris are required"},400);await v(t,r,"applications.application.create","applications","application","create",o);let u={id:n,name:o,description:a,redirectUris:Array.isArray(c)?c:[c],metadata:l,owners:[i.id]},p=await e.createApplication(u,i.id);return t.json(p,201)}catch(s){let{message:i,status:n}=h(s,"Error creating application");return t.json({error:i},n)}}async function zr(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 v(t,r,"applications.application.read","applications","application","read",s);let n=await e.getApplication(s,i?.id);return t.json(n,200)}catch(s){let{message:i,status:n}=h(s,"Error retrieving application");return t.json({error:i},n)}}async function Wr(t,e,r){try{let s=t.state.requestingIdentity;if(!s)return t.json({error:"Authentication required"},401);await v(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:n}=h(s,"Error listing applications");return t.json({error:i},n)}}async function Jr(t,e,r){try{let s=t.params.id,i=await S(t),n=t.state.requestingIdentity;if(!n)return t.json({error:"Authentication required"},401);if(!s)return t.json({error:"Application ID is required"},400);await v(t,r,"applications.application.update","applications","application","update",s);let o=await e.updateApplication(s,i,n.id);return t.json(o,200)}catch(s){let{message:i,status:n}=h(s,"Error updating application");return t.json({error:i},n)}}async function Kr(t,e,r){try{let s=t.params.id,i=t.state.requestingIdentity;return i?s?(await v(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:n}=h(s,"Error deleting application");return t.json({error:i},n)}}async function Xr(t,e,r){try{let s=await S(t),{name:i,description:n,schema:o}=s;if(!i||!o)return t.json({error:"Missing required fields: name and schema are required"},400);await v(t,r,"schemas.schema.create","schemas","schema","create",i);let a=await e.createSchema({name:i,description:n,schema:o});return t.json(a,201)}catch(s){let{message:i,status:n}=h(s,"Error creating schema");return t.json({error:i},n)}}async function At(t,e,r){try{let s=t.params.name,i=t.params.version;if(!s)return t.json({error:"Schema name is required"},400);await v(t,r,"schemas.schema.read","schemas","schema","read",s);let n=i?parseInt(i,10):void 0,o=await e.getSchema(s,n);return t.json(o,200)}catch(s){let{message:i,status:n}=h(s,"Error retrieving schema");return t.json({error:i},n)}}async function Yr(t,e,r){try{await v(t,r,"schemas.schema.list","schemas","schema","list");let s=await e.listSchemas();return t.json({schemas:s,total:s.length},200)}catch(s){let{message:i,status:n}=h(s,"Error listing schemas");return t.json({error:i},n)}}async function Zr(t,e,r){try{let s=t.params.name,i=await S(t);if(!s)return t.json({error:"Schema name is required"},400);if(!i.schema)return t.json({error:"Missing required field: schema is required for update"},400);await v(t,r,"schemas.schema.update","schemas","schema","update",s);let n=await e.updateSchema(s,{description:i.description,schema:i.schema});return t.json(n,200)}catch(s){let{message:i,status:n}=h(s,"Error updating schema");return t.json({error:i},n)}}async function Qr(t,e,r){try{let s=t.params.name;return s?(await v(t,r,"schemas.schema.delete","schemas","schema","delete",s),await e.deleteSchema(s),t.json({success:!0,message:"Schema deleted"},200)):t.json({error:"Schema name is required"},400)}catch(s){let{message:i,status:n}=h(s,"Error deleting schema");return t.json({error:i},n)}}async function es(t,e,r){try{await v(t,r,"contexts.context.get","contexts","context","get");let i=e.listContexts().map(n=>{let o=e.getContextResources(n.name);return{...n,resourceCount:{functions:o.functions.length,databases:o.databases.length,storage:o.storage.length,sites:o.sites.length,users:o.users.length,serviceAccounts:o.serviceAccounts.length}}});return t.json({success:!0,contexts:i},200)}catch(s){let{message:i,status:n}=h(s,"Error listing contexts");return t.json({error:i},n)}}async function ts(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);await v(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:n}=h(s,"Error getting context");return t.json({error:i},n)}}var on=new $(!0),an={properties:{name:{type:"string",minLength:1,maxLength:64},intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},required:["name"],additionalProperties:!1};async function rs(t,e,r){try{let s=await S(t),i=on.test(an,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);await v(t,r,"contexts.context.create","contexts","context","create");let{name:n,intent:o,attributes:a}=s,c=await e.createContext({name:n,intent:o,attributes:a});return t.json({success:!0,context:c},201)}catch(s){let{message:i,status:n}=h(s,"Error creating context");return t.json({error:i},n)}}var cn=new $(!0),ln={properties:{intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},additionalProperties:!1};async function ss(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);let i=await S(t),n=cn.test(ln,i||{});if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);await v(t,r,"contexts.context.update","contexts","context","update",s);let{intent:o,attributes:a}=i||{},c=await e.updateContext(s,{intent:o,attributes:a});return t.json({success:!0,context:c},200)}catch(s){let{message:i,status:n}=h(s,"Error updating context");return t.json({error:i},n)}}async function is(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 v(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:n}=h(s,"Error deleting context");return t.json({error:i},n)}}async function ns(t,e,r,s){try{let i=t.params.contextName;if(!i)return t.json({error:"contextName parameter is required"},400);await v(t,r,"contexts.context.delete-resources","contexts","context","delete-resources",i);let n=t.headers.authorization,o=n?.startsWith("Bearer ")?n.slice(7):n,a=s(o),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 p=await a.functions.list();for(let m of c.functions)try{let w=p.find(b=>b.id===m);w&&(await a.functions.delete(m),await e.unregisterResource(i,"function",m),l.deleted.push({type:"function",name:w.name}))}catch(w){l.errors.push({type:"function",name:m,error:w.message||"Unknown error"}),l.success=!1}}if(a.databases)for(let p of c.databases)try{await a.databases.deleteTable(p),await e.unregisterResource(i,"database",p),l.deleted.push({type:"database",name:p})}catch(m){l.errors.push({type:"database",name:p,error:m.message||"Unknown error"}),l.success=!1}if(a.storage)for(let p of c.storage)try{await a.storage.deleteBucket(p),await e.unregisterResource(i,"storage",p),l.deleted.push({type:"storage",name:p})}catch(m){l.errors.push({type:"storage",name:p,error:m.message||"Unknown error"}),l.success=!1}if(a.sites)for(let p of c.sites)try{await a.sites.deleteProject(p),await e.unregisterResource(i,"site",p),l.deleted.push({type:"site",name:p})}catch(m){l.errors.push({type:"site",name:p,error:m.message||"Unknown error"}),l.success=!1}if(a.applications){let p=await a.applications.list();for(let m of c.applications)try{let w=p.find(b=>b.id===m);w&&(await a.applications.delete(m),await e.unregisterResource(i,"application",m),l.deleted.push({type:"application",name:w.name}))}catch(w){l.errors.push({type:"application",name:m,error:w.message||"Unknown error"}),l.success=!1}}if(a.identity)for(let p of c.users)try{let m=await a.identity.getUser(p);m&&(await a.identity.deleteUser(m.id),await e.unregisterResource(i,"user",p),l.deleted.push({type:"user",name:p}))}catch(m){l.errors.push({type:"user",name:p,error:m.message||"Unknown error"}),l.success=!1}if(a.identity)for(let p of c.serviceAccounts)try{let m=await a.identity.getServiceAccount(p);m&&(await a.identity.deleteServiceAccount(m.id),await e.unregisterResource(i,"serviceAccount",p),l.deleted.push({type:"serviceAccount",name:p}))}catch(m){l.errors.push({type:"serviceAccount",name:p,error:m.message||"Unknown error"}),l.success=!1}l.summary.deletedCount=l.deleted.length,l.summary.failedCount=l.errors.length;let u=l.success?200:207;return t.json(l,u)}catch(i){let{message:n,status:o}=h(i,"Error deleting context resources");return t.json({error:n},o)}}async function os(t,e,r){try{await v(t,r,"iac.config.get","iac","config","get");let s=await S(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,o=e().validate(i);return t.json({success:!0,valid:o.valid,errors:o.errors,warnings:o.warnings},200)}catch(s){let{message:i,status:n}=h(s,"Error validating IaC");return t.json({error:i},n)}}async function as(t,e,r){try{await v(t,r,"iac.config.create","iac","config","create");let s=await S(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,n=t.headers.authorization,o=n?.startsWith("Bearer ")?n.slice(7):n,a=e(o),c=t.query?.prune==="true",l=await a.apply(i,{prune:c}),u=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},u)}catch(s){let{message:i,status:n}=h(s,"Error applying IaC");return t.json({error:i},n)}}var Y="default",Ye=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(n=>n.name===r))throw new G(`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 q(`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(o=>o.name===e);if(s===-1)throw new q(`Context '${e}' not found`);let i=this.contexts[s],n={...i,intent:r.intent??i.intent,attributes:r.attributes??i.attributes,updatedAt:new Date().toISOString()};return this.contexts[s]=n,await this.saveState(),n}async deleteContext(e){let r=this.contexts.findIndex(s=>s.name===e);if(r===-1)throw new q(`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||Y;return this.contextExists(r)||await this.createContext({name:r,intent:r===Y?"Default context for resources without explicit context assignment.":void 0}),r}async registerResource(e,r,s){await this.ensureContext(e),this.resourceMappings.find(n=>n.context===e&&n.resourceType===r&&n.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:[],schemas:[]};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;case"schema":s.schemas.push(i.resourceName);break}return s}getResourceContext(e,r){return this.resourceMappings.find(i=>i.resourceType===e&&i.resourceName===r)?.context||Y}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 cs(t,e,r){try{await v(t,r,"iac.config.get","iac","config","get");let s=await S(t);if(!s)return t.json({error:"Request body is required"},400);let i=s,n=t.headers.authorization,o=n?.startsWith("Bearer ")?n.slice(7):n,a=e(o),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||Y,toCreate:l.toCreate,toUpdate:l.toUpdate,toDelete:l.toDelete,unchanged:l.unchanged,warnings:c.warnings},200)}catch(s){let{message:i,status:n}=h(s,"Error generating IaC diff");return t.json({error:i},n)}}var un=new $(!0),dn={type:"object",properties:{intent:{type:"string",minLength:1,maxLength:1e4},intentAttributes:{type:"object"},resourceTypes:{type:"array",items:{type:"string",enum:["functions","sites"]}},files:{type:"array",items:{type:"object",properties:{path:{type:"string"},content:{type:"string"}},required:["path","content"]}},iacConfig:{type:"object"},iterationFeedback:{type:"string"},previousAttemptId:{type:"string"},providerOverride:{type:"string"},modelOverride:{type:"string"},userApiKey:{type:"string"}},additionalProperties:!1};async function ls(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"Context name is required"},400);await v(t,r,"ai.generation.generate","ai","generation","generate",s);let i=await S(t),n=un.test(dn,i);if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);if(!e.isAvailable())return t.json({error:"AI generation is not enabled. Please configure AI in molnos.config.json or provide your own API key."},503);let o=null;if(i.previousAttemptId&&(o=e.getGeneration(i.previousAttemptId),!o))return t.json({error:"Previous generation not found"},404);let a=await e.generate({contextName:s,intent:i.intent,intentAttributes:i.intentAttributes,resourceTypes:i.resourceTypes,files:i.files,iacConfig:i.iacConfig,iterationFeedback:i.iterationFeedback,previousAttempt:o||void 0,providerOverride:i.providerOverride,modelOverride:i.modelOverride,userApiKey:i.userApiKey});return t.json({success:!0,generation:a},201)}catch(s){let{message:i,status:n}=h(s,"Error generating code");return t.json({error:i},n)}}async function us(t,e,r){try{let s=t.params.generationId;if(!s)return t.json({error:"Generation ID is required"},400);await v(t,r,"ai.generation.read","ai","generation","read",s);let i=e.getGeneration(s);return i?t.json({success:!0,generation:i}):t.json({error:"Generation not found or expired"},404)}catch(s){let{message:i,status:n}=h(s,"Error retrieving generation");return t.json({error:i},n)}}async function ds(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"Context name is required"},400);await v(t,r,"ai.generation.read","ai","generation","read",s);let i=e.listGenerations(s);return t.json({success:!0,generations:i})}catch(s){let{message:i,status:n}=h(s,"Error listing generations");return t.json({error:i},n)}}async function ps(t,e,r){try{let s=t.params.generationId;if(!s)return t.json({error:"Generation ID is required"},400);await v(t,r,"ai.generation.apply","ai","generation","apply",s);let i=t.headers.authorization?.replace("Bearer ",""),n=await e.applyGeneration(s,i);if(!n.success)return t.json({error:"Failed to apply IAC configuration",details:n.errors},400);let o=e.getGeneration(s);return t.json({success:!0,generation:o,applyResult:n})}catch(s){let{message:i,status:n}=h(s,"Error applying generation");return t.json({error:i},n)}}async function ms(t,e,r){try{let s=t.params.generationId;return s?(await v(t,r,"ai.generation.discard","ai","generation","discard",s),e.getGeneration(s)?e.discardGeneration(s)?t.json({success:!0,message:"Generation discarded"}):t.json({error:"Failed to discard generation"},500):t.json({error:"Generation not found or expired"},404)):t.json({error:"Generation ID is required"},400)}catch(s){let{message:i,status:n}=h(s,"Error discarding generation");return t.json({error:i},n)}}async function hs(t,e,r){try{let s=t.params.generationId;return s?(await v(t,r,"ai.generation.delete","ai","generation","delete",s),e.getGeneration(s)?e.deleteGeneration(s)?t.json({success:!0,message:"Generation deleted"}):t.json({error:"Failed to delete generation"},500):t.json({error:"Generation not found or expired"},404)):t.json({error:"Generation ID is required"},400)}catch(s){let{message:i,status:n}=h(s,"Error deleting generation");return t.json({error:i},n)}}import{promises as Ze}from"node:fs";import{join as kt,resolve as mn}from"node:path";var fs={$schema:"https://json-schema.org/draft-07/schema#",$id:"https://schemas.molnos.cloud/schema-iac-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"],default:"1",description:'IaC schema version (defaults to "1" if not specified)'},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"},schemas:{type:"object",description:"Schema registry declarations"}}},identities:{type:"object",description:"Identity declarations",properties:{users:{type:"object",description:"User declarations"},serviceAccounts:{type:"object",description:"Service account declarations"}}}},required:[]};var hn=new $(!0),Qe=class{contextService;clients;constructor(e,r){this.contextService=e,this.clients=r}async loadConfiguration(e){let r=mn(e);try{let s=await Ze.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=[];e.version||(e.version="1");let i=hn.test(fs,e);if(!i.success)for(let n of i.errors||[])r.push({path:n.key||"",message:n.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[n,o]of Object.entries(e.resources.functions))if(o.bindings)for(let a of o.bindings){let c=a.resource;c.includes(":")||(a.service==="databases"?e.resources?.databases?.[c]||s.push({path:`resources.functions.${n}.bindings`,message:`Database '${c}' is not declared in this configuration`}):a.service==="storage"&&(e.resources?.storage?.[c]||s.push({path:`resources.functions.${n}.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||Y,created:[],updated:[],unchanged:[],deleted:[],errors:s.errors.map(o=>({type:"validation",name:o.path,error:o.message}))};let i=e.context?.name||Y,n={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[o]of Object.entries(e.resources.databases))try{await this.clients.databases.tableExists(o)?n.unchanged.push({type:"database",name:o}):(await this.clients.databases.createTable(o),await this.contextService.registerResource(i,"database",o),n.created.push({type:"database",name:o}))}catch(a){n.errors.push({type:"database",name:o,error:a.message||"Unknown error"}),n.success=!1}if(e.resources?.storage&&this.clients.storage)for(let[o,a]of Object.entries(e.resources.storage))try{await this.clients.storage.bucketExists(o)?await this.clients.storage.isBucketPublic(o)!==(a.public||!1)?(await this.clients.storage.updateBucket(o,{public:a.public}),n.updated.push({type:"storage",name:o})):n.unchanged.push({type:"storage",name:o}):(await this.clients.storage.createBucket(o,a.public||!1),await this.contextService.registerResource(i,"storage",o),n.created.push({type:"storage",name:o}))}catch(c){n.errors.push({type:"storage",name:o,error:c.message||"Unknown error"}),n.success=!1}if(e.resources?.functions&&this.clients.functions)for(let[o,a]of Object.entries(e.resources.functions))try{let c;if(a.code)c=a.code;else if(a.source){let u=r.basePath?kt(r.basePath,a.source):a.source;try{c=await Ze.readFile(u,"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(o);if(l)await this.clients.functions.update(l.id,{code:c,methods:a.methods,bindings:a.bindings,triggers:a.triggers,allowUnauthenticated:a.allowUnauthenticated,passAllHeaders:a.passAllHeaders}),n.updated.push({type:"function",name:o});else{let u=await this.clients.functions.deploy(o,c,{id:a.id,methods:a.methods,bindings:a.bindings,triggers:a.triggers,allowUnauthenticated:a.allowUnauthenticated,passAllHeaders:a.passAllHeaders});await this.contextService.registerResource(i,"function",u.id),n.created.push({type:"function",name:o})}}catch(c){n.errors.push({type:"function",name:o,error:c.message||"Unknown error"}),n.success=!1}if(e.resources?.sites&&this.clients.sites)for(let[o,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 u=r.basePath?kt(r.basePath,a.source):a.source;if(c=await this.loadSiteFiles(u),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(o);await this.clients.sites.uploadProject(c,o),await this.contextService.registerResource(i,"site",o),l?n.updated.push({type:"site",name:o}):n.created.push({type:"site",name:o})}catch(c){n.errors.push({type:"site",name:o,error:c.message||"Unknown error"}),n.success=!1}if(e.identities?.users&&this.clients.identity)for(let[o,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}),n.updated.push({type:"user",name:a.email})):(await this.clients.identity.createUser(a.email,o,a.roles,{id:a.id}),await this.contextService.registerResource(i,"user",a.email),n.created.push({type:"user",name:a.email}))}catch(c){n.errors.push({type:"user",name:a.email,error:c.message||"Unknown error"}),n.success=!1}if(e.identities?.serviceAccounts&&this.clients.identity)for(let[o,a]of Object.entries(e.identities.serviceAccounts))try{let c=await this.clients.identity.getServiceAccount(o);c?(await this.clients.identity.updateServiceAccount(c.id,{roles:a.roles,description:a.description}),n.updated.push({type:"serviceAccount",name:o})):(await this.clients.identity.createServiceAccount(o,a.roles,a.description,{id:a.id}),await this.contextService.registerResource(i,"serviceAccount",o),n.created.push({type:"serviceAccount",name:o}))}catch(c){n.errors.push({type:"serviceAccount",name:o,error:c.message||"Unknown error"}),n.success=!1}if(e.resources?.applications&&this.clients.applications)for(let[o,a]of Object.entries(e.resources.applications))try{let c=await this.clients.applications.get(o);if(c)await this.clients.applications.update(c.id,{description:a.description,redirectUris:a.redirectUris}),n.updated.push({type:"application",name:o});else{let l=await this.clients.applications.create(o,a.description,a.redirectUris,{id:a.id});await this.contextService.registerResource(i,"application",l.id),n.created.push({type:"application",name:o})}}catch(c){n.errors.push({type:"application",name:o,error:c.message||"Unknown error"}),n.success=!1}if(e.resources?.schemas&&this.clients.schemas)for(let[o,a]of Object.entries(e.resources.schemas))try{await this.clients.schemas.get(o)?(await this.clients.schemas.update(o,a.schema,a.description),n.updated.push({type:"schema",name:o})):(await this.clients.schemas.create(o,a.schema,a.description),await this.contextService.registerResource(i,"schema",o),n.created.push({type:"schema",name:o}))}catch(c){n.errors.push({type:"schema",name:o,error:c.message||"Unknown error"}),n.success=!1}if(r.prune){let o=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 o.functions){let u=c.find(p=>p.id===l);if(u&&!a.includes(u.name))try{await this.clients.functions.delete(l),await this.contextService.unregisterResource(i,"function",l),n.deleted.push({type:"function",name:u.name})}catch(p){n.errors.push({type:"function",name:u.name,error:`Failed to delete: ${p.message||"Unknown error"}`}),n.success=!1}}}if(this.clients.databases){let a=Object.keys(e.resources?.databases||{});for(let c of o.databases)if(!a.includes(c))try{await this.clients.databases.deleteTable(c),await this.contextService.unregisterResource(i,"database",c),n.deleted.push({type:"database",name:c})}catch(l){n.errors.push({type:"database",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),n.success=!1}}if(this.clients.storage){let a=Object.keys(e.resources?.storage||{});for(let c of o.storage)if(!a.includes(c))try{await this.clients.storage.deleteBucket(c),await this.contextService.unregisterResource(i,"storage",c),n.deleted.push({type:"storage",name:c})}catch(l){n.errors.push({type:"storage",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),n.success=!1}}if(this.clients.sites){let a=Object.keys(e.resources?.sites||{});for(let c of o.sites)if(!a.includes(c))try{await this.clients.sites.deleteProject(c),await this.contextService.unregisterResource(i,"site",c),n.deleted.push({type:"site",name:c})}catch(l){n.errors.push({type:"site",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),n.success=!1}}if(this.clients.applications){let a=Object.keys(e.resources?.applications||{}),c=await this.clients.applications.list();for(let l of o.applications){let u=c.find(p=>p.id===l);if(u&&!a.includes(u.name))try{await this.clients.applications.delete(l),await this.contextService.unregisterResource(i,"application",l),n.deleted.push({type:"application",name:u.name})}catch(p){n.errors.push({type:"application",name:u.name,error:`Failed to delete: ${p.message||"Unknown error"}`}),n.success=!1}}}if(this.clients.identity){let a=Object.values(e.identities?.users||{}).map(c=>c.email);for(let c of o.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),n.deleted.push({type:"user",name:c}))}catch(l){n.errors.push({type:"user",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),n.success=!1}}if(this.clients.identity){let a=Object.keys(e.identities?.serviceAccounts||{});for(let c of o.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),n.deleted.push({type:"serviceAccount",name:c}))}catch(l){n.errors.push({type:"serviceAccount",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),n.success=!1}}if(this.clients.schemas){let a=Object.keys(e.resources?.schemas||{});for(let c of o.schemas)if(!a.includes(c))try{await this.clients.schemas.delete(c),await this.contextService.unregisterResource(i,"schema",c),n.deleted.push({type:"schema",name:c})}catch(l){n.errors.push({type:"schema",name:c,error:`Failed to delete: ${l.message||"Unknown error"}`}),n.success=!1}}}return n}async loadSiteFiles(e,r=""){let s=[];try{let i=await Ze.readdir(e,{withFileTypes:!0});for(let n of i){let o=kt(e,n.name),a=r?`${r}/${n.name}`:n.name;if(n.isDirectory()){let c=await this.loadSiteFiles(o,a);s.push(...c)}else if(n.isFile()){let l=(await Ze.readFile(o)).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||Y,s=[],i=[],n=[],o=[],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)?o.push({type:"database",name:l}):s.push({type:"database",name:l});for(let l of a.databases)c.includes(l)||n.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 p=e.resources?.storage?.[l];await this.clients.storage.isBucketPublic(l)!==(p?.public||!1)?i.push({type:"storage",name:l}):o.push({type:"storage",name:l})}else s.push({type:"storage",name:l});for(let l of a.storage)c.includes(l)||n.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)||n.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)||n.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)||n.push({type:"application",name:l})}if(this.clients.schemas){let c=Object.keys(e.resources?.schemas||{});for(let l of c)await this.clients.schemas.get(l)?i.push({type:"schema",name:l}):s.push({type:"schema",name:l});for(let l of a.schemas)c.includes(l)||n.push({type:"schema",name:l})}return{toCreate:s,toUpdate:i,toDelete:n,unchanged:o}}};var Z=class{constructor(e,r){this.baseUrl=e;this.authToken=r}async request(e,r,s,i){let n=`${this.baseUrl}${r}`;if(i){let p=new URLSearchParams(i);n+=`?${p.toString()}`}let o={"Content-Type":"application/json"};this.authToken&&(o.Authorization=`Bearer ${this.authToken}`);let a={method:e,headers:o};s&&(a.body=JSON.stringify(s));let c=await fetch(n,a),l=c.headers.get("content-type"),u;if(l?.includes("application/json")?u=await c.json():u=await c.text(),!c.ok){let p=typeof u=="object"&&u.error?u.error:typeof u=="string"?u:JSON.stringify(u);throw new Error(p)}return u}},Pt=class extends Z{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)}},Et=class extends Z{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}}},Tt=class extends Z{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,triggers:s.triggers,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||[]}},Rt=class extends Z{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||[]}},jt=class extends Z{async createUser(e,r,s,i){let n=await this.request("POST","/identity/users",{email:e,name:r,roles:s,id:i?.id});return n.user||n}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 n=await this.request("POST","/identity/service-accounts",{name:e,roles:r,description:s,id:i?.id});return n.serviceAccount||n}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||[]}},$t=class extends Z{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||[]}},Ot=class extends Z{async create(e,r,s){return await this.request("POST","",{name:e,schema:r,description:s})}async get(e){try{return await this.request("GET",`/${e}`)}catch{return null}}async update(e,r,s){return await this.request("PUT",`/${e}`,{schema:r,description:s})}async delete(e){await this.request("DELETE",`/${e}`)}async list(){return(await this.request("GET","")).schemas||[]}};function Mt(t){let{serviceUrls:e,authToken:r}=t,s={};return e.databases&&(s.databases=new Pt(e.databases,r)),e.storage&&(s.storage=new Et(e.storage,r)),e.functions&&(s.functions=new Tt(e.functions,r)),e.sites&&(s.sites=new Rt(e.sites,r)),e.identity&&(s.identity=new jt(e.identity,r)),e.applications&&(s.applications=new $t(e.applications,r)),e.schemas&&(s.schemas=new Ot(e.schemas,r)),s}import ys from"crypto";var gs="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var fn=128,de,ye,gn=t=>{!de||de.length<t?(de=Buffer.allocUnsafe(t*fn),ys.randomFillSync(de),ye=0):ye+t>de.length&&(ys.randomFillSync(de),ye=0),ye+=t};var vs=(t=21)=>{gn(t|=0);let e="";for(let r=ye-t;r<ye;r++)e+=gs[de[r]&63];return e};var et=class{generations=new Map;cleanupInterval=null;ttlHours;constructor(e=24){this.ttlHours=e}start(){this.cleanupInterval||(this.cleanupInterval=setInterval(()=>{this.cleanup()},3600*1e3))}stop(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null)}store(e){let r=vs(12),s=new Date().toISOString(),i=new Date(Date.now()+this.ttlHours*60*60*1e3).toISOString(),n={id:r,timestamp:s,expiresAt:i,...e};return this.generations.set(r,n),n}get(e){let r=this.generations.get(e);return r?new Date(r.expiresAt)<new Date?(this.generations.delete(e),null):r:null}updateStatus(e,r){let s=this.get(e);return s?(s.status=r,this.generations.set(e,s),!0):!1}delete(e){return this.generations.delete(e)}listByContext(e){let r=[];for(let s of this.generations.values())s.contextId===e&&new Date(s.expiresAt)>=new Date&&r.push(s);return r.sort((s,i)=>new Date(i.timestamp).getTime()-new Date(s.timestamp).getTime())}listPendingByContext(e){return this.listByContext(e).filter(r=>r.status==="pending")}getStats(){let e=0,r=0,s=0,i={};for(let n of this.generations.values())new Date(n.expiresAt)<new Date||(n.status==="pending"?e++:n.status==="applied"?r++:n.status==="discarded"&&s++,i[n.contextId]=(i[n.contextId]||0)+1);return{total:e+r+s,pending:e,applied:r,discarded:s,byContext:i}}cleanup(){let e=new Date,r=[];for(let[s,i]of this.generations.entries())new Date(i.expiresAt)<e&&r.push(s);for(let s of r)this.generations.delete(s);r.length>0&&console.log(`[GenerationStorage] Cleaned up ${r.length} expired generations`)}clear(){this.generations.clear()}size(){return this.generations.size}};var tt=class{constructor(e){this.config=e;if(!e.apiKey)throw new Error("Anthropic API key is required");e.model||(this.config.model="claude-sonnet-4-5"),e.baseUrl||(this.config.baseUrl="https://api.anthropic.com"),e.maxTokens||(this.config.maxTokens=32e3)}name="anthropic";async validateConfig(){try{let e=await fetch(`${this.config.baseUrl}/v1/messages`,{method:"POST",headers:{"x-api-key":this.config.apiKey,"anthropic-version":"2023-06-01","content-type":"application/json"},body:JSON.stringify({model:this.config.model,max_tokens:1,messages:[{role:"user",content:"test"}]})});return e.ok||e.status===400}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:n}=e,o={...this.config,...n},a=this.transformMessages(r),c={model:o.model,max_tokens:o.maxTokens||32e3,messages:a};i&&(c.system=i),s&&s.length>0&&(c.tools=this.transformTools(s)),o.temperature!==void 0&&(c.temperature=o.temperature);let l=await fetch(`${o.baseUrl}/v1/messages`,{method:"POST",headers:{"x-api-key":o.apiKey,"anthropic-version":"2023-06-01","content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let p=await l.text();throw new Error(`Anthropic API error (${l.status}): ${p}`)}let u=await l.json();return this.transformResponse(u)}transformMessages(e){return e.map(r=>Array.isArray(r.content)?{role:r.role==="system"?"user":r.role,content:r.content}:{role:r.role==="system"?"user":r.role,content:r.content})}transformTools(e){return e.map(r=>({name:r.name,description:r.description,input_schema:r.input_schema}))}transformResponse(e){let r={content:"",stopReason:e.stop_reason},s=e.content.filter(n=>n.type==="text");r.content=s.map(n=>n.text).join(`
115
+ `);let i=e.content.filter(n=>n.type==="tool_use");return i.length>0&&(r.toolCalls=i.map(n=>({id:n.id,name:n.name,input:n.input}))),e.usage&&(r.usage={inputTokens:e.usage.input_tokens||0,outputTokens:e.usage.output_tokens||0,totalTokens:(e.usage.input_tokens||0)+(e.usage.output_tokens||0)}),r}};var rt=class{constructor(e){this.config=e;if(!e.apiKey)throw new Error("OpenAI API key is required");e.model||(this.config.model="gpt-4-turbo"),e.baseUrl||(this.config.baseUrl="https://api.openai.com/v1"),e.maxTokens||(this.config.maxTokens=32e3)}name="openai";async validateConfig(){try{return(await fetch(`${this.config.baseUrl}/models`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`}})).ok}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:n}=e,o={...this.config,...n},a=this.transformMessages(r,i),c={model:o.model,max_tokens:o.maxTokens||32e3,messages:a};s&&s.length>0&&(c.tools=this.transformTools(s),c.tool_choice="auto"),o.temperature!==void 0&&(c.temperature=o.temperature);let l=await fetch(`${o.baseUrl}/chat/completions`,{method:"POST",headers:{Authorization:`Bearer ${o.apiKey}`,"content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let p=await l.text();throw new Error(`OpenAI API error (${l.status}): ${p}`)}let u=await l.json();return this.transformResponse(u)}transformMessages(e,r){let s=[];r&&s.push({role:"system",content:r});for(let i of e)if(Array.isArray(i.content)){let n=i.content.filter(c=>c.type==="tool_use");if(n.length>0&&i.role==="assistant"){s.push({role:"assistant",content:null,tool_calls:n.map(c=>({id:c.tool_use_id||`call_${Date.now()}`,type:"function",function:{name:c.tool_name||"",arguments:JSON.stringify(c.tool_input||{})}}))});continue}let o=i.content.filter(c=>c.type==="tool_result");if(o.length>0&&i.role==="user"){for(let c of o)s.push({role:"tool",tool_call_id:c.tool_use_id||"",content:c.content||""});continue}let a=i.content.filter(c=>c.type==="text");a.length>0&&s.push({role:i.role==="system"?"system":i.role,content:a.map(c=>c.text).join(`
116
+ `)})}else s.push({role:i.role==="system"?"system":i.role,content:i.content});return s}transformTools(e){return e.map(r=>({type:"function",function:{name:r.name,description:r.description,parameters:r.input_schema}}))}transformResponse(e){let r=e.choices[0],s=r.message,i={content:s.content||"",stopReason:r.finish_reason};return s.tool_calls&&s.tool_calls.length>0&&(i.toolCalls=s.tool_calls.map(n=>({id:n.id,name:n.function.name,input:JSON.parse(n.function.arguments)}))),e.usage&&(i.usage={inputTokens:e.usage.prompt_tokens||0,outputTokens:e.usage.completion_tokens||0,totalTokens:e.usage.total_tokens||0}),i}};var st=class{constructor(e){this.config=e;e.endpoint||(this.config.endpoint="http://localhost:11434"),e.model||(this.config.model="codellama:13b"),e.maxTokens||(this.config.maxTokens=32e3)}name="ollama";async validateConfig(){try{let e=await fetch(`${this.config.endpoint}/api/tags`);return e.ok?((await e.json()).models||[]).some(n=>n.name===this.config.model||n.name.startsWith(this.config.model)):!1}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:n}=e,o={...this.config,...n},a=this.transformMessages(r,i),c={model:o.model,messages:a,stream:!1};o.maxTokens&&(c.options={num_predict:o.maxTokens}),o.temperature!==void 0&&(c.options={...c.options,temperature:o.temperature}),s&&s.length>0&&(c.tools=this.transformTools(s));let l=await fetch(`${o.endpoint}/api/chat`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let p=await l.text();throw new Error(`Ollama API error (${l.status}): ${p}`)}let u=await l.json();return this.transformResponse(u)}transformMessages(e,r){let s=[];r&&s.push({role:"system",content:r});for(let i of e)if(Array.isArray(i.content)){let n=i.content.filter(c=>c.type==="tool_use");if(n.length>0&&i.role==="assistant"){let c=n.map(l=>`Calling tool: ${l.tool_name}
117
117
  Input: ${JSON.stringify(l.tool_input,null,2)}`).join(`
118
118
 
119
- `);s.push({role:"assistant",content:c});continue}let n=i.content.filter(c=>c.type==="tool_result");if(n.length>0&&i.role==="user"){let c=n.map(l=>`Tool result:
119
+ `);s.push({role:"assistant",content:c});continue}let o=i.content.filter(c=>c.type==="tool_result");if(o.length>0&&i.role==="user"){let c=o.map(l=>`Tool result:
120
120
  ${l.content}`).join(`
121
121
 
122
122
  `);s.push({role:"user",content:c});continue}let a=i.content.filter(c=>c.type==="text");a.length>0&&s.push({role:i.role==="system"?"system":i.role,content:a.map(c=>c.text).join(`
123
- `)})}else s.push({role:i.role==="system"?"system":i.role,content:i.content});return s}transformTools(e){return e.map(r=>({type:"function",function:{name:r.name,description:r.description,parameters:r.input_schema}}))}transformResponse(e){let r=e.message||{},s={content:r.content||"",stopReason:e.done?"end_turn":"max_tokens"};return r.tool_calls&&r.tool_calls.length>0&&(s.toolCalls=r.tool_calls.map((i,o)=>({id:i.id||`call_${Date.now()}_${o}`,name:i.function?.name||"",input:typeof i.function?.arguments=="string"?JSON.parse(i.function.arguments):i.function?.arguments||{}}))),(e.eval_count||e.prompt_eval_count)&&(s.usage={inputTokens:e.prompt_eval_count||0,outputTokens:e.eval_count||0,totalTokens:(e.prompt_eval_count||0)+(e.eval_count||0)}),s}};var et=class{constructor(e){this.config=e;if(!e.apiKey)throw new Error("evroc Think API key is required");e.model||(this.config.model="openai/gpt-oss-120b"),e.baseUrl||(this.config.baseUrl="https://models.think.cloud.evroc.com/v1"),e.maxTokens||(this.config.maxTokens=32e3)}name="evroc";async validateConfig(){try{return(await fetch(`${this.config.baseUrl}/models`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`}})).ok}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:o}=e,n={...this.config,...o},a=this.transformMessages(r,i),c={model:n.model,max_tokens:n.maxTokens||32e3,messages:a};s&&s.length>0&&(c.tools=this.transformTools(s),c.tool_choice="auto"),n.temperature!==void 0&&(c.temperature=n.temperature);let l=await fetch(`${n.baseUrl}/chat/completions`,{method:"POST",headers:{Authorization:`Bearer ${n.apiKey}`,"content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let u=await l.text();throw new Error(`evroc Think API error (${l.status}): ${u}`)}let d=await l.json();return this.transformResponse(d)}transformMessages(e,r){let s=[];r&&s.push({role:"system",content:r});for(let i of e)if(Array.isArray(i.content)){let o=i.content.filter(c=>c.type==="tool_use");if(o.length>0&&i.role==="assistant"){s.push({role:"assistant",content:null,tool_calls:o.map(c=>({id:c.tool_use_id||`call_${Date.now()}`,type:"function",function:{name:c.tool_name||"",arguments:JSON.stringify(c.tool_input||{})}}))});continue}let n=i.content.filter(c=>c.type==="tool_result");if(n.length>0&&i.role==="user"){for(let c of n)s.push({role:"tool",tool_call_id:c.tool_use_id||"",content:c.content||""});continue}let a=i.content.filter(c=>c.type==="text");a.length>0&&s.push({role:i.role==="system"?"system":i.role,content:a.map(c=>c.text).join(`
124
- `)})}else s.push({role:i.role==="system"?"system":i.role,content:i.content});return s}transformTools(e){return e.map(r=>({type:"function",function:{name:r.name,description:r.description,parameters:r.input_schema}}))}transformResponse(e){let r=e.choices[0],s=r.message,i={content:s.content||"",stopReason:r.finish_reason};return s.tool_calls&&s.tool_calls.length>0&&(i.toolCalls=s.tool_calls.map(o=>({id:o.id,name:o.function.name,input:JSON.parse(o.function.arguments)}))),e.usage&&(i.usage={inputTokens:e.usage.prompt_tokens||0,outputTokens:e.usage.completion_tokens||0,totalTokens:e.usage.total_tokens||0}),i}};var je=class t{static providers=new Map;static{t.providers.set("anthropic",Ye),t.providers.set("openai",Ze),t.providers.set("ollama",Qe),t.providers.set("evroc",et)}static createProvider(e,r){let s=t.providers.get(e.toLowerCase());if(!s)throw new Error(`Unknown AI provider: ${e}. Supported providers: ${Array.from(t.providers.keys()).join(", ")}`);return new s(r)}static getSupportedProviders(){return Array.from(t.providers.keys())}static isProviderSupported(e){return t.providers.has(e.toLowerCase())}static registerProvider(e,r){t.providers.set(e.toLowerCase(),r)}};import{readFileSync as io}from"node:fs";import{resolve as oo,dirname as no}from"node:path";import{fileURLToPath as ao}from"node:url";function co(){try{let t=no(ao(import.meta.url)),e=oo(t,"../../../schemas/schema-iac-v1.json"),r=io(e,"utf-8");return JSON.stringify(JSON.parse(r))}catch{return"(schema file not found \u2014 use the inline example below as reference)"}}var lo=co(),us=`# MolnOS Code Generation Protocol
123
+ `)})}else s.push({role:i.role==="system"?"system":i.role,content:i.content});return s}transformTools(e){return e.map(r=>({type:"function",function:{name:r.name,description:r.description,parameters:r.input_schema}}))}transformResponse(e){let r=e.message||{},s={content:r.content||"",stopReason:e.done?"end_turn":"max_tokens"};return r.tool_calls&&r.tool_calls.length>0&&(s.toolCalls=r.tool_calls.map((i,n)=>({id:i.id||`call_${Date.now()}_${n}`,name:i.function?.name||"",input:typeof i.function?.arguments=="string"?JSON.parse(i.function.arguments):i.function?.arguments||{}}))),(e.eval_count||e.prompt_eval_count)&&(s.usage={inputTokens:e.prompt_eval_count||0,outputTokens:e.eval_count||0,totalTokens:(e.prompt_eval_count||0)+(e.eval_count||0)}),s}};var it=class{constructor(e){this.config=e;if(!e.apiKey)throw new Error("evroc Think API key is required");e.model||(this.config.model="openai/gpt-oss-120b"),e.baseUrl||(this.config.baseUrl="https://models.think.cloud.evroc.com/v1"),e.maxTokens||(this.config.maxTokens=32e3)}name="evroc";async validateConfig(){try{return(await fetch(`${this.config.baseUrl}/models`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`}})).ok}catch{return!1}}async complete(e){let{messages:r,tools:s,systemPrompt:i,config:n}=e,o={...this.config,...n},a=this.transformMessages(r,i),c={model:o.model,max_tokens:o.maxTokens||32e3,messages:a};s&&s.length>0&&(c.tools=this.transformTools(s),c.tool_choice="auto"),o.temperature!==void 0&&(c.temperature=o.temperature);let l=await fetch(`${o.baseUrl}/chat/completions`,{method:"POST",headers:{Authorization:`Bearer ${o.apiKey}`,"content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){let p=await l.text();throw new Error(`evroc Think API error (${l.status}): ${p}`)}let u=await l.json();return this.transformResponse(u)}transformMessages(e,r){let s=[];r&&s.push({role:"system",content:r});for(let i of e)if(Array.isArray(i.content)){let n=i.content.filter(c=>c.type==="tool_use");if(n.length>0&&i.role==="assistant"){s.push({role:"assistant",content:null,tool_calls:n.map(c=>({id:c.tool_use_id||`call_${Date.now()}`,type:"function",function:{name:c.tool_name||"",arguments:JSON.stringify(c.tool_input||{})}}))});continue}let o=i.content.filter(c=>c.type==="tool_result");if(o.length>0&&i.role==="user"){for(let c of o)s.push({role:"tool",tool_call_id:c.tool_use_id||"",content:c.content||""});continue}let a=i.content.filter(c=>c.type==="text");a.length>0&&s.push({role:i.role==="system"?"system":i.role,content:a.map(c=>c.text).join(`
124
+ `)})}else s.push({role:i.role==="system"?"system":i.role,content:i.content});return s}transformTools(e){return e.map(r=>({type:"function",function:{name:r.name,description:r.description,parameters:r.input_schema}}))}transformResponse(e){let r=e.choices[0],s=r.message,i={content:s.content||"",stopReason:r.finish_reason};return s.tool_calls&&s.tool_calls.length>0&&(i.toolCalls=s.tool_calls.map(n=>({id:n.id,name:n.function.name,input:JSON.parse(n.function.arguments)}))),e.usage&&(i.usage={inputTokens:e.usage.prompt_tokens||0,outputTokens:e.usage.completion_tokens||0,totalTokens:e.usage.total_tokens||0}),i}};var Oe=class t{static providers=new Map;static{t.providers.set("anthropic",tt),t.providers.set("openai",rt),t.providers.set("ollama",st),t.providers.set("evroc",it)}static createProvider(e,r){let s=t.providers.get(e.toLowerCase());if(!s)throw new Error(`Unknown AI provider: ${e}. Supported providers: ${Array.from(t.providers.keys()).join(", ")}`);return new s(r)}static getSupportedProviders(){return Array.from(t.providers.keys())}static isProviderSupported(e){return t.providers.has(e.toLowerCase())}static registerProvider(e,r){t.providers.set(e.toLowerCase(),r)}};import{readFileSync as yn}from"node:fs";import{resolve as vn,dirname as wn}from"node:path";import{fileURLToPath as Sn}from"node:url";function xn(){try{let t=wn(Sn(import.meta.url)),e=vn(t,"../../../schemas/schema-iac-v1.json"),r=yn(e,"utf-8");return JSON.stringify(JSON.parse(r))}catch{return"(schema file not found \u2014 use the inline example below as reference)"}}var bn=xn(),ws=`# MolnOS Code Generation Protocol
125
125
 
126
126
  You generate production-ready code for MolnOS. Follow this protocol exactly.
127
127
 
@@ -135,6 +135,7 @@ OUTPUT: Return ONLY valid JSON in this shape:
135
135
  "explanation": "One sentence summary."
136
136
  }
137
137
  \`\`\`
138
+ For event-triggered functions, the handler signature is \`handler(event, context)\` instead of \`handler(request, context)\`.
138
139
  No text, no comments, no extra fields.
139
140
 
140
141
  EXPLANATION: Keep the "explanation" field to one sentence (max two). Do not elaborate beyond a brief summary of what was generated.
@@ -147,7 +148,7 @@ IAC:
147
148
  ## MolnOS IAC JSON Schema (authoritative)
148
149
 
149
150
  The \`iacConfig\` MUST conform to this JSON Schema:
150
- ${lo}
151
+ ${bn}
151
152
 
152
153
  ### Minimal example
153
154
 
@@ -164,6 +165,11 @@ ${lo}
164
165
  "code": "export async function handler(req, context) { return { message: 'Hello' }; }",
165
166
  "methods": ["GET"],
166
167
  "allowUnauthenticated": false
168
+ },
169
+ "myEventHandler": {
170
+ "code": "export async function handler(event, context) { console.log(event.data); return { processed: true }; }",
171
+ "triggers": [{ "type": "event", "eventName": "my.event" }],
172
+ "allowUnauthenticated": false
167
173
  }
168
174
  },
169
175
  "databases": {
@@ -188,11 +194,25 @@ ${lo}
188
194
  ## FUNCTION RULES
189
195
 
190
196
  ### Signature (REQUIRED)
197
+
198
+ **HTTP-triggered functions (default):**
191
199
  \`\`\`js
192
200
  export async function handler(req, context) { <function code here> }
193
201
  \`\`\`
194
202
 
195
203
  - \`req.body\` is already parsed
204
+
205
+ **Event-triggered functions** (when triggers include \`{ "type": "event" }\`):
206
+ \`\`\`js
207
+ export async function handler(event, context) { <function code here> }
208
+ \`\`\`
209
+
210
+ - \`event.eventName\` \u2014 the event name (e.g. \`"order.created"\`)
211
+ - \`event.data\` \u2014 the event payload
212
+ - \`event.timestamp\` \u2014 when the event was emitted (ms)
213
+ - \`event.id\` \u2014 unique event ID
214
+
215
+ **Common:**
196
216
  - JavaScript only (Node.js 24+)
197
217
  - Modern syntax (async/await, ES modules)
198
218
 
@@ -206,7 +226,7 @@ export async function handler(req, context) { <function code here> }
206
226
 
207
227
  ## RESOURCE ACCESS (BINDINGS ONLY)
208
228
 
209
- Use \`context.bindings\` exclusively to use bound resources (e.g. databases).
229
+ Use \`context.bindings\` exclusively to use bound resources (e.g. databases, events).
210
230
 
211
231
  ### Databases (\`context.bindings.databases\`)
212
232
  - \`get(table, key?)\`
@@ -215,6 +235,11 @@ Use \`context.bindings\` exclusively to use bound resources (e.g. databases).
215
235
 
216
236
  Key-value only. No SQL.
217
237
 
238
+ ### Events (\`context.bindings.events\`)
239
+ - \`emit(eventName, data)\` \u2014 emit an event to the in-process event bus
240
+
241
+ Use events to decouple functions. One function emits; another function with an event trigger processes it.
242
+
218
243
  ### Binding Declaration (REQUIRED)
219
244
  Any binding used in code MUST be declared in IAC:
220
245
  \`\`\`json
@@ -227,8 +252,76 @@ Any binding used in code MUST be declared in IAC:
227
252
  }
228
253
  \`\`\`
229
254
 
255
+ Events binding example:
256
+ \`\`\`json
257
+ {
258
+ "bindings": [{
259
+ "service": "events",
260
+ "resource": "my-events",
261
+ "permissions": ["write"]
262
+ }]
263
+ }
264
+ \`\`\`
265
+
266
+ Valid services: \`databases\`, \`events\`, \`storage\`, \`schemas\`
230
267
  Valid permissions: \`read\`, \`write\`, \`delete\`
231
268
 
269
+ ### Event Triggers
270
+ To make a function execute when an event is emitted, add \`triggers\`:
271
+ \`\`\`json
272
+ {
273
+ "triggers": [{ "type": "event", "eventName": "order.created" }]
274
+ }
275
+ \`\`\`
276
+ A function can subscribe to multiple events. Default trigger type is \`"http"\` (standard HTTP-invoked function).
277
+
278
+ **Disabling HTTP access**: If \`triggers\` are specified and none have \`type: "http"\`, the function is event-only and not accessible via HTTP. To keep HTTP access alongside event triggers, include \`{ "type": "http" }\`:
279
+ \`\`\`json
280
+ {
281
+ "triggers": [
282
+ { "type": "http" },
283
+ { "type": "event", "eventName": "order.created" }
284
+ ]
285
+ }
286
+ \`\`\`
287
+
288
+ ### Schemas (\`context.bindings.schemas\`)
289
+ - \`validate(data, schemaName, version?)\` \u2014 validate data against a registered schema
290
+
291
+ Returns \`{ valid: boolean, errors?: [{ path, message }] }\`.
292
+
293
+ Schemas binding example:
294
+ \`\`\`json
295
+ {
296
+ "bindings": [{
297
+ "service": "schemas",
298
+ "resource": "my-schemas",
299
+ "permissions": ["read"]
300
+ }]
301
+ }
302
+ \`\`\`
303
+
304
+ Schemas are declared as IAC resources:
305
+ \`\`\`json
306
+ {
307
+ "resources": {
308
+ "schemas": {
309
+ "order-created": {
310
+ "description": "Order creation event payload",
311
+ "schema": {
312
+ "properties": {
313
+ "orderId": { "type": "string" },
314
+ "amount": { "type": "number" }
315
+ },
316
+ "required": ["orderId", "amount"],
317
+ "additionalProperties": false
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+ \`\`\`
324
+
232
325
  ## SITES (STATIC FRONTEND)
233
326
 
234
327
  When the user's intent involves a UI or frontend, generate a static site using plain HTML, CSS, and vanilla JavaScript (no frameworks).
@@ -279,7 +372,7 @@ When the user's intent involves a UI or frontend, generate a static site using p
279
372
  - Invented binding names (\`db\`, \`kv\`, etc.)
280
373
 
281
374
  /no_think
282
- `;async function ds(t,e){let{contextName:r,intent:s,intentAttributes:i,resourceTypes:o,files:n,iacConfig:a}=t,c=null,l=null;e.contextExists(r)&&(c=e.getContext(r),l=e.getContextResources(r));let d=s||a?.context?.intent||c?.intent||"",u=ps(c?.attributes||{},a?.context?.attributes||{},i||{});return{contextName:r,intent:d,intentAttributes:u,resourceTypes:o||["functions","sites"],existingFiles:n||[],existingResources:l||{functions:[],databases:[],storage:[],sites:[],users:[],serviceAccounts:[],applications:[]},iacConfig:a}}function ps(...t){let e={};for(let r of t)if(!(!r||typeof r!="object"))for(let s in r){if(!Object.hasOwn(r,s))continue;let i=r[s];i!=null&&(typeof i=="object"&&!Array.isArray(i)?e[s]=ps(e[s]||{},i):e[s]=i)}return e}function ms(t){let e=`Context: ${t.contextName}
375
+ `;async function Ss(t,e){let{contextName:r,intent:s,intentAttributes:i,resourceTypes:n,files:o,iacConfig:a}=t,c=null,l=null;e.contextExists(r)&&(c=e.getContext(r),l=e.getContextResources(r));let u=s||a?.context?.intent||c?.intent||"",p=xs(c?.attributes||{},a?.context?.attributes||{},i||{});return{contextName:r,intent:u,intentAttributes:p,resourceTypes:n||["functions","sites"],existingFiles:o||[],existingResources:l||{functions:[],databases:[],storage:[],sites:[],users:[],serviceAccounts:[],applications:[]},iacConfig:a}}function xs(...t){let e={};for(let r of t)if(!(!r||typeof r!="object"))for(let s in r){if(!Object.hasOwn(r,s))continue;let i=r[s];i!=null&&(typeof i=="object"&&!Array.isArray(i)?e[s]=xs(e[s]||{},i):e[s]=i)}return e}function bs(t){let e=`Context: ${t.contextName}
283
376
 
284
377
  `;if(t.intent&&(e+=`Intent: ${t.intent}
285
378
 
@@ -287,43 +380,43 @@ When the user's intent involves a UI or frontend, generate a static site using p
287
380
  ${JSON.stringify(t.intentAttributes,null,2)}
288
381
 
289
382
  `),t.existingFiles.length>0){e+=`Existing Files:
290
- `;for(let n of t.existingFiles)e+=`
291
- --- ${n.path} ---
292
- ${n.content}
383
+ `;for(let o of t.existingFiles)e+=`
384
+ --- ${o.path} ---
385
+ ${o.content}
293
386
  `;e+=`
294
- `}Object.values(t.existingResources).some(n=>n.length>0)&&(e+=`Existing Resources:
387
+ `}Object.values(t.existingResources).some(o=>o.length>0)&&(e+=`Existing Resources:
295
388
  `,t.existingResources.functions.length>0&&(e+=`- Functions: ${t.existingResources.functions.join(", ")}
296
389
  `),t.existingResources.databases.length>0&&(e+=`- Databases: ${t.existingResources.databases.join(", ")}
297
390
  `),t.existingResources.storage.length>0&&(e+=`- Storage: ${t.existingResources.storage.join(", ")}
298
391
  `),t.existingResources.sites.length>0&&(e+=`- Sites: ${t.existingResources.sites.join(", ")}
299
392
  `),e+=`
300
- `);let r=t.resourceTypes,s=r.map(n=>n==="functions"?"Functions (backend)":"Sites (frontend)").join(" and "),i=r.length===1&&r[0]==="functions",o=r.length===1&&r[0]==="sites";return e+=`Generate: ${s}.
393
+ `);let r=t.resourceTypes,s=r.map(o=>o==="functions"?"Functions (backend)":"Sites (frontend)").join(" and "),i=r.length===1&&r[0]==="functions",n=r.length===1&&r[0]==="sites";return e+=`Generate: ${s}.
301
394
  `,i?e+=`Do NOT generate sites or frontend code.
302
- `:o&&(e+=`Do NOT generate functions or backend code. Only generate a static site.
395
+ `:n&&(e+=`Do NOT generate functions or backend code. Only generate a static site.
303
396
  `),e+=`Return as JSON:
304
397
  {
305
398
  "functions": [{ "name": "...", "code": "..." }],
306
399
  "iacConfig": { ... },
307
400
  "explanation": "One sentence summary."
308
- }`,e}var tt=class{storage;config;contextService;iacServiceFactory;cachedProvider=null;cachedProviderKey=null;constructor(e,r,s){this.config=e,this.contextService=r,this.iacServiceFactory=s,this.storage=new Xe(e.generationTtlHours||24)}async start(){if(this.storage.start(),this.config.enabled&&this.config.provider)try{await this.initializeProvider()}catch{}}stop(){this.storage.stop()}isAvailable(){return this.config.enabled===!0&&!!this.config.provider}async initializeProvider(e,r){let s=e||this.config.provider;if(!s)throw new K("No AI provider configured");let i=`${s}:${r||this.config.apiKey||"none"}`;if(this.cachedProvider&&this.cachedProviderKey===i)return this.cachedProvider;let o={apiKey:r||this.config.apiKey,model:this.config.model,baseUrl:this.config.baseUrl,endpoint:this.config.endpoint,maxTokens:this.config.maxTokens,temperature:this.config.temperature};if(!o.apiKey&&s.toLowerCase()!=="ollama")throw new K(`API key required for provider: ${s}. Either configure in molnos.config.json or provide userApiKey.`);let n=je.createProvider(s,o);if(!await n.validateConfig())throw new K(`Failed to validate ${s} provider configuration`);return this.cachedProvider=n,this.cachedProviderKey=i,n}async generate(e){if(!this.isAvailable())throw new K("AI generation is not enabled. Configure AI in molnos.config.json.");let r=await this.initializeProvider(e.providerOverride,e.userApiKey),s=await ds(e,this.contextService),o=[{role:"user",content:ms(s)}];e.iterationFeedback&&e.previousAttempt&&(o.push({role:"assistant",content:JSON.stringify({functions:e.previousAttempt.functions,iacConfig:e.previousAttempt.iacConfig,explanation:e.previousAttempt.explanation})}),o.push({role:"user",content:`Please refine the implementation based on this feedback:
401
+ }`,e}var nt=class{storage;config;contextService;iacServiceFactory;cachedProvider=null;cachedProviderKey=null;constructor(e,r,s){this.config=e,this.contextService=r,this.iacServiceFactory=s,this.storage=new et(e.generationTtlHours||24)}async start(){if(this.storage.start(),this.config.enabled&&this.config.provider)try{await this.initializeProvider()}catch{}}stop(){this.storage.stop()}isAvailable(){return this.config.enabled===!0&&!!this.config.provider}async initializeProvider(e,r){let s=e||this.config.provider;if(!s)throw new K("No AI provider configured");let i=`${s}:${r||this.config.apiKey||"none"}`;if(this.cachedProvider&&this.cachedProviderKey===i)return this.cachedProvider;let n={apiKey:r||this.config.apiKey,model:this.config.model,baseUrl:this.config.baseUrl,endpoint:this.config.endpoint,maxTokens:this.config.maxTokens,temperature:this.config.temperature};if(!n.apiKey&&s.toLowerCase()!=="ollama")throw new K(`API key required for provider: ${s}. Either configure in molnos.config.json or provide userApiKey.`);let o=Oe.createProvider(s,n);if(!await o.validateConfig())throw new K(`Failed to validate ${s} provider configuration`);return this.cachedProvider=o,this.cachedProviderKey=i,o}async generate(e){if(!this.isAvailable())throw new K("AI generation is not enabled. Configure AI in molnos.config.json.");let r=await this.initializeProvider(e.providerOverride,e.userApiKey),s=await Ss(e,this.contextService),n=[{role:"user",content:bs(s)}];e.iterationFeedback&&e.previousAttempt&&(n.push({role:"assistant",content:JSON.stringify({functions:e.previousAttempt.functions,iacConfig:e.previousAttempt.iacConfig,explanation:e.previousAttempt.explanation})}),n.push({role:"user",content:`Please refine the implementation based on this feedback:
309
402
 
310
- ${e.iterationFeedback}`}));let n=await this.runGenerationLoop(r,o);return this.storage.store({contextId:e.contextName,status:"pending",functions:n.functions,iacConfig:n.iacConfig,explanation:n.explanation,parentGenerationId:e.previousAttempt?.id,iterationFeedback:e.iterationFeedback,provider:e.providerOverride||this.config.provider,model:e.modelOverride||this.config.model,tokensUsed:0})}async runGenerationLoop(e,r){let i=(await e.complete({messages:r,systemPrompt:us})).content.trim(),o=this.extractJson(i);if(!o)throw new Error(`Invalid response format from AI: could not find JSON in response. Got: ${i.substring(0,100)}...`);let n=JSON.parse(o);if(!n.functions||!n.iacConfig)throw new Error(`Invalid response format: missing required fields. Got keys: ${Object.keys(n).join(", ")}`);let a=this.mergeFunctionCode(n.iacConfig,n.functions);return{functions:n.functions||[],iacConfig:a,explanation:n.explanation||""}}mergeFunctionCode(e,r){if(!e?.resources?.functions||!r?.length)return e;let s=new Map;for(let i of r)i.name&&i.code&&s.set(i.name,i.code);for(let[i,o]of Object.entries(e.resources.functions)){let n=o,a=s.get(i);a&&(!n.code||n.code.includes("..."))&&(n.code=a)}return e}extractJson(e){try{return JSON.parse(e),e}catch{}let r=e.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);if(r){let n=r[1].trim();try{return JSON.parse(n),n}catch{}}let s=e.match(/```(?:json)?\s*\n([\s\S]+)/);if(s){let n=s[1].trim();try{return JSON.parse(n),n}catch{let a=this.repairTruncatedJson(n);if(a)return a}}let i=e.match(/\{[\s\S]*\}/);if(i)try{return JSON.parse(i[0]),i[0]}catch{}let o=e.match(/\{[\s\S]+/);if(o){let n=this.repairTruncatedJson(o[0]);if(n)return n}return null}repairTruncatedJson(e){let r=e.trimEnd();r=r.replace(/,\s*$/,""),r=r.replace(/,?\s*"[^"]*"\s*:\s*$/,""),r=r.replace(/,?\s*"[^"]*"\s*:\s*"[^"]*$/,"");let s=(r.match(/{/g)||[]).length,i=(r.match(/}/g)||[]).length,o=(r.match(/\[/g)||[]).length,n=(r.match(/]/g)||[]).length;for(let a=0;a<o-n;a++)r+="]";for(let a=0;a<s-i;a++)r+="}";try{return JSON.parse(r),r}catch{return null}}getGeneration(e){return this.storage.get(e)}listGenerations(e){return this.storage.listByContext(e)}discardGeneration(e){return this.storage.updateStatus(e,"discarded")}markApplied(e){return this.storage.updateStatus(e,"applied")}async applyGeneration(e,r){let s=this.getGeneration(e);if(!s)throw new Error("Generation not found");if(s.status!=="pending")throw new Error(`Generation has already been ${s.status}`);let o=await this.iacServiceFactory(r).apply(s.iacConfig);return this.markApplied(e),o}deleteGeneration(e){return this.storage.delete(e)}getStats(){return this.storage.getStats()}getSupportedProviders(){return je.getSupportedProviders()}};async function hs(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 d=r.getRateLimitInfo(`oauth:${o}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((d.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}=h(i,"Error initiating OAuth flow");return t.json({error:o},n)}}async function fs(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,d=a?.split(",")[0]?.trim()||l||"unknown";if(!r.checkRateLimit(`oauth:${d}`)){let x=r.getRateLimitInfo(`oauth:${d}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((x.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 m=await e.handleCallback(u.code,d),v=await s.getUserByEmail(m.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:m.accessToken,refreshToken:m.refreshToken,expiresIn:m.expiresIn,tokenType:m.tokenType,user:{id:v.id,email:m.user.email,name:m.user.name,username:m.user.username},warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);let x=new URL(u.redirectUrl);return x.searchParams.set("access_token",m.accessToken),x.searchParams.set("refresh_token",m.refreshToken),x.searchParams.set("expires_in",m.expiresIn.toString()),t.redirect(x.toString(),302)}return t.json({success:!0,accessToken:m.accessToken,refreshToken:m.refreshToken,expiresIn:m.expiresIn,tokenType:m.tokenType,user:{id:v.id,email:m.user.email,name:m.user.name,username:m.user.username}})}catch(n){let{message:a,status:c}=h(n,"OAuth authentication failed");return t.json({error:a},c)}}async function gs(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}=h(r,"Error listing OAuth providers");return t.json({error:s},i)}}var rt=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 uo from"node:crypto";var st=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=uo.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 ys={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 vs(t){let e=[];if(t.presets)for(let[r,s]of Object.entries(t.presets)){let i=ys[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 ws(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 Et(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 Ss(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 it=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 xs(t){return t?new it(t):null}function bs(t){return t&&typeof t=="number"&&t>0?t*1024*1024:0}async function Cs(t){let{auth:e,db:r,config:s,molnos:i,oauth:o,ai:n}=t,a=new Ge(e,r,i.initialUser);await a.start();let l=`${s.useHttps||s.useHttp2?"https":"http"}://${s.host||"127.0.0.1"}:${s.port||3e3}`,d=xs(l),u,m;if(o){u=new st(o),m=new Map;let p=vs(o);for(let A of p){let b=new rt(A,e);m.set(A.id,b)}}let v=Tt(i.dataPath,"applications"),x=new ze({dbPath:v});await x.start();let H=Tt(i.dataPath,"management"),U=new fe({dbPath:H}),ye=Tt(i.dataPath,".runtime-config.json");U.setEnvironmentVariables({MOLNOS_RUNTIME_CONFIG:ye});let F=i.cluster;U.setClusterConfig(F),await U.start();let D;F?.mode==="core"&&F.workers&&(D=new Te,await D.registerWorkers(F.workers));let L=new We(r);await L.start();let N=ns(),G=p=>{let A=Pt({serviceUrls:{databases:N.services.databases.url,storage:N.services.storage.url,functions:N.services.functions.url,sites:N.services.sites.url,identity:N.identity.apiUrl,applications:N.identity.apiUrl},authToken:p});return new Ke(L,A)},ue=n||{enabled:!1},z=new tt(ue,L,G);await z.start();let ot=!1,f=new Ae({port:s.port||3e3,host:s.host||"127.0.0.1",allowedDomains:s.allowedDomains,maxBodySize:bs(1e3),rateLimit:i.rateLimit?.global||{enabled:!1,requestsPerMinute:0}});f.use(async(p,A)=>ot?p.text("Service Unavailable - Server is shutting down",503):A()),f.use(ws),F?.mode==="worker"&&F.secret&&f.use(ke(F.secret)),f.get("/health",async p=>p.text("OK"));let T=async p=>p.text("Not Found",404);if(f.post("/auth/login",p=>sr(p,a,e,x)),f.get("/auth/verify",p=>ir(p,e,x)),f.post("/auth/refresh",p=>or(p,e)),m&&u){f.get("/auth/oauth/providers",p=>gs(p,m));for(let[p,A]of m.entries())f.get(`/auth/oauth/${p}`,Et,b=>hs(b,A,u,p)),f.get(`/auth/oauth/${p}/callback`,Et,b=>fs(b,A,u,a,x,p))}f.post("/management/service",y,p=>Rr(p,U)),f.get("/management/services",y,p=>Pr(p,U)),f.get("/management/service/:serviceName",y,p=>Er(p,U)),f.put("/management/service/:serviceName",y,p=>$r(p,U)),f.delete("/management/service/:serviceName",y,p=>Or(p,U)),f.get("/management/service/:serviceName/start",y,p=>Mr(p,U)),f.get("/management/service/:serviceName/stop",y,p=>Ur(p,U)),f.get("/management/service/:serviceName/logs",y,p=>Lr(p,U)),f.get("/management/service/:serviceName/restart",y,p=>Hr(p,U)),f.get("/identity/whoami",y,p=>nr(p)),f.get("/identity/identities",y,p=>ar(p,a)),f.post("/identity/users",y,p=>lr(p,a)),f.get("/identity/users",y,p=>ur(p,a)),f.get("/identity/users/:userId",y,p=>dr(p,a)),f.patch("/identity/users/:userId",y,p=>mr(p,a)),f.delete("/identity/users/:userId",y,p=>hr(p,a)),f.post("/identity/service-accounts",y,p=>fr(p,a)),f.get("/identity/service-accounts",y,p=>gr(p,a)),f.get("/identity/service-accounts/:serviceAccountId",y,p=>yr(p,a)),f.patch("/identity/service-accounts/:serviceAccountId",y,p=>wr(p,a)),f.delete("/identity/service-accounts/:serviceAccountId",y,p=>Sr(p,a)),f.post("/identity/service-accounts/:serviceAccountId/rotate-key",y,p=>xr(p,a)),f.post("/identity/roles",y,p=>Ir(p,a)),f.get("/identity/roles",y,p=>br(p,a)),f.get("/identity/roles/:roleId",y,p=>Cr(p,a)),f.patch("/identity/roles/:roleId",y,p=>Ar(p,a)),f.delete("/identity/roles/:roleId",y,p=>kr(p,a)),f.post("/applications",y,p=>Nr(p,x,d)),f.get("/applications",y,p=>_r(p,x,d)),f.get("/applications/:id",y,p=>Fr(p,x,d)),f.patch("/applications/:id",y,p=>qr(p,x,d)),f.delete("/applications/:id",y,p=>Br(p,x,d)),f.get("/contexts",y,p=>Vr(p,L,d)),f.post("/contexts",y,p=>zr(p,L,d)),f.get("/contexts/:contextName",y,p=>Gr(p,L,d)),f.patch("/contexts/:contextName",y,p=>Wr(p,L,d)),f.delete("/contexts/:contextName",y,p=>Jr(p,L,d)),f.delete("/contexts/:contextName/resources",y,p=>Kr(p,L,d,A=>Pt({serviceUrls:{databases:N.services.databases.url,storage:N.services.storage.url,functions:N.services.functions.url,sites:N.services.sites.url,identity:N.identity.apiUrl,applications:N.identity.apiUrl},authToken:A}))),f.post("/iac/validate",y,p=>Xr(p,G,d)),f.post("/iac/apply",y,p=>Yr(p,G,d)),f.post("/iac/diff",y,p=>Zr(p,G,d)),f.post("/contexts/:contextName/generate",y,p=>Qr(p,z,d)),f.get("/contexts/:contextName/generations",y,p=>ts(p,z,d)),f.get("/generations/:generationId",y,p=>es(p,z,d)),f.post("/generations/:generationId/apply",y,p=>rs(p,z,d)),f.post("/generations/:generationId/discard",y,p=>ss(p,z,d)),f.delete("/generations/:generationId",y,p=>is(p,z,d)),f.get("/databases/*",y,E,T),f.post("/databases/*",y,E,T),f.put("/databases/*",y,E,T),f.patch("/databases/*",y,E,T),f.delete("/databases/*",y,E,T);async function ve(p,A){if(p.path.match(/^\/functions\/run\//)){let O=p.headers.authorization;if(O)try{let R=await a.getUserFromToken(O);R&&(p.state.user=R,p.state.requestingIdentity=R)}catch{}return A()}return y(p,A)}f.get("/functions/*",ve,E,T),f.post("/functions/*",ve,E,T),f.put("/functions/*",ve,E,T),f.patch("/functions/*",ve,E,T),f.delete("/functions/*",ve,E,T),f.get("/sites/projects/:projectId/*",E,async p=>p.text("Not Found",404)),f.get("/sites/*",y,E,T),f.post("/sites/*",y,E,T),f.put("/sites/*",y,E,T),f.patch("/sites/*",y,E,T),f.delete("/sites/*",y,E,T);async function we(p,A){let b=p.req.method;if(p.path.match(/^\/storage\/buckets\/[^/]+\/objects\/.+/)&&(b==="GET"||b==="HEAD")){let R=p.headers.authorization;if(R)try{let Z=await a.getUserFromToken(R);Z&&(p.state.user=Z,p.state.requestingIdentity=Z)}catch{}return A()}return y(p,A)}f.get("/storage/*",we,E,T),f.post("/storage/*",we,E,T),f.put("/storage/*",we,E,T),f.patch("/storage/*",we,E,T),f.delete("/storage/*",we,E,T),f.get("/observability/*",y,E,T),f.post("/observability/*",y,E,T),f.put("/observability/*",y,E,T),f.patch("/observability/*",y,E,T),f.delete("/observability/*",y,E,T);function $s(p,A,b,$){if(A!=="POST")return;let O=null,R=null;p==="/functions/deploy"&&$.function?.id?(O="function",R=$.function.id):p.match(/^\/databases\/tables\/[^/]+$/)&&$.name?(O="database",R=$.name):p.match(/^\/storage\/buckets\/[^/]+$/)&&$.bucket?(O="storage",R=$.bucket):p==="/sites/projects"&&$.projectId&&(O="site",R=$.projectId),O&&R&&L.registerResource(b,O,R).catch(Z=>{console.error(`[Server] Failed to register ${O} '${R}' with context '${b}':`,Z.message)})}async function E(p,A){try{let b=p.path,$=Object.keys(p.query).length>0?`?${new URLSearchParams(p.query).toString()}`:"",O=p.req.method||"",R,Z=0,Ms=await U.getServices();for(let M of Ms)M.active&&b.startsWith(M.prefix)&&M.prefix.length>Z&&(R=M,Z=M.prefix.length);if(!R)return A();let $t=p.state.user;if(!(b.match(/^\/sites\/projects\/[^/]+.*/)&&O==="GET")&&$t&&Ss($t,O,b),R.healthCheck&&R.healthCheck.healthy===!1)return p.json({error:"Service unavailable (unhealthy)"},503);let Ot=(b.substring(R.prefix.length)||"/")+$,_=null,nt=null,at=null;if(["POST","PUT","PATCH","DELETE"].includes(O)){let M=p.headers["content-type"]||"";if(M.includes("application/json"))try{let te=await S(p);at=te,_=JSON.stringify(te)}catch{_=null}else if(M.includes("multipart/form-data"))try{_=JSON.stringify(p.body),nt="application/json"}catch{_=null}else try{_=Buffer.isBuffer(p.body)?p.body:Buffer.from(p.body)}catch{_=null}}let $e=R.name,Mt=F?.mode==="core"?F.workers?.[$e]:void 0;if(Mt&&D){if(!D.isHealthy($e))return p.json({error:`Worker for ${$e} is unavailable`},503);try{let M=await yt(Mt,Ot,O,_,p.headers,F?.secret);return vt(p,M)}catch(M){return console.error(`[Server] Worker proxy error for ${$e}:`,M.message),p.json({error:M.message},M.statusCode||503)}}return new Promise(M=>{let te={...p.headers,host:`127.0.0.1:${R.port}`};nt&&(te["content-type"]=nt),_&&(typeof _=="string"?te["content-length"]=Buffer.byteLength(_).toString():te["content-length"]=_.length.toString());let Us={method:O,hostname:"127.0.0.1",port:R.port,path:Ot,headers:te},Se=po.request(Us,B=>{let Ut=[];B.on("data",de=>{Ut.push(de)}),B.on("end",()=>{let de=Buffer.concat(Ut),ct={};Object.entries(B.headers).forEach(([be,Q])=>{Q!==void 0&&(ct[be]=Array.isArray(Q)?Q.join(", "):Q)});let xe=B.headers["content-type"]||"",W;if(xe.includes("application/json"))try{let be=JSON.parse(de.toString("utf-8")),Q=B.statusCode||200;be.success&&Q>=200&&Q<300&&at?.context&&$s(b,O,at.context,be),W=p.json(be,Q)}catch{W=p.text(de.toString("utf-8"),B.statusCode||200)}else xe.startsWith("text/")||xe.includes("javascript")||xe.includes("xml")?W=p.text(de.toString("utf-8"),B.statusCode||200):(W=p.binary(de,xe||"application/octet-stream"),B.statusCode&&B.statusCode!==200&&(W.statusCode=B.statusCode));W.headers?W.headers={...W.headers,...ct}:W.headers=ct,M(W)})});Se.on("error",B=>{M(p.json({error:"Proxy Error",message:B.message},502))}),Se.on("timeout",()=>{Se.destroy(),M(p.json({error:"Gateway Timeout"},504))}),_&&Se.write(_),Se.end()})}catch(b){return Rt(p,b)}}async function y(p,A){try{let b=p.headers.authorization;if(!b)return p.text("Unauthorized",401);let $=await a.getUserFromToken(b);return $?(p.state.user=$,p.state.requestingIdentity=$,A()):p.text("Unauthorized",401)}catch(b){return Rt(p,b)}}function Rt(p,A){let b=A.message||A,$=A?.cause?.statusCode||400;return p.json({error:b},$)}let jt=f.start();async function Os(){ot||(ot=!0,await new Promise((p,A)=>{jt.close(b=>{b?A(b):p()})}),console.log("[Server] Stopping managed services..."),await U.shutdown(),u&&u.shutdown(),console.log("[Server] Stopping AI service..."),z.stop(),await r.close())}return{server:jt,shutdown:Os,processManager:U,identityService:a}}import mo from"node:http";import{join as ho}from"node:path";async function Is(t){let{config:e,dataPath:r,cluster:s}=t,i=new Ae({...e});if(s.secret){let l=ke(s.secret);i.use(l)}let o=new fe({dbPath:ho(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 d=l.path,u=Object.keys(l.query).length>0?`?${new URLSearchParams(l.query).toString()}`:"",m=l.req.method||"GET",x=(await o.getServices()).find(D=>d.startsWith(`/${D.name}`)&&D.active);if(!x)return l.json({error:"Service not found"},404);let U=(d.substring(`/${x.name}`.length)||"/")+u,ye=null;["POST","PUT","PATCH","DELETE"].includes(m)&&(l.headers["content-type"]||"").includes("application/json")&&l.body&&(ye=JSON.stringify(l.body));let F={};for(let[D,L]of Object.entries(l.headers))D.toLowerCase()!==ae&&L&&(F[D]=typeof L=="string"?L:L[0]);return new Promise(D=>{let L={method:m,hostname:"127.0.0.1",port:x.port,path:U,headers:F},N=mo.request(L,G=>{let ue="";G.on("data",z=>{ue+=z}),G.on("end",()=>{if((G.headers["content-type"]||"").includes("application/json"))try{D(l.json(JSON.parse(ue),G.statusCode||200))}catch{D(l.text(ue,G.statusCode||200))}else D(l.text(ue,G.statusCode||200))})});N.on("error",()=>{D(l.json({error:"Service unavailable"},503))}),ye&&N.write(ye),N.end()})};i.get("/health",l=>l.json({status:"ok",mode:"worker"})),i.post("/management/service/:serviceName/start",async l=>{let d=l.params?.serviceName;if(!d)return l.json({error:"Service name required"},400);if(!n.includes(d))return l.json({error:`This worker does not handle capability: ${d}`},400);let u=await o.startService(d);return l.json({serviceName:d,isStarted:u})}),i.post("/management/service/:serviceName/stop",async l=>{let d=l.params?.serviceName;if(!d)return l.json({error:"Service name required"},400);if(!n.includes(d))return l.json({error:`This worker does not handle capability: ${d}`},400);let u=await o.stopService(d);return l.json({serviceName:d,isStopped:u})}),i.post("/management/service/:serviceName/restart",async l=>{let d=l.params?.serviceName;if(!d)return l.json({error:"Service name required"},400);if(!n.includes(d))return l.json({error:`This worker does not handle capability: ${d}`},400);let u=await o.restartService(d);return l.json({serviceName:d,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 ks=()=>{let t=As(process.env.DEBUG)||!1,e=As(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||Re(),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 As(t){return t==="true"||t===!0}var I=ks(),Ps={configFilePath:"molnos.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:"--consoleUrl",path:"auth.consoleUrl",defaultValue:I.auth.consoleUrl},{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:"--db",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:"--http2",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:"--allowed",path:"server.allowedDomains",defaultValue:I.server.allowedDomains,parser:se.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:I.server.debug},{flag:"--data-path",path:"dataPath",defaultValue:I.molnos.dataPath},{flag:"--initialUserId",path:"molnos.initialUser.id",defaultValue:I.molnos.initialUser.id},{flag:"--initialUserName",path:"molnos.initialUser.userName",defaultValue:I.molnos.initialUser.userName},{flag:"--initialUserEmail",path:"molnos.initialUser.email",defaultValue:I.molnos.initialUser.email}]};function Es(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",d=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`
403
+ ${e.iterationFeedback}`}));let o=await this.runGenerationLoop(r,n);return this.storage.store({contextId:e.contextName,status:"pending",functions:o.functions,iacConfig:o.iacConfig,explanation:o.explanation,parentGenerationId:e.previousAttempt?.id,iterationFeedback:e.iterationFeedback,provider:e.providerOverride||this.config.provider,model:e.modelOverride||this.config.model,tokensUsed:0})}async runGenerationLoop(e,r){let i=(await e.complete({messages:r,systemPrompt:ws})).content.trim(),n=this.extractJson(i);if(!n)throw new Error(`Invalid response format from AI: could not find JSON in response. Got: ${i.substring(0,100)}...`);let o=JSON.parse(n);if(!o.functions||!o.iacConfig)throw new Error(`Invalid response format: missing required fields. Got keys: ${Object.keys(o).join(", ")}`);let a=this.mergeFunctionCode(o.iacConfig,o.functions);return{functions:o.functions||[],iacConfig:a,explanation:o.explanation||""}}mergeFunctionCode(e,r){if(!e?.resources?.functions||!r?.length)return e;let s=new Map;for(let i of r)i.name&&i.code&&s.set(i.name,i.code);for(let[i,n]of Object.entries(e.resources.functions)){let o=n,a=s.get(i);a&&(!o.code||o.code.includes("..."))&&(o.code=a)}return e}extractJson(e){try{return JSON.parse(e),e}catch{}let r=e.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);if(r){let o=r[1].trim();try{return JSON.parse(o),o}catch{}}let s=e.match(/```(?:json)?\s*\n([\s\S]+)/);if(s){let o=s[1].trim();try{return JSON.parse(o),o}catch{let a=this.repairTruncatedJson(o);if(a)return a}}let i=e.match(/\{[\s\S]*\}/);if(i)try{return JSON.parse(i[0]),i[0]}catch{}let n=e.match(/\{[\s\S]+/);if(n){let o=this.repairTruncatedJson(n[0]);if(o)return o}return null}repairTruncatedJson(e){let r=e.trimEnd();r=r.replace(/,\s*$/,""),r=r.replace(/,?\s*"[^"]*"\s*:\s*$/,""),r=r.replace(/,?\s*"[^"]*"\s*:\s*"[^"]*$/,"");let s=(r.match(/{/g)||[]).length,i=(r.match(/}/g)||[]).length,n=(r.match(/\[/g)||[]).length,o=(r.match(/]/g)||[]).length;for(let a=0;a<n-o;a++)r+="]";for(let a=0;a<s-i;a++)r+="}";try{return JSON.parse(r),r}catch{return null}}getGeneration(e){return this.storage.get(e)}listGenerations(e){return this.storage.listByContext(e)}discardGeneration(e){return this.storage.updateStatus(e,"discarded")}markApplied(e){return this.storage.updateStatus(e,"applied")}async applyGeneration(e,r){let s=this.getGeneration(e);if(!s)throw new Error("Generation not found");if(s.status!=="pending")throw new Error(`Generation has already been ${s.status}`);let n=await this.iacServiceFactory(r).apply(s.iacConfig);return this.markApplied(e),n}deleteGeneration(e){return this.storage.delete(e)}getStats(){return this.storage.getStats()}getSupportedProviders(){return Oe.getSupportedProviders()}};async function Cs(t,e,r,s){try{let i=t.headers["x-forwarded-for"],n=(Array.isArray(i)?i[0]:i)?.split(",")[0]?.trim()||t.headers["x-real-ip"]||"unknown";if(!r.checkRateLimit(`oauth:${n}`)){let u=r.getRateLimitInfo(`oauth:${n}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((u.reset-Date.now())/1e3)},429)}let o=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,o,a),l=e.getAuthorizationUrl(c);return t.redirect(l,302)}catch(i){let{message:n,status:o}=h(i,"Error initiating OAuth flow");return t.json({error:n},o)}}async function Is(t,e,r,s,i,n){try{let o=t.headers["x-forwarded-for"],a=Array.isArray(o)?o[0]:o,c=t.headers["x-real-ip"],l=Array.isArray(c)?c[0]:c,u=a?.split(",")[0]?.trim()||l||"unknown";if(!r.checkRateLimit(`oauth:${u}`)){let b=r.getRateLimitInfo(`oauth:${u}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((b.reset-Date.now())/1e3)},429)}let p=r.validateCallback(t,n);if(!p.valid)return t.json({error:p.error||"Invalid OAuth callback"},400);let m=await e.handleCallback(p.code,u),w=await s.getUserByEmail(m.user.email);if(!w)return t.json({error:"User not found. You must be invited before signing in with OAuth."},403);if(await s.updateUser(w.id,{lastLogin:new Date().toISOString()}),p.redirectUrl){if(p.applicationId&&!await i.validateRedirectUri(p.applicationId,p.redirectUrl))return console.warn(`Redirect URL validation failed for applicationId: ${p.applicationId}`),t.json({success:!0,accessToken:m.accessToken,refreshToken:m.refreshToken,expiresIn:m.expiresIn,tokenType:m.tokenType,user:{id:w.id,email:m.user.email,name:m.user.name,username:m.user.username},warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);let b=new URL(p.redirectUrl);return b.searchParams.set("access_token",m.accessToken),b.searchParams.set("refresh_token",m.refreshToken),b.searchParams.set("expires_in",m.expiresIn.toString()),t.redirect(b.toString(),302)}return t.json({success:!0,accessToken:m.accessToken,refreshToken:m.refreshToken,expiresIn:m.expiresIn,tokenType:m.tokenType,user:{id:w.id,email:m.user.email,name:m.user.name,username:m.user.username}})}catch(o){let{message:a,status:c}=h(o,"OAuth authentication failed");return t.json({error:a},c)}}async function As(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}=h(r,"Error listing OAuth providers");return t.json({error:s},i)}}var ot=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),n=this.mapUserInfo(i);if(!n.email)throw new Error("OAuth provider did not return user email");let o=await this.mikroAuth.createToken({email:n.email,username:n.username||n.name,role:"user",ip:r});return{accessToken:o.accessToken,refreshToken:o.refreshToken,expiresIn:o.exp,tokenType:o.tokenType,user:n}}getPublicInfo(){return{id:this.config.id,name:this.config.name,loginUrl:`/auth/oauth/${this.config.id}`}}};import Cn from"node:crypto";var at=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 n=Cn.randomBytes(32).toString("hex"),o=this.getClientIp(e),a=e.headers["user-agent"]||"";return this.stateStore.set(n,{expires:Date.now()+this.stateExpiryMs,providerId:r,ip:o,userAgent:a,redirectUrl:s,applicationId:i}),n}validateState(e,r,s,i){let n=this.stateStore.get(e);return n?n.expires<Date.now()?(this.stateStore.delete(e),!1):n.providerId!==r||n.ip!==s||i&&n.userAgent&&n.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,n=Array.isArray(e.query.error)?e.query.error[0]:e.query.error,o=Array.isArray(e.query.error_description)?e.query.error_description[0]:e.query.error_description;if(n)return{valid:!1,error:`OAuth provider error: ${o||n}`};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"],n=Array.isArray(i)?i[0]:i;return s?.split(",")[0]?.trim()||n||"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 ks={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 Ps(t){let e=[];if(t.presets)for(let[r,s]of Object.entries(t.presets)){let i=ks[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}var In=null;function Es(t){In=t}async function Ts(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 Ut(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 Rs(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 ct=class{baseUrl;authToken;constructor(e,r){this.baseUrl=e.replace(/\/$/,""),this.authToken=r}async createCustomRole(e,r,s,i){let n=await fetch(`${this.baseUrl}/identity/roles`,{method:"POST",headers:this.getHeaders(),body:JSON.stringify({roleId:e,name:r,description:s,permissions:i})});if(!n.ok){let o=`Failed to create role: ${n.statusText}`;try{o=(await n.json()).error||o}catch{o=await n.text().catch(()=>n.statusText)||o}throw new Error(o)}}async updateRole(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 o=`Failed to create service account: ${i.statusText}`;try{o=(await i.json()).error||o}catch{o=await i.text().catch(()=>i.statusText)||o}throw new Error(o)}let n=await i.json();return{id:n.id,apiKey:n.apiKey}}async deleteIdentity(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 js(t){return t?new ct(t):null}function $s(t){return t&&typeof t=="number"&&t>0?t*1024*1024:0}async function Os(t){let{auth:e,db:r,config:s,molnos:i,oauth:n,ai:o}=t,a=new We(e,r,i.initialUser);await a.start();let l=`${s.useHttps||s.useHttp2?"https":"http"}://${s.host||"127.0.0.1"}:${s.port||3e3}`,u=js(l),p,m;if(n){p=new at(n),m=new Map;let d=Ps(n);for(let A of d){let C=new ot(A,e);m.set(A.id,C)}}let w=lt(i.dataPath,"applications"),b=new Je({dbPath:w});await b.start();let N=lt(i.dataPath,"schemas"),z=new Ke({dbPath:N});await z.start(),Es(z);let ve=lt(i.dataPath,"management"),O=new ge({dbPath:ve}),F=lt(i.dataPath,".runtime-config.json");O.setEnvironmentVariables({MOLNOS_RUNTIME_CONFIG:F});let D=i.cluster;O.setClusterConfig(D),await O.start();let Q;D?.mode==="core"&&D.workers&&(Q=new Re,await Q.registerWorkers(D.workers));let L=new Ye(r);await L.start();let j=Xe(),se=d=>{let A=Mt({serviceUrls:{databases:j.services.databases.url,storage:j.services.storage.url,functions:j.services.functions.url,sites:j.services.sites.url,identity:j.identity.apiUrl,applications:j.identity.apiUrl,schemas:`${j.identity.apiUrl}/schemas`},authToken:d});return new Qe(L,A)},_s=o||{enabled:!1},ee=new nt(_s,L,se);await ee.start();let ut=!1,f=new ke({port:s.port||3e3,host:s.host||"127.0.0.1",allowedDomains:s.allowedDomains,maxBodySize:$s(1e3),rateLimit:i.rateLimit?.global||{enabled:!1,requestsPerMinute:0}});f.use(async(d,A)=>ut?d.text("Service Unavailable - Server is shutting down",503):A()),f.use(Ts),D?.mode==="worker"&&D.secret&&f.use(Pe(D.secret)),f.get("/health",async d=>d.text("OK"));let T=async d=>d.text("Not Found",404);if(f.post("/auth/login",d=>lr(d,a,e,b)),f.get("/auth/verify",d=>ur(d,e,b)),f.post("/auth/refresh",d=>dr(d,e)),m&&p){f.get("/auth/oauth/providers",d=>As(d,m));for(let[d,A]of m.entries())f.get(`/auth/oauth/${d}`,Ut,C=>Cs(C,A,p,d)),f.get(`/auth/oauth/${d}/callback`,Ut,C=>Is(C,A,p,a,b,d))}f.post("/management/service",y,d=>Hr(d,O)),f.get("/management/services",y,d=>Or(d,O)),f.get("/management/service/:serviceName",y,d=>Mr(d,O)),f.put("/management/service/:serviceName",y,d=>Lr(d,O)),f.delete("/management/service/:serviceName",y,d=>Nr(d,O)),f.get("/management/service/:serviceName/start",y,d=>qr(d,O)),f.get("/management/service/:serviceName/stop",y,d=>Fr(d,O)),f.get("/management/service/:serviceName/logs",y,d=>_r(d,O)),f.get("/management/service/:serviceName/restart",y,d=>Br(d,O)),f.get("/identity/whoami",y,d=>pr(d)),f.get("/identity/identities",y,d=>mr(d,a)),f.post("/identity/users",y,d=>fr(d,a)),f.get("/identity/users",y,d=>gr(d,a)),f.get("/identity/users/:userId",y,d=>yr(d,a)),f.patch("/identity/users/:userId",y,d=>wr(d,a)),f.delete("/identity/users/:userId",y,d=>Sr(d,a)),f.post("/identity/service-accounts",y,d=>xr(d,a)),f.get("/identity/service-accounts",y,d=>br(d,a)),f.get("/identity/service-accounts/:serviceAccountId",y,d=>Cr(d,a)),f.patch("/identity/service-accounts/:serviceAccountId",y,d=>Ar(d,a)),f.delete("/identity/service-accounts/:serviceAccountId",y,d=>kr(d,a)),f.post("/identity/service-accounts/:serviceAccountId/rotate-key",y,d=>Pr(d,a)),f.post("/identity/roles",y,d=>Rr(d,a)),f.get("/identity/roles",y,d=>Er(d,a)),f.get("/identity/roles/:roleId",y,d=>Tr(d,a)),f.patch("/identity/roles/:roleId",y,d=>jr(d,a)),f.delete("/identity/roles/:roleId",y,d=>$r(d,a)),f.post("/applications",y,d=>Gr(d,b,u)),f.get("/applications",y,d=>Wr(d,b,u)),f.get("/applications/:id",y,d=>zr(d,b,u)),f.patch("/applications/:id",y,d=>Jr(d,b,u)),f.delete("/applications/:id",y,d=>Kr(d,b,u)),f.post("/schemas",y,d=>Xr(d,z,u)),f.get("/schemas",y,d=>Yr(d,z,u)),f.get("/schemas/:name",y,d=>At(d,z,u)),f.get("/schemas/:name/:version",y,d=>At(d,z,u)),f.put("/schemas/:name",y,d=>Zr(d,z,u)),f.delete("/schemas/:name",y,d=>Qr(d,z,u)),f.get("/contexts",y,d=>es(d,L,u)),f.post("/contexts",y,d=>rs(d,L,u)),f.get("/contexts/:contextName",y,d=>ts(d,L,u)),f.patch("/contexts/:contextName",y,d=>ss(d,L,u)),f.delete("/contexts/:contextName",y,d=>is(d,L,u)),f.delete("/contexts/:contextName/resources",y,d=>ns(d,L,u,A=>Mt({serviceUrls:{databases:j.services.databases.url,storage:j.services.storage.url,functions:j.services.functions.url,sites:j.services.sites.url,identity:j.identity.apiUrl,applications:j.identity.apiUrl,schemas:`${j.identity.apiUrl}/schemas`},authToken:A}))),f.post("/iac/validate",y,d=>os(d,se,u)),f.post("/iac/apply",y,d=>as(d,se,u)),f.post("/iac/diff",y,d=>cs(d,se,u)),f.post("/contexts/:contextName/generate",y,d=>ls(d,ee,u)),f.get("/contexts/:contextName/generations",y,d=>ds(d,ee,u)),f.get("/generations/:generationId",y,d=>us(d,ee,u)),f.post("/generations/:generationId/apply",y,d=>ps(d,ee,u)),f.post("/generations/:generationId/discard",y,d=>ms(d,ee,u)),f.delete("/generations/:generationId",y,d=>hs(d,ee,u)),f.get("/databases/*",y,E,T),f.post("/databases/*",y,E,T),f.put("/databases/*",y,E,T),f.patch("/databases/*",y,E,T),f.delete("/databases/*",y,E,T);async function we(d,A){if(d.path.match(/^\/functions\/run\//)){let U=d.headers.authorization;if(U)try{let R=await a.getUserFromToken(U);R&&(d.state.user=R,d.state.requestingIdentity=R)}catch{}return A()}return y(d,A)}f.get("/functions/*",we,E,T),f.post("/functions/*",we,E,T),f.put("/functions/*",we,E,T),f.patch("/functions/*",we,E,T),f.delete("/functions/*",we,E,T),f.get("/sites/projects/:projectId/*",E,async d=>d.text("Not Found",404)),f.get("/sites/*",y,E,T),f.post("/sites/*",y,E,T),f.put("/sites/*",y,E,T),f.patch("/sites/*",y,E,T),f.delete("/sites/*",y,E,T);async function Se(d,A){let C=d.req.method;if(d.path.match(/^\/storage\/buckets\/[^/]+\/objects\/.+/)&&(C==="GET"||C==="HEAD")){let R=d.headers.authorization;if(R)try{let te=await a.getUserFromToken(R);te&&(d.state.user=te,d.state.requestingIdentity=te)}catch{}return A()}return y(d,A)}f.get("/storage/*",Se,E,T),f.post("/storage/*",Se,E,T),f.put("/storage/*",Se,E,T),f.patch("/storage/*",Se,E,T),f.delete("/storage/*",Se,E,T),f.get("/observability/*",y,E,T),f.post("/observability/*",y,E,T),f.put("/observability/*",y,E,T),f.patch("/observability/*",y,E,T),f.delete("/observability/*",y,E,T);function Bs(d,A,C,M){if(A!=="POST")return;let U=null,R=null;d==="/functions/deploy"&&M.function?.id?(U="function",R=M.function.id):d.match(/^\/databases\/tables\/[^/]+$/)&&M.name?(U="database",R=M.name):d.match(/^\/storage\/buckets\/[^/]+$/)&&M.bucket?(U="storage",R=M.bucket):d==="/sites/projects"&&M.projectId&&(U="site",R=M.projectId),U&&R&&L.registerResource(C,U,R).catch(te=>{console.error(`[Server] Failed to register ${U} '${R}' with context '${C}':`,te.message)})}async function E(d,A){try{let C=d.path,M=Object.keys(d.query).length>0?`?${new URLSearchParams(d.query).toString()}`:"",U=d.req.method||"",R,te=0,Gs=await O.getServices();for(let H of Gs)H.active&&C.startsWith(H.prefix)&&H.prefix.length>te&&(R=H,te=H.prefix.length);if(!R)return A();let Lt=d.state.user;if(!(C.match(/^\/sites\/projects\/[^/]+.*/)&&U==="GET")&&Lt&&Rs(Lt,U,C),R.healthCheck&&R.healthCheck.healthy===!1)return d.json({error:"Service unavailable (unhealthy)"},503);let Nt=(C.substring(R.prefix.length)||"/")+M,_=null,dt=null,pt=null;if(["POST","PUT","PATCH","DELETE"].includes(U)){let H=d.headers["content-type"]||"";if(H.includes("application/json"))try{let ie=await S(d);pt=ie,_=JSON.stringify(ie)}catch{_=null}else if(H.includes("multipart/form-data"))try{_=JSON.stringify(d.body),dt="application/json"}catch{_=null}else try{_=Buffer.isBuffer(d.body)?d.body:Buffer.from(d.body)}catch{_=null}}let Me=R.name,qt=D?.mode==="core"?D.workers?.[Me]:void 0;if(qt&&Q){if(!Q.isHealthy(Me))return d.json({error:`Worker for ${Me} is unavailable`},503);try{let H=await bt(qt,Nt,U,_,d.headers,D?.secret);return Ct(d,H)}catch(H){return console.error(`[Server] Worker proxy error for ${Me}:`,H.message),d.json({error:H.message},H.statusCode||503)}}return new Promise(H=>{let ie={...d.headers,host:`127.0.0.1:${R.port}`};dt&&(ie["content-type"]=dt),_&&(typeof _=="string"?ie["content-length"]=Buffer.byteLength(_).toString():ie["content-length"]=_.length.toString());let zs={method:U,hostname:"127.0.0.1",port:R.port,path:Nt,headers:ie},xe=An.request(zs,V=>{let Ft=[];V.on("data",pe=>{Ft.push(pe)}),V.on("end",()=>{let pe=Buffer.concat(Ft),mt={};Object.entries(V.headers).forEach(([Ce,re])=>{re!==void 0&&(mt[Ce]=Array.isArray(re)?re.join(", "):re)});let be=V.headers["content-type"]||"",W;if(be.includes("application/json"))try{let Ce=JSON.parse(pe.toString("utf-8")),re=V.statusCode||200;Ce.success&&re>=200&&re<300&&pt?.context&&Bs(C,U,pt.context,Ce),W=d.json(Ce,re)}catch{W=d.text(pe.toString("utf-8"),V.statusCode||200)}else be.startsWith("text/")||be.includes("javascript")||be.includes("xml")?W=d.text(pe.toString("utf-8"),V.statusCode||200):(W=d.binary(pe,be||"application/octet-stream"),V.statusCode&&V.statusCode!==200&&(W.statusCode=V.statusCode));W.headers?W.headers={...W.headers,...mt}:W.headers=mt,H(W)})});xe.on("error",V=>{H(d.json({error:"Proxy Error",message:V.message},502))}),xe.on("timeout",()=>{xe.destroy(),H(d.json({error:"Gateway Timeout"},504))}),_&&xe.write(_),xe.end()})}catch(C){return Ht(d,C)}}async function y(d,A){try{let C=d.headers.authorization;if(!C)return d.text("Unauthorized",401);let M=await a.getUserFromToken(C);return M?(d.state.user=M,d.state.requestingIdentity=M,A()):d.text("Unauthorized",401)}catch(C){return Ht(d,C)}}function Ht(d,A){let C=A.message||A,M=A?.cause?.statusCode||400;return d.json({error:C},M)}let Dt=f.start();async function Vs(){ut||(ut=!0,await new Promise((d,A)=>{Dt.close(C=>{C?A(C):d()})}),console.log("[Server] Stopping managed services..."),await O.shutdown(),p&&p.shutdown(),console.log("[Server] Stopping AI service..."),ee.stop(),await r.close())}return{server:Dt,shutdown:Vs,processManager:O,identityService:a}}import kn from"node:http";import{join as Pn}from"node:path";async function Ms(t){let{config:e,dataPath:r,cluster:s}=t,i=new ke({...e});if(s.secret){let l=Pe(s.secret);i.use(l)}let n=new ge({dbPath:Pn(r,"molnosdb")});await n.start();let o=s.capabilities||[];console.log(`[Worker] Starting capabilities: ${o.join(", ")}`);for(let l of o)await n.startService(l);let a=async l=>{let u=l.path,p=Object.keys(l.query).length>0?`?${new URLSearchParams(l.query).toString()}`:"",m=l.req.method||"GET",b=(await n.getServices()).find(F=>u.startsWith(`/${F.name}`)&&F.active);if(!b)return l.json({error:"Service not found"},404);let z=(u.substring(`/${b.name}`.length)||"/")+p,ve=null;["POST","PUT","PATCH","DELETE"].includes(m)&&(l.headers["content-type"]||"").includes("application/json")&&l.body&&(ve=JSON.stringify(l.body));let O={};for(let[F,D]of Object.entries(l.headers))F.toLowerCase()!==le&&D&&(O[F]=typeof D=="string"?D:D[0]);return new Promise(F=>{let D={method:m,hostname:"127.0.0.1",port:b.port,path:z,headers:O},Q=kn.request(D,L=>{let j="";L.on("data",se=>{j+=se}),L.on("end",()=>{if((L.headers["content-type"]||"").includes("application/json"))try{F(l.json(JSON.parse(j),L.statusCode||200))}catch{F(l.text(j,L.statusCode||200))}else F(l.text(j,L.statusCode||200))})});Q.on("error",()=>{F(l.json({error:"Service unavailable"},503))}),ve&&Q.write(ve),Q.end()})};i.get("/health",l=>l.json({status:"ok",mode:"worker"})),i.post("/management/service/:serviceName/start",async l=>{let u=l.params?.serviceName;if(!u)return l.json({error:"Service name required"},400);if(!o.includes(u))return l.json({error:`This worker does not handle capability: ${u}`},400);let p=await n.startService(u);return l.json({serviceName:u,isStarted:p})}),i.post("/management/service/:serviceName/stop",async l=>{let u=l.params?.serviceName;if(!u)return l.json({error:"Service name required"},400);if(!o.includes(u))return l.json({error:`This worker does not handle capability: ${u}`},400);let p=await n.stopService(u);return l.json({serviceName:u,isStopped:p})}),i.post("/management/service/:serviceName/restart",async l=>{let u=l.params?.serviceName;if(!u)return l.json({error:"Service name required"},400);if(!o.includes(u))return l.json({error:`This worker does not handle capability: ${u}`},400);let p=await n.restartService(u);return l.json({serviceName:u,isRestarted:p})});for(let l of o)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 n.shutdown()}}}var Hs=()=>{let t=Us(process.env.DEBUG)||!1,e=Us(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||je(),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 Us(t){return t==="true"||t===!0}var I=Hs(),Ds={configFilePath:"molnos.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:"--consoleUrl",path:"auth.consoleUrl",defaultValue:I.auth.consoleUrl},{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:"--db",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:"--http2",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:"--allowed",path:"server.allowedDomains",defaultValue:I.server.allowedDomains,parser:oe.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:I.server.debug},{flag:"--data-path",path:"dataPath",defaultValue:I.molnos.dataPath},{flag:"--initialUserId",path:"molnos.initialUser.id",defaultValue:I.molnos.initialUser.id},{flag:"--initialUserName",path:"molnos.initialUser.userName",defaultValue:I.molnos.initialUser.userName},{flag:"--initialUserEmail",path:"molnos.initialUser.email",defaultValue:I.molnos.initialUser.email}]};function Ls(t){return{...t,auth:{...t.auth,templates:{textVersion:(e,r,s)=>{let i=new URL(e),n=i.searchParams.get("token")||"",o=i.searchParams.get("email")||"",a=s?.appName||"MolnOS",c=s?.redirectUrl&&s?.applicationId,l=c?`Sign in to ${a}`:"Sign in to MolnOS",u=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`
311
404
  ${l}
312
405
 
313
- ${d}
406
+ ${u}
314
407
 
315
408
  ${e}
316
409
 
317
410
  ${c?"":`For CLI/Terminal users:
318
- Run: molnos auth verify ${o} ${n}
411
+ Run: molnos auth verify ${n} ${o}
319
412
  `}
320
413
  This link expires in ${r} minutes and can only be used once.
321
414
  If you didn't request this, please ignore this email.
322
- `},htmlVersion:(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",d=c?`You're signing in to <strong>${a}</strong>. Click the button below to complete the authentication process. You'll be redirected to the application after verification.`:"Click the button below to sign in to your account.",u=c?"":`
415
+ `},htmlVersion:(e,r,s)=>{let i=new URL(e),n=i.searchParams.get("token")||"",o=i.searchParams.get("email")||"",a=s?.appName||"MolnOS",c=s?.redirectUrl&&s?.applicationId,l=c?`Sign in to ${a}`:"Sign in to MolnOS",u=c?`You're signing in to <strong>${a}</strong>. Click the button below to complete the authentication process. You'll be redirected to the application after verification.`:"Click the button below to sign in to your account.",p=c?"":`
323
416
  <div style="margin-top: 2rem; padding: 1rem; background-color: #f8f8f8; border-radius: 6px; border-left: 3px solid #3e63dd;">
324
417
  <p style="font-size: 0.85rem; font-weight: 600; margin: 0 0 0.5rem 0; color: #202020;">CLI/Terminal Users</p>
325
418
  <p style="font-size: 0.8rem; line-height: 1.5; margin: 0 0 0.75rem 0; color: #646464;">Run this command in your terminal (click to select, then copy):</p>
326
- <code style="display: block; padding: 0.75rem; background-color: #ffffff; border: 1px solid #e0e0e0; border-radius: 4px; font-size: 0.75rem; color: #202020; font-family: 'Courier New', Courier, monospace; overflow-x: auto; white-space: nowrap; user-select: all; -webkit-user-select: all; -moz-user-select: all; -ms-user-select: all; cursor: pointer;">molnos auth verify ${o} ${n}</code>
419
+ <code style="display: block; padding: 0.75rem; background-color: #ffffff; border: 1px solid #e0e0e0; border-radius: 4px; font-size: 0.75rem; color: #202020; font-family: 'Courier New', Courier, monospace; overflow-x: auto; white-space: nowrap; user-select: all; -webkit-user-select: all; -moz-user-select: all; -ms-user-select: all; cursor: pointer;">molnos auth verify ${n} ${o}</code>
327
420
  </div>
328
421
  `;return`
329
422
  <!DOCTYPE html>
@@ -336,12 +429,12 @@ If you didn't request this, please ignore this email.
336
429
  <body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
337
430
  <div style="max-width: 600px; margin: 0 auto; padding: 2rem;">
338
431
  <h1 style="font-size: 1.5rem; font-weight: 600; margin: 0 0 1rem 0; color: #202020;">${l}</h1>
339
- <p style="font-size: 0.9rem; line-height: 1.5; margin: 0 0 1.5rem 0; color: #646464;">${d}</p>
432
+ <p style="font-size: 0.9rem; line-height: 1.5; margin: 0 0 1.5rem 0; color: #646464;">${u}</p>
340
433
  <a href="${e}" style="display: inline-block; padding: 0.75rem 1.5rem; background-color: #3e63dd; color: #ffffff; text-decoration: none; border-radius: 6px; font-size: 0.9rem; font-weight: 500;">Sign in</a>
341
- ${u}
434
+ ${p}
342
435
  <p style="font-size: 0.8rem; line-height: 1.5; margin: 1.5rem 0 0 0; color: #8d8d8d;">This link expires in ${r} minutes and can only be used once. If you didn't request this, please ignore this email.</p>
343
436
  </div>
344
437
  </body>
345
438
  </html>
346
- `}}}}}function Ts(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 fo,mkdirSync as go,existsSync as yo}from"node:fs";import{join as vo}from"node:path";function Rs(t){let e=t.molnos.dataPath||"data";yo(e)||go(e,{recursive:!0});let r=vo(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 d=i[l]||{},u=d.host||s,m=d.port||o[l],v=d.secure?"https":"http";return{host:u,port:m,url:`${v}://${u}:${m}`}},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 fo(r,JSON.stringify(c,null,2),"utf-8"),r}async function So(){let t=xo(),e=Es(t),r=Ts(e);if(!r.success)throw console.error(`Found configuration validation errors: ${JSON.stringify(r.errors)}`),new He("Invalid configuration provided. Please see the validation errors and fix these and then retry again.");Rs(e);let s=e.molnos.dataPath||"data",i=e.molnos?.cluster;if(i?.mode==="worker"){let u=await Is({config:e.server,dataPath:s,cluster:i});js(u);return}let o=new ne({databaseDirectory:wo(s,"molnosdb")});await o.start();let n=new Bt(o),a=new Vt(e.email),c={...e,auth:{...e.auth,appUrl:e.auth.consoleUrl}},l=new qt(c,a,n),d=await Cs({config:e.server,molnos:e.molnos,auth:l,db:o,oauth:e.oauth,ai:e.ai});js(d)}function js(t){let e=async r=>{console.log(`
347
- [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 xo(){return new re(Ps).get()}So();export{So as start};
439
+ `}}}}}function Ns(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 En,mkdirSync as Tn,existsSync as Rn}from"node:fs";import{randomBytes as jn,createHmac as $n}from"node:crypto";import{join as On}from"node:path";function qs(t){let e=t.molnos.dataPath||"data";Rn(e)||Tn(e,{recursive:!0});let r=On(e,".runtime-config.json"),s=t.server.host||"127.0.0.1",i=t.molnos.services||{},n={storage:3001,functions:3002,sites:3003,databases:3004,observability:3005},o=l=>{let u=i[l]||{},p=u.host||s,m=u.port||n[l],w=u.secure?"https":"http";return{host:p,port:m,url:`${w}://${p}:${m}`}},a={storage:o("storage"),functions:o("functions"),sites:o("sites"),databases:o("databases"),observability:o("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}`},internalServiceSecret:t.molnos.cluster?.secret?$n("sha256",t.molnos.cluster.secret).update("molnos-internal-service").digest("hex"):jn(32).toString("hex"),services:a,storage:t.storage};return En(r,JSON.stringify(c,null,2),"utf-8"),r}async function Un(){let t=Hn(),e=Ls(t),r=Ns(e);if(!r.success)throw console.error(`Found configuration validation errors: ${JSON.stringify(r.errors)}`),new Ne("Invalid configuration provided. Please see the validation errors and fix these and then retry again.");qs(e);let s=e.molnos.dataPath||"data",i=e.molnos?.cluster;if(i?.mode==="worker"){let p=await Ms({config:e.server,dataPath:s,cluster:i});Fs(p);return}let n=new J({databaseDirectory:Mn(s,"molnosdb")});await n.start();let o=new Kt(n),a=new Xt(e.email),c={...e,auth:{...e.auth,appUrl:e.auth.consoleUrl}},l=new Jt(c,a,o),u=await Os({config:e.server,molnos:e.molnos,auth:l,db:n,oauth:e.oauth,ai:e.ai});Fs(u)}function Fs(t){let e=async r=>{console.log(`
440
+ [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 Hn(){return new ne(Ds).get()}Un();export{Un as start};