molnos 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION +1 -1
- package/dist/databases.mjs +4 -4
- package/dist/functions.mjs +4 -4
- package/dist/molnos_core.mjs +33 -32
- package/dist/observability.mjs +6 -6
- package/dist/sites.mjs +3 -3
- package/dist/storage.mjs +4 -4
- package/package.json +1 -1
- package/sbom.json +1 -1
package/dist/molnos_core.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// MolnOS Core - See LICENSE file for copyright and license details.
|
|
2
|
-
import
|
|
2
|
+
import le,{createHash as Un,createHmac as Nn,scryptSync as ni,randomBytes as ai,createCipheriv as ci,createDecipheriv as li}from"crypto";import{URL as ui}from"url";var yt=class extends Error{constructor(t){super(t),this.name="ValidationError",this.message=t||"Validation did not pass",this.cause={statusCode:400}}};import{existsSync as Zs,readFileSync as Qs}from"node:fs";var ae=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&&Zs(t))try{let a=Qs(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 yt(t.message);if(typeof r=="string")throw new yt(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
|
|
9
|
-
`);if(l.length>0&&l[l.length-1]===""){let u=l[l.length-2]||"",
|
|
8
|
+
`;return t}};var ce={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 di}from"events";var Gt=class extends Error{constructor(t){super(),this.name="ValidationError",this.message=t,this.cause={statusCode:400}}};import{existsSync as ei,readFileSync as ti}from"fs";var zt=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(ei(t))try{let n=ti(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 Gt("Host value not found")}get(){return this.validate(),this.config}};import{promises as ri}from"dns";function ke(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 si(t){try{let e=await ri.resolveMx(t);return!!e&&e.length>0}catch{return!1}}async function Wt(t){try{let e=t.split("@")[1];return e?await si(e):!1}catch{return!1}}import{Buffer as Pe}from"buffer";import vt from"crypto";import ii from"net";import oi from"os";import Jt from"tls";var Kt=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??oi.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=Jt.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=ii.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=Jt.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 u=l[l.length-2]||"",d=/^(\d{3})(.?)/.exec(u);d?.[1]&&d[2]!=="-"&&(this.socket?.removeListener("data",a),clearTimeout(o),this.log(`SMTP Response: ${n.trim()}`),d[1]===e.toString()?s(n.trim()):i(new Error(`SMTP Error: ${n.trim()}`)))}};this.socket.on("data",a),t.startsWith("AUTH PLAIN")||t.startsWith("AUTH LOGIN")||this.lastCommand==="AUTH LOGIN"&&!t.startsWith("AUTH")?this.log("SMTP Command: [Credentials hidden]"):this.log(`SMTP Command: ${t}`),this.lastCommand=t,this.socket.write(`${t}\r
|
|
10
10
|
`)})}parseCapabilities(t){let e=t.split(`\r
|
|
11
|
-
`);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=
|
|
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=Pe.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(Pe.from(this.config.user).toString("base64"),334),await this.sendCommand(Pe.from(this.config.password).toString("base64"),235)}async authenticateCramMD5(){let t=await this.sendCommand("AUTH CRAM-MD5",334),e=Pe.from(t.substr(4),"base64").toString("utf8"),r=vt.createHmac("md5",this.config.password);r.update(e);let s=r.digest("hex"),i=`${this.config.user} ${s}`,o=Pe.from(i).toString("base64");await this.sendCommand(o,235)}generateMessageId(){let t=vt.randomBytes(16).toString("hex"),e=this.config.user.split("@")[1]||"localhost";return`<${t}@${e}>`}generateBoundary(){return`----=_NextPart_${vt.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
|
|
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||"",
|
|
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
|
|
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(!ke(e))return{success:!1,error:"Invalid email address format"};for(let a of n)if(!ke(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 n)await this.sendCommand(`RCPT TO:<${u}>`,250);if(t.cc){let u=Array.isArray(t.cc)?t.cc:[t.cc];for(let d of u)ke(d)&&await this.sendCommand(`RCPT TO:<${d}>`,250)}if(t.bcc){let u=Array.isArray(t.bcc)?t.bcc:[t.bcc];for(let d of u)ke(d)&&await this.sendCommand(`RCPT TO:<${d}>`,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 St=class{smtpClient;config;constructor(t){let e=new zt(t).get(),r=new Kt(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 Wt(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 wt=()=>{let t=pi(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 pi(t){return t==="true"||t===!0}var mi=class{algorithm="HS256";secret="HS256";constructor(t){if(process.env.NODE_ENV==="production"&&(!t||t.length<32||t===wt().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=le.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()}},hi=class{templates;constructor(t){t?this.templates=t:this.templates=fi}getText(t,e,r){return this.templates.textVersion(t,e,r).trim()}getHtml(t,e,r){return this.templates.htmlVersion(t,e,r).trim()}},fi={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
|
-
`},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
|
|
111
|
+
`},gi=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=[]}},yi=class{data=new Map;collections=new Map;expiryEmitter=new di;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 Xt(t){if(!t||t.trim()===""||(t.match(/@/g)||[]).length!==1)return!1;let[e,r]=t.split("@");return!(!e||!r||t.includes("..")||!vi(e)||!Si(r))}function vi(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:")?bi(r.slice(5)):wi(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 wi(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 bi(t){if(!/^[a-fA-F0-9:]+$/.test(t))return!1;let e=t.split(":");return!(e.length<2||e.length>8)}var E=wt(),xi=t=>{let e={configFilePath:"mikroauth.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:E.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:E.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:E.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:E.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:E.auth.maxActiveSessions},{flag:"--appUrl",path:"auth.appUrl",defaultValue:E.auth.appUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:E.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:E.email.host},{flag:"--emailUser",path:"email.user",defaultValue:E.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:E.email.password},{flag:"--emailPort",path:"email.port",defaultValue:E.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:E.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:E.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:E.email.debug},{flag:"--dir",path:"storage.databaseDirectory",defaultValue:E.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:E.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:E.storage.debug},{flag:"--port",path:"server.port",defaultValue:E.server.port},{flag:"--host",path:"server.host",defaultValue:E.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:E.server.useHttps},{flag:"--https",path:"server.useHttp2",isFlag:!0,defaultValue:E.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:E.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:E.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:E.server.sslCa},{flag:"--ratelimit",path:"server.rateLimit.enabled",defaultValue:E.server.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"server.rateLimit.requestsPerMinute",defaultValue:E.server.rateLimit.requestsPerMinute},{flag:"--allowed",path:"server.allowedDomains",defaultValue:E.server.allowedDomains,parser:ce.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:E.server.debug}]};return t&&(e.config=t),e},Le={linkSent:"If a matching account was found, a magic link has been sent.",revokedSuccess:"All other sessions revoked successfully.",logoutSuccess:"Logged out successfully."},Yt=class{config;email;storage;jwtService;templates;constructor(t,e,r){let s=new ae(xi({auth:t.auth,email:t.email})).get();s.auth.debug&&console.log("Using configuration:",s),this.config=s,this.email=e||new gi,this.storage=r||new yi,this.jwtService=new mi(s.auth.jwtSecret),this.templates=new hi(s?.auth.templates),this.checkIfUsingDefaultCredentialsInProduction()}checkIfUsingDefaultCredentialsInProduction(){process.env.NODE_ENV==="production"&&this.config.auth.jwtSecret===wt().auth.jwtSecret&&(console.error("WARNING: Using default secrets in production environment!"),process.exit(1))}generateToken(t){let e=Date.now().toString(),r=le.randomBytes(32).toString("hex");return le.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 le.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 ui(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(!Xt(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 f of l){if(f===a)continue;let w=await this.storage.get(f);if(w)try{JSON.parse(w).email===e&&await this.storage.delete(f)}catch{}}let u=this.generateMagicLinkUrl({token:n,email:e,appUrl:i}),d=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(u,d,s),html:this.templates.getHtml(u,d,s)}),{message:Le.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(!Xt(e))throw new Error("Valid email required");try{let o=le.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}),u={email:e,username:r,role:s,ipAddress:i||"unknown",tokenId:o,createdAt:a,lastLogin:a};return await this.trackSession(e,n,u),{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=le.randomBytes(16).toString("hex"),l=this.generateRefreshToken(),u={sub:r,username:n,role:a,jti:c,lastLogin:o.createdAt,metadata:{ip:o.ipAddress},exp:Math.floor(Date.now()/1e3)+3600*24},d=this.jwtService.sign(u,{exp:this.config.auth.jwtExpirySeconds});return await this.trackSession(r,l,{...o,tokenId:c,createdAt:Date.now()}),{accessToken:d,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=le.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:Le.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:Le.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:Le.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)}}},Ci=class{key;algorithm="aes-256-gcm";keyLength=32;constructor(t){this.key=ni(t,"mikroauth-salt",this.keyLength)}encrypt(t){let e=ai(12),r=ci(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=li(this.algorithm,this.key,o);return c.setAuthTag(n),Buffer.concat([c.update(a),c.final()]).toString("utf8")}},Zt=class{db;encryption;PREFIX_KV="kv:";PREFIX_COLLECTION="coll:";TABLE_NAME="mikroauth";constructor(t,e){this.db=t,e&&(this.encryption=new Ci(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)):[]}},Qt=class{email;sender;constructor(t){this.sender=t.user,this.email=new St({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:er(t.deflate)}:{deflate:er(t.inflate),inflate:t.inflate}}function er(t){let e={};for(let[r,s]of Object.entries(t))e[s]=r;return e}function fe(t,e){if(t==null||typeof t!="object")return t;if(Array.isArray(t))return t.map(s=>fe(s,e));let r={};for(let[s,i]of Object.entries(t)){let o=e[s]||s;r[o]=fe(i,e)}return r}function ue(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 qe(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 tr(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 bt,mkdirSync as Ii,readdirSync as Ai,openSync as ki,closeSync as Pi}from"fs";import{readFile as Ei,writeFile as Ri,rename as Ti,unlink as rr,open as ji}from"fs/promises";import{join as xt,dirname as Oi}from"path";var X=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)}),bt(this.databaseDirectory)||Ii(this.databaseDirectory,{recursive:!0})}async start(){try{let t=Ai(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(ue(t),qe(e),tr(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){ue(t),e!==void 0&&qe(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){ue(t),qe(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){ue(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){ue(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){ue(t);try{this.data.delete(t);let e=xt(this.databaseDirectory,t);return bt(e)&&await rr(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=xt(this.databaseDirectory,t);if(!bt(e)){this.data.set(t,new Map);return}try{let r=await Ei(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=xt(this.databaseDirectory,t),i=`${s}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await Ri(i,r),this.useFsync){let o=await ji(i,"r+");try{await o.sync()}finally{await o.close()}}if(await Ti(i,s),this.useFsync){let o=Oi(s),n=ki(o,"r");try{Pi(n)}catch{}}}catch(o){try{await rr(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?fe(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?fe(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 _o}from"node:path";import Oo from"node:http";import{join as pt}from"node:path";var sr=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 $i}from"url";var ir=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 $i(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((d,f)=>{c[f]=d});let l={req:t,res:e,params:a,query:c,body:t.body||{},headers:t.headers,path:i,state:{},raw:()=>e,binary:(d,f="application/octet-stream",w=200)=>({statusCode:w,body:d,headers:{"Content-Type":f,"Content-Length":d.length.toString()},isRaw:!0}),text:(d,f=200)=>({statusCode:f,body:d,headers:{"Content-Type":"text/plain"}}),form:(d,f=200)=>({statusCode:f,body:d,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),json:(d,f=200)=>({statusCode:f,body:d,headers:{"Content-Type":"application/json"}}),html:(d,f=200)=>({statusCode:f,body:d,headers:{"Content-Type":"text/html"}}),redirect:(d,f=302)=>({statusCode:f,body:null,headers:{Location:d}}),status:function(d){return{raw:()=>e,binary:(f,w="application/octet-stream")=>({statusCode:d,body:f,headers:{"Content-Type":w,"Content-Length":f.length.toString()},isRaw:!0}),text:f=>({statusCode:d,body:f,headers:{"Content-Type":"text/plain"}}),json:f=>({statusCode:d,body:f,headers:{"Content-Type":"application/json"}}),html:f=>({statusCode:d,body:f,headers:{"Content-Type":"text/html"}}),form:f=>({statusCode:d,body:f,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),redirect:(f,w=302)=>({statusCode:w,body:null,headers:{Location:f}}),status:f=>this.status(f)}}},u=[...this.globalMiddlewares,...n.middlewares];return this.executeMiddlewareChain(l,u,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 _e=()=>({port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",debug:Mi(process.env.DEBUG)||!1,maxBodySize:1048576,requestTimeout:3e4,rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"]});function Mi(t){return t==="true"||t===!0}var G=_e(),or=t=>({configFilePath:"mikroserve.config.json",args:process.argv,options:[{flag:"--port",path:"port",defaultValue:G.port},{flag:"--host",path:"host",defaultValue:G.host},{flag:"--https",path:"useHttps",defaultValue:G.useHttps,isFlag:!0},{flag:"--http2",path:"useHttp2",defaultValue:G.useHttp2,isFlag:!0},{flag:"--cert",path:"sslCert",defaultValue:G.sslCert},{flag:"--key",path:"sslKey",defaultValue:G.sslKey},{flag:"--ca",path:"sslCa",defaultValue:G.sslCa},{flag:"--ratelimit",path:"rateLimit.enabled",defaultValue:G.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"rateLimit.requestsPerMinute",defaultValue:G.rateLimit.requestsPerMinute},{flag:"--allowed",path:"allowedDomains",defaultValue:G.allowedDomains,parser:ce.array},{flag:"--debug",path:"debug",defaultValue:G.debug,isFlag:!0},{flag:"--max-body-size",path:"maxBodySize",defaultValue:G.maxBodySize},{flag:"--request-timeout",path:"requestTimeout",defaultValue:G.requestTimeout}],config:t});function nr(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=Ui(t,i);for(let l of c){if(l.length===0||l.equals(o.subarray(i.length)))continue;let u=Ni(l);if(!u)continue;let{name:d,filename:f,contentType:w,data:k}=u;if(f){let $={filename:f,contentType:w||"application/octet-stream",data:k,size:k.length};a[d]?Array.isArray(a[d])?a[d].push($):a[d]=[a[d],$]:a[d]=$}else{let $=k.toString("utf8");n[d]?Array.isArray(n[d])?n[d].push($):n[d]=[n[d],$]:n[d]=$}}return{fields:n,files:a}}function Ui(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 Ni(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),
|
|
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(
|
|
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(
|
|
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,u;for(let f of n){let w=f.toLowerCase();if(w.startsWith("content-disposition:")){a=f.substring(20).trim();let k=a.match(/name="([^"]+)"/);k&&(c=k[1]);let $=a.match(/filename="([^"]+)"/);$&&(l=$[1])}else w.startsWith("content-type:")&&(u=f.substring(13).trim())}if(!c)return null;let d=i;return d.length>=2&&d[d.length-2]===13&&d[d.length-1]===10&&(d=d.subarray(0,d.length-2)),{disposition:a,name:c,filename:l,contentType:u,data:d}}import{readFileSync as ge}from"fs";import Ct from"http";import Di from"http2";import Li from"https";var Ee=class{config;rateLimiter;router;shutdownHandlers=[];constructor(t){let e=new ae(or(t||{})).get();e.debug&&console.log("Using configuration:",e),this.config=e,this.router=new ir;let r=e.rateLimit.requestsPerMinute||_e().rateLimit.requestsPerMinute;this.rateLimiter=new sr(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:ge(this.config.sslKey),cert:ge(this.config.sslCert),...this.config.sslCa?{ca:ge(this.config.sslCa)}:{}};return Di.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:ge(this.config.sslKey),cert:ge(this.config.sslCert),...this.config.sslCa?{ca:ge(this.config.sslCa)}:{}};return Li.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 Ct.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 Ct.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 u=()=>{a&&(clearTimeout(a),a=null)};t.on("data",d=>{if(!n){if(i+=d.length,c&&console.log(`Received chunk: ${d.length} bytes, total size: ${i}`),i>o){n=!0,u(),c&&console.log(`Body size exceeded limit: ${i} > ${o}`),r(new Error("Request body too large"));return}s.push(d)}}),t.on("end",()=>{if(!n){n=!0,u(),c&&console.log(`Request body complete: ${i} bytes`);try{if(s.length>0){let d=Buffer.concat(s);if(l.includes("application/json"))try{let f=d.toString("utf8");e(JSON.parse(f))}catch(f){r(new Error(`Invalid JSON in request body: ${f.message}`))}else if(l.includes("application/x-www-form-urlencoded")){let f=d.toString("utf8"),w={};new URLSearchParams(f).forEach((k,$)=>{w[$]=k}),e(w)}else if(l.includes("multipart/form-data"))try{let f=nr(d,l);e(f)}catch(f){r(new Error(`Invalid multipart form data: ${f.message}`))}else this.isBinaryContentType(l)?e(d):e(d.toString("utf8"))}else e({})}catch(d){r(new Error(`Invalid request body: ${d}`))}}}),t.on("error",d=>{n||(n=!0,u(),r(new Error(`Error reading request body: ${d.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 Ct.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 Hi}from"node:crypto";var de="x-molnos-cluster-secret";function ar(t,e){if(!t)return!1;let r=Buffer.from(t),s=Buffer.from(e);return r.length!==s.length?!1:Hi(r,s)}function Re(t){return async(e,r)=>{let s=e.headers[de];return s?ar(s,t)?(e.state.isClusterRequest=!0,r()):e.json({success:!1,error:"Invalid cluster authentication"},403):r()}}function It(t,e){return{...t,[de]:e}}var x=class extends Error{constructor(e){super(),this.name="ValidationError",this.message=e||"Invalid input",this.cause={statusCode:400}}},Te=class extends Error{constructor(e){super(),this.name="IdentityAlreadyExistsError",this.message=e||"Identity already exists",this.cause={statusCode:400}}},F=class extends Error{constructor(e){super(),this.name="NotFoundError",this.message=e||"Resource not found",this.cause={statusCode:404}}},Fe=class extends Error{constructor(e){super(),this.name="InvalidInputError",this.message=e||"Invalid input",this.cause={statusCode:400}}};var Y=class extends Error{constructor(e){super(),this.name="ConfigurationError",this.message=e||"Invalid configuration",this.cause={statusCode:400}}};var ye=class extends Error{constructor(e){super(),this.name="PermissionDeniedError",this.message=e||"Permission denied",this.cause={statusCode:403}}},W=class extends Error{constructor(e){super(),this.name="AlreadyExistsError",this.message=e||"Resource already exists",this.cause={statusCode:409}}},Ve=class extends Error{constructor(e){super(),this.name="PortInUseError",this.message=e||"Port already in use",this.cause={statusCode:409}}},je=class extends Error{constructor(e){super(),this.name="RoleNotFoundError",this.message=e||"Role not found",this.cause={statusCode:404}}},Be=class extends Error{constructor(e){super(),this.name="ProtectedResourceError",this.message=e||"Cannot modify protected resource",this.cause={statusCode:403}}},Ge=class extends Error{constructor(e){super(),this.name="ServiceRequestError",this.message=e||"Service request failed",this.cause={statusCode:502}}},ze=class extends Error{constructor(e){super(),this.name="WorkerUnavailableError",this.message=e||"Worker node is unavailable",this.cause={statusCode:503}}},We=class extends Error{constructor(e){super(),this.name="WorkerTimeoutError",this.message=e||"Worker node did not respond in time",this.cause={statusCode:504}}};var qi=5e3;async function At(t,e,r,s,i,o){let n=new URL(e,t.url),a=new Headers;for(let[d,f]of Object.entries(i)){let w=d.toLowerCase();w==="host"||w==="connection"||w==="keep-alive"||w==="transfer-encoding"||a.set(d,f)}o&&a.set(de,o);let c=t.timeoutMs||qi,l=new AbortController,u=setTimeout(()=>l.abort(),c);try{let d;s&&(Buffer.isBuffer(s)?d=new Uint8Array(s):d=s);let f=await fetch(n.toString(),{method:r,headers:a,body:d,signal:l.signal});return clearTimeout(u),f}catch(d){throw clearTimeout(u),d.name==="AbortError"?new We(`Worker at ${t.url} did not respond within ${c}ms`):new ze(`Worker at ${t.url} is unavailable: ${d.message}`)}}async function kt(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 Je={healthCheckPath:"/health",healthCheckIntervalMs:3e4,timeoutMs:5e3,failureThreshold:3},Oe=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||Je.timeoutMs};this.workers.set(e,s);let i=r.healthCheckIntervalMs||Je.healthCheckIntervalMs,o=r.healthCheckPath||Je.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>=Je.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 _i}from"node:crypto";var Pt=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);_i(l);for(let u=0;u<a;u++){let d=l[u]&n;if(d<o.length&&(c+=o[d],c.length===e))break}}return c}};var Fi=8,Vi=40,Bi=/^[a-zA-Z0-9_-]{1,40}$/;function $e(){return new Pt().create(Fi,"alphanumeric",!1,!0)}function Gi(t){return Bi.test(t)}function zi(t){if(!Gi(t))throw new Error(`Invalid ID format: "${t}". IDs must be 1-${Vi} characters using only alphanumeric characters, underscores, and hyphens.`)}function Ke(t){return t?(zi(t),t):$e()}function lr(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(u=>cr(u?.permissions,a)&&cr(u?.targets,c)))return!1;return!0}function cr(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 pe=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 Ke()}isValidRoleId(e){return typeof e!="string"||e.length===0?!1:/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)}isValidType(e){return["user","service_account"].includes(e)}validate(e){let r=e.id||"",s=e.name||"",i=e.type||"",o=e.metadata||{},n=e.roles||[];if(!r)throw new x("Missing ID");if(!s)throw new x("Missing name");if(!i||!this.isValidType(i))throw new x("Missing or invalid type");if(i==="user"&&!o?.email)throw new x("Missing email for user identity");if(!n||n.length===0)throw new x("Must have at least one role");this.validateRoles(n)}validateRoles(e){(e||[]).forEach(r=>{let s=r.id||r;if(!this.isValidRoleId(s))throw new x(`Invalid role ID '${s}'`)})}can(e,r,s){return lr(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}}};var m={ai:{generation:{generate:"ai.generation.generate",read:"ai.generation.read",apply:"ai.generation.apply",discard:"ai.generation.discard",delete:"ai.generation.delete"}},applications:{application:{create:"applications.application.create",read:"applications.application.read",list:"applications.application.list",update:"applications.application.update",delete:"applications.application.delete"}},contexts:{context:{create:"contexts.context.create",get:"contexts.context.get",update:"contexts.context.update",delete:"contexts.context.delete",deleteResources:"contexts.context.delete-resources"}},databases:{table:{create:"databases.table.create",get:"databases.table.get",update:"databases.table.update",delete:"databases.table.delete"}},functions:{function:{create:"functions.function.create",get:"functions.function.get",update:"functions.function.update",delete:"functions.function.delete",execute:"functions.function.execute"}},iac:{config:{create:"iac.config.create",get:"iac.config.get"}},identity:{identities:{get:"identity.identities.get"},user:{create:"identity.user.create",get:"identity.user.get",update:"identity.user.update",delete:"identity.user.delete"},role:{create:"identity.role.create",get:"identity.role.get",update:"identity.role.update",delete:"identity.role.delete"},serviceAccount:{create:"identity.service-account.create",get:"identity.service-account.get",update:"identity.service-account.update",delete:"identity.service-account.delete"}},management:{service:{create:"management.service.create",get:"management.service.get",update:"management.service.update",delete:"management.service.delete",start:"management.service.start",stop:"management.service.stop"},services:{get:"management.services.get"}},observability:{event:{create:"observability.event.create",read:"observability.event.read",delete:"observability.event.delete"},stats:{read:"observability.stats.read"},buffer:{write:"observability.buffer.write"},metrics:{read:"observability.metrics.read"}},schemas:{schema:{create:"schemas.schema.create",read:"schemas.schema.read",list:"schemas.schema.list",update:"schemas.schema.update",delete:"schemas.schema.delete"}},sites:{project:{create:"sites.project.create",list:"sites.project.list",delete:"sites.project.delete",download:"sites.project.download"}},storage:{bucket:{create:"storage.bucket.create",read:"storage.bucket.read",update:"storage.bucket.update",delete:"storage.bucket.delete",list:"storage.bucket.list"},object:{write:"storage.object.write",read:"storage.object.read",delete:"storage.object.delete",list:"storage.object.list"}}},Me={ALL:"*",ANY_READ:"*.read",ANY_GET:"*.get",ANY_LIST:"*.list"};function ur(t,e){if(typeof t=="string"){e.push(t);return}if(!(!t||typeof t!="object"))for(let r of Object.values(t))ur(r,e)}var dr=[];ur(m,dr);var Wi=[...new Set(dr)],ac=Object.freeze(Wi);function pr(){return[{id:"administrator",name:"Administrator",description:"Full system administrator with all permissions",policies:[{permissions:[Me.ALL],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:[Me.ANY_READ,Me.ANY_GET,Me.ANY_LIST],targets:["*"]}],constraints:{assumable_by:{identities:[],roles:[],services:[]},assumption_constraints:{max_duration:3600,require_reason:!1,audit_level:"low"}}}]}var Xe=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=pr();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 Te(`User with email ${e} already exists`);let c=new pe({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 Te(`Service account with name ${e} already exists`);let a=new pe({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 pe().fromDTO(s);r?.name&&i.changeName(r.name),r?.email&&i.changeEmail(r.email),r?.roles&&i.updateRoles(r.roles),r?.metadata&&i.updateMetadata(r.metadata);let o=i.toDTO();return this.updateIdentityList(o),await this.saveState(),this.enrichIdentityWithRoles(o)}updateIdentityList(e){if(!e)throw new x("Cannot update identity list: updatedIdentity is null or undefined");let r=JSON.parse(JSON.stringify(this.identities)),s=r.find(i=>i.id===e.id);s&&Object.assign(s,e),this.identities=r}generateServiceAccountToken(){return`sa.${$e()}.${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 pe(s).can(e,r,s)}async createCustomRole(e,r,s,i,o){if(this.roles.find(l=>l.id===e))throw new W(`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 je(`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 je(`Role with ID ${e} not found`);if(e==="administrator"||e==="user")throw new Be("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 Ki}from"node:fs";import{spawn as Xi}from"node:child_process";import{createServer as Yi}from"node:net";var mr={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"]}},ve=class{db;services=new Map;tableName="molnosmanagement";environmentVariables={};clusterConfig;setEnvironmentVariables(e){this.environmentVariables={...this.environmentVariables,...e}}setClusterConfig(e){this.clusterConfig=e}shouldSpawnLocally(e){if(!this.clusterConfig||this.clusterConfig.mode==="standalone")return!0;let r=e;return this.clusterConfig.mode==="core"?!this.clusterConfig.workers?.[r]:this.clusterConfig.mode==="worker"?this.clusterConfig.capabilities?.includes(r)??!1:!0}getWorkerEndpoint(e){if(!this.clusterConfig||this.clusterConfig.mode!=="core")return null;let r=e;return this.clusterConfig.workers?.[r]?.url??null}async forwardToWorker(e,r){let s=this.getWorkerEndpoint(e);if(!s)return console.error(`[ManagementService] No worker configured for capability: ${e}`),!1;let i=this.clusterConfig?.secret;if(!i)return console.error("[ManagementService] Cannot forward to worker: no cluster secret configured"),!1;let o=`${s}/management/service/${e}/${r}`,n=It({"Content-Type":"application/json"},i);try{let a=await fetch(o,{method:"POST",headers:n});if(!a.ok){let l=await a.text();return console.error(`[ManagementService] Worker returned error for ${r} ${e}: ${l}`),!1}let c=await a.json();return c.isStarted??c.isStopped??c.isRestarted??!1}catch(a){return console.error(`[ManagementService] Failed to forward ${r} ${e} to worker:`,a),!1}}async isPortInUse(e){return new Promise(r=>{let s=Yi();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 X({databaseDirectory:e.dbPath})}getServiceDefinition(e){let r=e.toLowerCase(),s=mr[r];if(!s)throw new F(`Unknown service: ${e}. Valid services are: ${Object.keys(mr).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(!Ki(e.path))throw new Y(`Service path does not exist: ${e.path}`);if(!e.port||e.port<1||e.port>65535)throw new x(`Invalid port: ${e.port}`);if(!e.prefix||!e.prefix.startsWith("/"))throw new x("Service prefix must start with /")}cleanServiceForStorage(e){let{process:r,...s}=e;if(s.healthCheck){let{timer:i,consecutiveFailures:o,consecutiveSuccesses:n,healthy:a,...c}=s.healthCheck;s.healthCheck=c}if(s.restartPolicy){let{attempts:i,...o}=s.restartPolicy;s.restartPolicy=o}return s}async registerService(e,r){let s;typeof e=="string"?s={...this.getServiceDefinition(e),...r}:s=e,this.validateServiceConfig(s);let i={...s,active:!1},o=await this.getServices(),n=[],a=[];if(o.forEach(l=>{n.push(l.name),a.push(l.port)}),a.includes(i.port))throw new Ve(`Port ${i.port} already in use`);if(n.includes(i.name))throw new W(`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=Xi("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 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,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 Z=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 Ke()}validate(e){let{id:r,name:s,redirectUris:i,metadata:o,owners:n}=e;if(!r)throw new x("Missing ID");if(!s||s.trim().length===0)throw new x("Missing or invalid name");if(!o)throw new x("Missing metadata");if(!n||n.length===0)throw new x("Application must have at least one owner");this.validateRedirectUris(i)}validateRedirectUris(e){if(!e||e.length===0)throw new x("At least one redirect URI is required");for(let r of e)try{let s=new URL(r);if(s.protocol!=="https:"&&s.protocol!=="http:"&&s.protocol!=="custom:")throw new x(`Invalid redirect URI protocol: ${r}. Must use https:, http: (localhost only), or custom: (for native apps)`);s.protocol==="http:"&&!s.hostname.match(/^(localhost|127\.0\.0\.1|\[::1\])$/)&&console.warn(`Warning: HTTP redirect URI detected for non-localhost: ${r}. HTTPS is recommended for production.`)}catch{throw new x(`Invalid redirect URI format: ${r}`)}}fromDTO(e){return this.validate(e),this.id=e.id,this.name=e.name,this.description=e.description,this.redirectUris=e.redirectUris,this.metadata=e.metadata,this.owners=e.owners,this}toDTO(){return{id:this.id,name:this.name,description:this.description,redirectUris:this.redirectUris,metadata:this.metadata,owners:this.owners}}};var Ye=class{db;tableName="molnosapplications";key="applications";applications;constructor(e){this.db=new X({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 Z({...e,owners:s,metadata:{...e.metadata,createdBy:r}}).toDTO();if(this.applications.find(a=>a.name===o.name))throw new W(`Application with name '${o.name}' already exists`);return this.applications.push(o),await this.saveState(),o}async getApplication(e,r){let s=this.applications.find(o=>o.id===e);if(!s)throw new F(`Application with ID '${e}' not found`);let i=new Z().fromDTO(s);if(r&&!i.isOwner(r))throw new ye("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 Z().fromDTO(r).toDTO())}async updateApplication(e,r,s){let i=this.applications.findIndex(a=>a.id===e);if(i===-1)throw new F(`Application with ID '${e}' not found`);let o=this.applications[i],n=new Z().fromDTO(o);if(!n.isOwner(s))throw new ye("Only application owners can update the application");if(r.owners&&r.owners.length===0)throw new x("Application must have at least one owner");if(r.owners&&!r.owners.includes(s)&&o.owners.length===1&&o.owners[0]===s)throw new x("Cannot remove yourself as the last owner of the application");return n.update(r),this.applications[i]=n.toDTO(),await this.saveState(),this.applications[i]}async deleteApplication(e,r){let s=this.applications.findIndex(n=>n.id===e);if(s===-1)throw new F(`Application with ID '${e}' not found`);let i=this.applications[s];if(!new Z().fromDTO(i).isOwner(r))throw new ye("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 Z().fromDTO(s).isValidRedirectUri(r):!1}getAllApplicationsInternal(){return this.applications}};var Zi=/^[a-z0-9][a-z0-9-]*[a-z0-9]$/,Ue=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,o=e?.schema||{properties:{}},n=new Date().toISOString(),a=e?.createdAt||n,c=n;return e&&this.validate({name:r,schema:o}),{name:r,version:s,description:i,schema:o,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 Ze=class{db;tableName="molnosschemas";key="schemas";schemas;constructor(e){this.db=new X({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(o=>o.name===e.name))throw new W(`Schema with name '${e.name}' already exists`);let i=new Ue(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 F(`Schema '${e}'${i} not found`)}return s}async listSchemas(){return[...this.schemas]}async updateSchema(e,r){let s=this.schemas.findIndex(n=>n.name===e);if(s===-1)throw new F(`Schema '${e}' not found`);if(!r.schema)throw new x("Schema definition is required for update");let i=this.schemas[s],o=new Ue().fromDTO(i);return o.update(r),this.schemas[s]=o.toDTO(),await this.saveState(),this.schemas[s]}async deleteSchema(e){let r=this.schemas.findIndex(s=>s.name===e);if(r===-1)throw new F(`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 o of r.required)o in i||s.push({path:o,message:`Missing required field '${o}'`});for(let[o,n]of Object.entries(r.properties))n.required&&!(o in i)&&(r.required?.includes(o)||s.push({path:o,message:`Missing required field '${o}'`}));for(let[o,n]of Object.entries(i)){let a=r.properties[o];if(!a){r.additionalProperties===!1&&s.push({path:o,message:`Unexpected property '${o}'`});continue}let c=this.validatePropertyType(o,n,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 b(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 hr(t,e,r,s){try{let i=await b(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 u=!1;return await e.getUserByEmail(c)&&(u=!0),u&&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 fr(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 gr(t,e){try{let s=(await b(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 yr(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 v(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.some(a=>Qi(a,n)))){let n=new Error("Unauthorized");throw n.cause={statusCode:403},n}return!0}function Qi(t,e){if(t==="*"||t===e)return!0;if(!t.includes("*"))return!1;let r=t.split("*").map(i=>i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join(".*");return new RegExp(`^${r}$`).test(e)}async function vr(t,e){try{let r=t.state.user;v(r,m.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 U=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],u=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,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),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 u=this.validateProperty(this.propertyPath,c.items,l);s.push(...u)}),this.updatePropertyPath()},n=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)o(a[u],r[u]);else{let d=this.validateProperty(this.propertyPath,r[u],a[u]);s.push(...d)}})};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 Sr={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 to=new U(!0);async function wr(t,e){try{let r=t.state.user,s=await b(t),i=to.test(Sr,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);v(r,m.identity.user.create,{});let{id:o,email:n,name:a,roles:c,verified:l}=s,u=await e.addUser(n,a,c,l,o);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 br(t,e){try{let r=t.state.user;v(r,m.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 R(t){return t.params}async function xr(t,e){try{let r=t.state.user,s=R(t),{userId:i}=s;v(r,m.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 Cr={properties:{name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var so=new U(!0);async function Ir(t,e){try{let r=t.state.user,s=R(t),{userId:i}=s,o=await b(t),n=so.test(Cr,o);if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);v(r,m.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 Ar(t,e){try{let r=t.state.user,s=R(t),{userId:i}=s;return v(r,m.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 kr(t,e){try{let r=t.state.user,s=await b(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);v(r,m.identity.serviceAccount.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 Pr(t,e){try{let r=t.state.user;v(r,m.identity.serviceAccount.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 Er(t,e){try{let r=t.state.user,s=R(t),{serviceAccountId:i}=s;v(r,m.identity.serviceAccount.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 Rr={properties:{name:{type:"string",minLength:1,maxLength:100},description:{type:"string",minLength:1,maxLength:500},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var oo=new U(!0);async function Tr(t,e){try{let r=t.state.user,s=R(t),{serviceAccountId:i}=s,o=await b(t),n=oo.test(Rr,o);if(!n.success)return t.json({error:"Invalid input",details:n.errors},400);v(r,m.identity.serviceAccount.update,{serviceAccountId:i});let{name:a,description:c,roles:l}=o,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 jr(t,e){try{let r=t.state.user,s=R(t),{serviceAccountId:i}=s;return v(r,m.identity.serviceAccount.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 Or(t,e){try{let r=t.state.user,s=R(t),{serviceAccountId:i}=s;v(r,m.identity.serviceAccount.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 $r(t,e){try{let r=t.state.user;v(r,m.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 Mr(t,e){try{let r=t.state.user;v(r,m.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 Ur(t,e){try{let r=t.state.user;v(r,m.identity.role.create,{});let s=await b(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 Nr(t,e){try{let r=t.state.user;v(r,m.identity.role.update,{});let s=t.params.roleId;if(!s)return t.text("Missing role ID",400);let i=await b(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 Dr(t,e){try{let r=t.state.user;v(r,m.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 Lr(t,e){try{let r=t.state.user;v(r,m.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 Hr(t,e){try{let r=t.state.user,s=R(t),{serviceName:i}=s;v(r,m.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 qr={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 ao=new U(!0);async function _r(t,e){try{let r=t.state.user,s=await b(t),i=ao.test(qr,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);if(v(r,m.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 Fr={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 lo=new U(!0);async function Vr(t,e){try{let r=t.state.user,s=R(t),i=await b(t),o=i.name,n=lo.test(Fr,i);return n.success?(v(r,m.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.text("",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 Br(t,e){try{let r=t.state.user,s=R(t),{serviceName:i}=s;return v(r,m.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 Gr(t,e){try{let r=t.state.user,s=R(t),{serviceName:i}=s;if(v(r,m.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 zr(t,e){try{let r=t.state.user,s=R(t),{serviceName:i}=s;if(v(r,m.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 Wr(t,e){try{let r=t.state.user,s=R(t),{serviceName:i}=s;if(v(r,m.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 Ge(`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 Jr(t,e){try{let r=t.state.user,s=R(t),{serviceName:i}=s;if(v(r,m.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 Kr(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)&&!(c.targets&&c.targets.length>0&&(!i||!c.targets.includes(i)&&!c.targets.includes("*"))))return}let n=i?`:${i}`:"",a=new Error(`Function bindings do not allow: ${e}.${r}.${s}${n}`);throw a.cause={statusCode:403},a}import{readFileSync as uo,existsSync as po}from"node:fs";function Qe(){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||!po(t))return e;try{let r=uo(t,"utf-8");return JSON.parse(r)}catch(r){return console.error("[loadRuntimeConfig] Failed to load runtime config:",r),e}}async function S(t,e,r,s,i,o,n){if(!e)return null;let a=t.headers["x-molnos-service-token"];if(a){let u=Qe();if(u.internalServiceSecret&&a===u.internalServiceSecret)return null}let c=t.state.user;if(!c){let u=t.headers.authorization;if(!u){let f=new Error("Unauthorized: No authentication provided");throw f.cause={statusCode:401},f}let d=u.replace(/^Bearer\s+/i,"");if(c=await e.getUserFromToken(d),!c){let f=new Error("Unauthorized: Invalid token");throw f.cause={statusCode:401},f}}v(c,r,{});let l=t.headers["x-function-bindings"];if(l)try{let u=Array.isArray(l)?l[0]:l,d=JSON.parse(u);Kr(d,s,i,o,n)}catch(u){if(u.cause?.statusCode===403)throw u;let d=new Error("Invalid function bindings header");throw d.cause={statusCode:400},d}return c}async function Xr(t,e,r){try{let s=await b(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 S(t,r,m.applications.application.create,"applications","application","create",n);let u={id:o,name:n,description:a,redirectUris:Array.isArray(c)?c:[c],metadata:l,owners:[i.id]},d=await e.createApplication(u,i.id);return t.json(d,201)}catch(s){let{message:i,status:o}=h(s,"Error creating application");return t.json({error:i},o)}}async function Yr(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 S(t,r,m.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 Zr(t,e,r){try{let s=t.state.requestingIdentity;if(!s)return t.json({error:"Authentication required"},401);await S(t,r,m.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 b(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 S(t,r,m.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 es(t,e,r){try{let s=t.params.id,i=t.state.requestingIdentity;return i?s?(await S(t,r,m.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 ts(t,e,r){try{let s=await b(t),{name:i,description:o,schema:n}=s;if(!i||!n)return t.json({error:"Missing required fields: name and schema are required"},400);await S(t,r,m.schemas.schema.create,"schemas","schema","create",i);let a=await e.createSchema({name:i,description:o,schema:n});return t.json(a,201)}catch(s){let{message:i,status:o}=h(s,"Error creating schema");return t.json({error:i},o)}}async function Et(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 S(t,r,m.schemas.schema.read,"schemas","schema","read",s);let o=i?parseInt(i,10):void 0,n=await e.getSchema(s,o);return t.json(n,200)}catch(s){let{message:i,status:o}=h(s,"Error retrieving schema");return t.json({error:i},o)}}async function rs(t,e,r){try{await S(t,r,m.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:o}=h(s,"Error listing schemas");return t.json({error:i},o)}}async function ss(t,e,r){try{let s=t.params.name,i=await b(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 S(t,r,m.schemas.schema.update,"schemas","schema","update",s);let o=await e.updateSchema(s,{description:i.description,schema:i.schema});return t.json(o,200)}catch(s){let{message:i,status:o}=h(s,"Error updating schema");return t.json({error:i},o)}}async function is(t,e,r){try{let s=t.params.name;return s?(await S(t,r,m.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:o}=h(s,"Error deleting schema");return t.json({error:i},o)}}async function os(t,e,r){try{await S(t,r,m.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 ns(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);await S(t,r,m.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 mo=new U(!0),ho={properties:{name:{type:"string",minLength:1,maxLength:64},intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},required:["name"],additionalProperties:!1};async function as(t,e,r){try{let s=await b(t),i=mo.test(ho,s);if(!i.success)return t.json({error:"Invalid input",details:i.errors},400);await S(t,r,m.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 fo=new U(!0),go={properties:{intent:{type:"string",maxLength:1e3},attributes:{type:"object"}},additionalProperties:!1};async function cs(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"contextName parameter is required"},400);let i=await b(t),o=fo.test(go,i||{});if(!o.success)return t.json({error:"Invalid input",details:o.errors},400);await S(t,r,m.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 ls(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 S(t,r,m.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 us(t,e,r,s){try{let i=t.params.contextName;if(!i)return t.json({error:"contextName parameter is required"},400);await S(t,r,m.contexts.context.deleteResources,"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 d=await a.functions.list();for(let f of c.functions)try{let w=d.find(k=>k.id===f);w&&(await a.functions.delete(f),await e.unregisterResource(i,"function",f),l.deleted.push({type:"function",name:w.name}))}catch(w){l.errors.push({type:"function",name:f,error:w.message||"Unknown error"}),l.success=!1}}if(a.databases)for(let d of c.databases)try{await a.databases.deleteTable(d),await e.unregisterResource(i,"database",d),l.deleted.push({type:"database",name:d})}catch(f){l.errors.push({type:"database",name:d,error:f.message||"Unknown error"}),l.success=!1}if(a.storage)for(let d of c.storage)try{await a.storage.deleteBucket(d),await e.unregisterResource(i,"storage",d),l.deleted.push({type:"storage",name:d})}catch(f){l.errors.push({type:"storage",name:d,error:f.message||"Unknown error"}),l.success=!1}if(a.sites)for(let d of c.sites)try{await a.sites.deleteProject(d),await e.unregisterResource(i,"site",d),l.deleted.push({type:"site",name:d})}catch(f){l.errors.push({type:"site",name:d,error:f.message||"Unknown error"}),l.success=!1}if(a.applications){let d=await a.applications.list();for(let f of c.applications)try{let w=d.find(k=>k.id===f);w&&(await a.applications.delete(f),await e.unregisterResource(i,"application",f),l.deleted.push({type:"application",name:w.name}))}catch(w){l.errors.push({type:"application",name:f,error:w.message||"Unknown error"}),l.success=!1}}if(a.identity)for(let d of c.users)try{let f=await a.identity.getUser(d);f&&(await a.identity.deleteUser(f.id),await e.unregisterResource(i,"user",d),l.deleted.push({type:"user",name:d}))}catch(f){l.errors.push({type:"user",name:d,error:f.message||"Unknown error"}),l.success=!1}if(a.identity)for(let d of c.serviceAccounts)try{let f=await a.identity.getServiceAccount(d);f&&(await a.identity.deleteServiceAccount(f.id),await e.unregisterResource(i,"serviceAccount",d),l.deleted.push({type:"serviceAccount",name:d}))}catch(f){l.errors.push({type:"serviceAccount",name:d,error:f.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:o,status:n}=h(i,"Error deleting context resources");return t.json({error:o},n)}}async function ds(t,e,r){try{await S(t,r,m.iac.config.get,"iac","config","get");let s=await b(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 ps(t,e,r){try{await S(t,r,m.iac.config.create,"iac","config","create");let s=await b(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}),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:o}=h(s,"Error applying IaC");return t.json({error:i},o)}}var Q="default",et=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 W(`Context '${r}' already exists`);let s=new Date().toISOString(),i={name:r,intent:e.intent,attributes:e.attributes,createdAt:s,updatedAt:s};return this.contexts.push(i),await this.saveState(),i}getContext(e){let r=this.contexts.find(s=>s.name===e);if(!r)throw new F(`Context '${e}' not found`);return r}getContextWithResources(e){let r=this.getContext(e),s=this.getContextResources(e);return{...r,resources:s}}async updateContext(e,r){let s=this.contexts.findIndex(n=>n.name===e);if(s===-1)throw new F(`Context '${e}' not found`);let i=this.contexts[s],o={...i,intent:r.intent??i.intent,attributes:r.attributes??i.attributes,updatedAt:new Date().toISOString()};return this.contexts[s]=o,await this.saveState(),o}async deleteContext(e){let r=this.contexts.findIndex(s=>s.name===e);if(r===-1)throw new F(`Context '${e}' not found`);this.contexts.splice(r,1),this.resourceMappings=this.resourceMappings.filter(s=>s.context!==e),await this.saveState()}contextExists(e){return this.contexts.some(r=>r.name===e)}listContexts(){return[...this.contexts].sort((e,r)=>e.name.localeCompare(r.name))}async ensureContext(e){let r=e||Q;return this.contextExists(r)||await this.createContext({name:r,intent:r===Q?"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:[],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||Q}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 ms(t,e,r){try{await S(t,r,m.iac.config.get,"iac","config","get");let s=await b(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||Q,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 yo=new U(!0),vo={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 hs(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"Context name is required"},400);await S(t,r,m.ai.generation.generate,"ai","generation","generate",s);let i=await b(t),o=yo.test(vo,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 fs(t,e,r){try{let s=t.params.generationId;if(!s)return t.json({error:"Generation ID is required"},400);await S(t,r,m.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 gs(t,e,r){try{let s=t.params.contextName;if(!s)return t.json({error:"Context name is required"},400);await S(t,r,m.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 ys(t,e,r){try{let s=t.params.generationId;if(!s)return t.json({error:"Generation ID is required"},400);await S(t,r,m.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 vs(t,e,r){try{let s=t.params.generationId;return s?(await S(t,r,m.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 Ss(t,e,r){try{let s=t.params.generationId;return s?(await S(t,r,m.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 tt}from"node:fs";import{join as Rt,resolve as wo}from"node:path";var ws={$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 bo=new U(!0),rt=class{contextService;clients;constructor(e,r){this.contextService=e,this.clients=r}async loadConfiguration(e){let r=wo(e);try{let s=await tt.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=bo.test(ws,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||Q,created:[],updated:[],unchanged:[],deleted:[],errors:s.errors.map(n=>({type:"validation",name:n.path,error:n.message}))};let i=e.context?.name||Q,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 u=r.basePath?Rt(r.basePath,a.source):a.source;try{c=await tt.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(n);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}),o.updated.push({type:"function",name:n});else{let u=await this.clients.functions.deploy(n,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),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 u=r.basePath?Rt(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(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(e.resources?.schemas&&this.clients.schemas)for(let[n,a]of Object.entries(e.resources.schemas))try{await this.clients.schemas.get(n)?(await this.clients.schemas.update(n,a.schema,a.description),o.updated.push({type:"schema",name:n})):(await this.clients.schemas.create(n,a.schema,a.description),await this.contextService.registerResource(i,"schema",n),o.created.push({type:"schema",name:n}))}catch(c){o.errors.push({type:"schema",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 u=c.find(d=>d.id===l);if(u&&!a.includes(u.name))try{await this.clients.functions.delete(l),await this.contextService.unregisterResource(i,"function",l),o.deleted.push({type:"function",name:u.name})}catch(d){o.errors.push({type:"function",name:u.name,error:`Failed to delete: ${d.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 u=c.find(d=>d.id===l);if(u&&!a.includes(u.name))try{await this.clients.applications.delete(l),await this.contextService.unregisterResource(i,"application",l),o.deleted.push({type:"application",name:u.name})}catch(d){o.errors.push({type:"application",name:u.name,error:`Failed to delete: ${d.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}}if(this.clients.schemas){let a=Object.keys(e.resources?.schemas||{});for(let c of n.schemas)if(!a.includes(c))try{await this.clients.schemas.delete(c),await this.contextService.unregisterResource(i,"schema",c),o.deleted.push({type:"schema",name:c})}catch(l){o.errors.push({type:"schema",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 tt.readdir(e,{withFileTypes:!0});for(let o of i){let n=Rt(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 tt.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||Q,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 d=e.resources?.storage?.[l];await this.clients.storage.isBucketPublic(l)!==(d?.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})}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)||o.push({type:"schema",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 d=new URLSearchParams(i);o+=`?${d.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"),u;if(l?.includes("application/json")?u=await c.json():u=await c.text(),!c.ok){let d=typeof u=="object"&&u.error?u.error:typeof u=="string"?u:JSON.stringify(u);throw new Error(d)}return u}},Tt=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)}},jt=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}}},Ot=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,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||[]}},$t=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||[]}},Mt=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||[]}},Ut=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||[]}},Nt=class extends ee{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 Dt(t){let{serviceUrls:e,authToken:r}=t,s={};return e.databases&&(s.databases=new Tt(e.databases,r)),e.storage&&(s.storage=new jt(e.storage,r)),e.functions&&(s.functions=new Ot(e.functions,r)),e.sites&&(s.sites=new $t(e.sites,r)),e.identity&&(s.identity=new Mt(e.identity,r)),e.applications&&(s.applications=new Ut(e.applications,r)),e.schemas&&(s.schemas=new Nt(e.schemas,r)),s}import xs from"crypto";var bs="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var xo=128,me,Se,Co=t=>{!me||me.length<t?(me=Buffer.allocUnsafe(t*xo),xs.randomFillSync(me),Se=0):Se+t>me.length&&(xs.randomFillSync(me),Se=0),Se+=t};var Cs=(t=21)=>{Co(t|=0);let e="";for(let r=Se-t;r<Se;r++)e+=bs[me[r]&63];return e};var st=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=Cs(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 it=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 d=await l.text();throw new Error(`Anthropic API error (${l.status}): ${d}`)}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(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 ot=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 d=await l.text();throw new Error(`OpenAI API error (${l.status}): ${d}`)}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 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 nt=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 d=await l.text();throw new Error(`Ollama API error (${l.status}): ${d}`)}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 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}
|
|
117
117
|
Input: ${JSON.stringify(l.tool_input,null,2)}`).join(`
|
|
118
118
|
|
|
119
|
-
`);s.push({role:"assistant",content:c});continue}let
|
|
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:
|
|
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,
|
|
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(
|
|
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 at=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 d=await l.text();throw new Error(`evroc Think API error (${l.status}): ${d}`)}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 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 Ne=class t{static providers=new Map;static{t.providers.set("anthropic",it),t.providers.set("openai",ot),t.providers.set("ollama",nt),t.providers.set("evroc",at)}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 Ao,dirname as ko}from"node:path";import{fileURLToPath as Po}from"node:url";function Eo(){try{let t=ko(Po(import.meta.url)),e=Ao(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 Ro=Eo(),Is=`# MolnOS Code Generation Protocol
|
|
125
125
|
|
|
126
126
|
You generate production-ready code for MolnOS. Follow this protocol exactly.
|
|
127
127
|
|
|
@@ -148,7 +148,7 @@ IAC:
|
|
|
148
148
|
## MolnOS IAC JSON Schema (authoritative)
|
|
149
149
|
|
|
150
150
|
The \`iacConfig\` MUST conform to this JSON Schema:
|
|
151
|
-
${
|
|
151
|
+
${Ro}
|
|
152
152
|
|
|
153
153
|
### Minimal example
|
|
154
154
|
|
|
@@ -164,6 +164,7 @@ ${bn}
|
|
|
164
164
|
"myFunction": {
|
|
165
165
|
"code": "export async function handler(req, context) { return { message: 'Hello' }; }",
|
|
166
166
|
"methods": ["GET"],
|
|
167
|
+
"triggers": [{ "type": "http" }],
|
|
167
168
|
"allowUnauthenticated": false
|
|
168
169
|
},
|
|
169
170
|
"myEventHandler": {
|
|
@@ -195,7 +196,7 @@ ${bn}
|
|
|
195
196
|
|
|
196
197
|
### Signature (REQUIRED)
|
|
197
198
|
|
|
198
|
-
**HTTP-triggered functions (
|
|
199
|
+
**HTTP-triggered functions (when triggers include \`{ "type": "http" }\`):**
|
|
199
200
|
\`\`\`js
|
|
200
201
|
export async function handler(req, context) { <function code here> }
|
|
201
202
|
\`\`\`
|
|
@@ -273,7 +274,7 @@ To make a function execute when an event is emitted, add \`triggers\`:
|
|
|
273
274
|
"triggers": [{ "type": "event", "eventName": "order.created" }]
|
|
274
275
|
}
|
|
275
276
|
\`\`\`
|
|
276
|
-
A function can subscribe to multiple events.
|
|
277
|
+
A function can subscribe to multiple events. If no triggers are specified, the function defaults to HTTP-accessible for backward compatibility, but it is recommended to always set triggers explicitly.
|
|
277
278
|
|
|
278
279
|
**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
280
|
\`\`\`json
|
|
@@ -372,7 +373,7 @@ When the user's intent involves a UI or frontend, generate a static site using p
|
|
|
372
373
|
- Invented binding names (\`db\`, \`kv\`, etc.)
|
|
373
374
|
|
|
374
375
|
/no_think
|
|
375
|
-
`;async function
|
|
376
|
+
`;async function As(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 u=s||a?.context?.intent||c?.intent||"",d=ks(c?.attributes||{},a?.context?.attributes||{},i||{});return{contextName:r,intent:u,intentAttributes:d,resourceTypes:o||["functions","sites"],existingFiles:n||[],existingResources:l||{functions:[],databases:[],storage:[],sites:[],users:[],serviceAccounts:[],applications:[]},iacConfig:a}}function ks(...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]=ks(e[s]||{},i):e[s]=i)}return e}function Ps(t){let e=`Context: ${t.contextName}
|
|
376
377
|
|
|
377
378
|
`;if(t.intent&&(e+=`Intent: ${t.intent}
|
|
378
379
|
|
|
@@ -380,27 +381,27 @@ When the user's intent involves a UI or frontend, generate a static site using p
|
|
|
380
381
|
${JSON.stringify(t.intentAttributes,null,2)}
|
|
381
382
|
|
|
382
383
|
`),t.existingFiles.length>0){e+=`Existing Files:
|
|
383
|
-
`;for(let
|
|
384
|
-
--- ${
|
|
385
|
-
${
|
|
384
|
+
`;for(let n of t.existingFiles)e+=`
|
|
385
|
+
--- ${n.path} ---
|
|
386
|
+
${n.content}
|
|
386
387
|
`;e+=`
|
|
387
|
-
`}Object.values(t.existingResources).some(
|
|
388
|
+
`}Object.values(t.existingResources).some(n=>n.length>0)&&(e+=`Existing Resources:
|
|
388
389
|
`,t.existingResources.functions.length>0&&(e+=`- Functions: ${t.existingResources.functions.join(", ")}
|
|
389
390
|
`),t.existingResources.databases.length>0&&(e+=`- Databases: ${t.existingResources.databases.join(", ")}
|
|
390
391
|
`),t.existingResources.storage.length>0&&(e+=`- Storage: ${t.existingResources.storage.join(", ")}
|
|
391
392
|
`),t.existingResources.sites.length>0&&(e+=`- Sites: ${t.existingResources.sites.join(", ")}
|
|
392
393
|
`),e+=`
|
|
393
|
-
`);let r=t.resourceTypes,s=r.map(
|
|
394
|
+
`);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}.
|
|
394
395
|
`,i?e+=`Do NOT generate sites or frontend code.
|
|
395
|
-
`:
|
|
396
|
+
`:o&&(e+=`Do NOT generate functions or backend code. Only generate a static site.
|
|
396
397
|
`),e+=`Return as JSON:
|
|
397
398
|
{
|
|
398
399
|
"functions": [{ "name": "...", "code": "..." }],
|
|
399
400
|
"iacConfig": { ... },
|
|
400
401
|
"explanation": "One sentence summary."
|
|
401
|
-
}`,e}var
|
|
402
|
+
}`,e}var ct=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 st(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 Y("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 Y(`API key required for provider: ${s}. Either configure in molnos.config.json or provide userApiKey.`);let n=Ne.createProvider(s,o);if(!await n.validateConfig())throw new Y(`Failed to validate ${s} provider configuration`);return this.cachedProvider=n,this.cachedProviderKey=i,n}async generate(e){if(!this.isAvailable())throw new Y("AI generation is not enabled. Configure AI in molnos.config.json.");let r=await this.initializeProvider(e.providerOverride,e.userApiKey),s=await As(e,this.contextService),o=[{role:"user",content:Ps(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:
|
|
402
403
|
|
|
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`
|
|
404
|
+
${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:Is})).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 Ne.getSupportedProviders()}};async function Es(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;if(n!==void 0){if(typeof n!="string"||n.trim()==="")return t.json({error:"redirect_uri must be a non-empty string"},400);let d;try{d=new URL(n)}catch{return t.json({error:"redirect_uri must be a valid absolute URL"},400)}if(!["http:","https:"].includes(d.protocol))return t.json({error:"redirect_uri must use http:// or https:// protocol"},400);if(d.username||d.password)return t.json({error:"redirect_uri cannot include credentials"},400);c=d.toString()}if(c&&!a)return t.json({error:"application_id is required when redirect_uri is provided"},400);let l=r.generateState(t,s,c,a),u=e.getAuthorizationUrl(l);return t.redirect(u,302)}catch(i){let{message:o,status:n}=h(i,"Error initiating OAuth flow");return t.json({error:o},n)}}async function Rs(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,u=a?.split(",")[0]?.trim()||l||"unknown";if(!r.checkRateLimit(`oauth:${u}`)){let k=r.getRateLimitInfo(`oauth:${u}`);return t.json({error:"Too many authentication attempts. Please try again later.",retryAfter:Math.ceil((k.reset-Date.now())/1e3)},429)}let d=r.validateCallback(t,o);if(!d.valid)return t.json({error:d.error||"Invalid OAuth callback"},400);let f=await e.handleCallback(d.code,u),w=await s.getUserByEmail(f.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()}),d.redirectUrl){if(!d.applicationId)return t.json({error:"Missing application_id for redirect-based OAuth flow"},400);if(!await i.validateRedirectUri(d.applicationId,d.redirectUrl))return t.json({error:"Invalid redirect URI for application"},400);let $=new URL(d.redirectUrl);return $.searchParams.set("access_token",f.accessToken),$.searchParams.set("refresh_token",f.refreshToken),$.searchParams.set("expires_in",f.expiresIn.toString()),t.redirect($.toString(),302)}return t.json({success:!0,accessToken:f.accessToken,refreshToken:f.refreshToken,expiresIn:f.expiresIn,tokenType:f.tokenType,user:{id:w.id,email:f.user.email,name:f.user.name,username:f.user.username}})}catch(n){let{message:a,status:c}=h(n,"OAuth authentication failed");return t.json({error:a},c)}}async function Ts(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 lt=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 To from"node:crypto";var ut=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=To.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 js={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 Os(t){let e=[];if(t.presets)for(let[r,s]of Object.entries(t.presets)){let i=js[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 jo=null;function $s(t){jo=t}async function Ms(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 Lt(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 C(t,e){v(t,e,{})}function Us(t,e,r){let s=e.toUpperCase();if(r.startsWith("/databases/")){s==="GET"&&r==="/databases/table"?C(t,m.databases.table.get):s==="POST"&&r==="/databases/get"?C(t,m.databases.table.get):s==="POST"&&r==="/databases/write"?C(t,m.databases.table.update):s==="DELETE"&&r==="/databases/delete"?C(t,m.databases.table.delete):s==="GET"&&r==="/databases/tables"?C(t,m.databases.table.get):s==="POST"&&/^\/databases\/tables\/[^/]+$/.test(r)?C(t,m.databases.table.create):s==="DELETE"&&/^\/databases\/tables\/[^/]+$/.test(r)?C(t,m.databases.table.delete):s==="GET"&&/^\/databases\/tables\/[^/]+(?:\/items)?$/.test(r)&&C(t,m.databases.table.get);return}if(r.startsWith("/functions/")){if(/^\/functions\/run\/[^/]+(?:\/.*)?$/.test(r))return;s==="POST"&&r==="/functions/deploy"?C(t,m.functions.function.create):s==="GET"&&(r==="/functions/list"||r==="/functions/stats")?C(t,m.functions.function.get):s==="GET"&&/^\/functions\/[^/]+\/config$/.test(r)?C(t,m.functions.function.get):s==="GET"&&/^\/functions\/[^/]+$/.test(r)?C(t,m.functions.function.get):s==="PUT"&&/^\/functions\/[^/]+$/.test(r)?C(t,m.functions.function.update):s==="DELETE"&&/^\/functions\/[^/]+$/.test(r)&&C(t,m.functions.function.delete);return}if(r.startsWith("/storage/")){if(s==="GET"&&r==="/storage/buckets")C(t,m.storage.bucket.list);else if(s==="POST"&&/^\/storage\/buckets\/[^/]+$/.test(r))C(t,m.storage.bucket.create);else if(s==="GET"&&/^\/storage\/buckets\/[^/]+$/.test(r))C(t,m.storage.bucket.read);else if(s==="PATCH"&&/^\/storage\/buckets\/[^/]+$/.test(r))C(t,m.storage.bucket.update);else if(s==="DELETE"&&/^\/storage\/buckets\/[^/]+$/.test(r))C(t,m.storage.bucket.delete);else if(s==="GET"&&/^\/storage\/buckets\/[^/]+\/objects$/.test(r))C(t,m.storage.object.list);else if(s==="PUT"&&/^\/storage\/buckets\/[^/]+\/objects$/.test(r))C(t,m.storage.object.write);else if(s==="POST"&&/^\/storage\/buckets\/[^/]+\/objects$/.test(r))C(t,m.storage.object.read);else if(s==="DELETE"&&/^\/storage\/buckets\/[^/]+\/objects$/.test(r))C(t,m.storage.object.delete);else if(s==="POST"&&/^\/storage\/buckets\/[^/]+\/objects\/.+\/sign$/.test(r))C(t,m.storage.object.read);else if(s==="GET"&&/^\/storage\/buckets\/[^/]+\/objects\/.+$/.test(r))return;return}if(r.startsWith("/sites/")){if(s==="GET"&&r==="/sites/projects")C(t,m.sites.project.list);else if(s==="POST"&&r==="/sites/projects")C(t,m.sites.project.create);else if(s==="DELETE"&&/^\/sites\/projects\/[^/]+$/.test(r))C(t,m.sites.project.delete);else if(s==="GET"&&/^\/sites\/projects\/[^/]+\/download$/.test(r))C(t,m.sites.project.download);else if(s==="GET"&&/^\/sites\/projects\/[^/]+(?:\/.*)?$/.test(r))return;return}if(r.startsWith("/observability/")){s==="POST"&&r==="/observability/events"?C(t,m.observability.event.create):s==="GET"&&r==="/observability/events"?C(t,m.observability.event.read):s==="GET"&&r==="/observability/stats"?C(t,m.observability.stats.read):s==="DELETE"&&r==="/observability/events/cleanup"?C(t,m.observability.event.delete):s==="POST"&&r==="/observability/flush"?C(t,m.observability.buffer.write):s==="GET"&&r==="/observability/metrics/system"&&C(t,m.observability.metrics.read);return}}var dt=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 Ns(t){return t?new dt(t):null}function Ds(t){return t&&typeof t=="number"&&t>0?t*1024*1024:0}async function Ls(t){let{auth:e,db:r,config:s,molnos:i,oauth:o,ai:n}=t,a=new Xe(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=Ns(l),d,f;if(o){d=new ut(o),f=new Map;let p=Os(o);for(let P of p){let I=new lt(P,e);f.set(P.id,I)}}let w=pt(i.dataPath,"applications"),k=new Ye({dbPath:w});await k.start();let $=pt(i.dataPath,"schemas"),J=new Ze({dbPath:$});await J.start(),$s(J);let we=pt(i.dataPath,"management"),N=new ve({dbPath:we}),V=pt(i.dataPath,".runtime-config.json");N.setEnvironmentVariables({MOLNOS_RUNTIME_CONFIG:V});let q=i.cluster;N.setClusterConfig(q),await N.start();let te;q?.mode==="core"&&q.workers&&(te=new Oe,await te.registerWorkers(q.workers));let _=new et(r);await _.start();let M=Qe(),oe=p=>{let P=Dt({serviceUrls:{databases:M.services.databases.url,storage:M.services.storage.url,functions:M.services.functions.url,sites:M.services.sites.url,identity:M.identity.apiUrl,applications:M.identity.apiUrl,schemas:`${M.identity.apiUrl}/schemas`},authToken:p});return new rt(_,P)},Ws=n||{enabled:!1},re=new ct(Ws,_,oe);await re.start();let mt=!1,g=new Ee({port:s.port||3e3,host:s.host||"127.0.0.1",allowedDomains:s.allowedDomains,maxBodySize:Ds(1e3),rateLimit:i.rateLimit?.global||{enabled:!1,requestsPerMinute:0}});g.use(async(p,P)=>mt?p.text("Service Unavailable - Server is shutting down",503):P()),g.use(Ms),q?.mode==="worker"&&q.secret&&g.use(Re(q.secret)),g.get("/health",async p=>p.text("OK"));let j=async p=>p.text("Not Found",404);if(g.post("/auth/login",p=>hr(p,a,e,k)),g.get("/auth/verify",p=>fr(p,e,k)),g.post("/auth/refresh",p=>gr(p,e)),f&&d){g.get("/auth/oauth/providers",p=>Ts(p,f));for(let[p,P]of f.entries())g.get(`/auth/oauth/${p}`,Lt,I=>Es(I,P,d,p)),g.get(`/auth/oauth/${p}/callback`,Lt,I=>Rs(I,P,d,a,k,p))}g.post("/management/service",y,p=>_r(p,N)),g.get("/management/services",y,p=>Lr(p,N)),g.get("/management/service/:serviceName",y,p=>Hr(p,N)),g.put("/management/service/:serviceName",y,p=>Vr(p,N)),g.delete("/management/service/:serviceName",y,p=>Br(p,N)),g.get("/management/service/:serviceName/start",y,p=>Gr(p,N)),g.get("/management/service/:serviceName/stop",y,p=>zr(p,N)),g.get("/management/service/:serviceName/logs",y,p=>Wr(p,N)),g.get("/management/service/:serviceName/restart",y,p=>Jr(p,N)),g.get("/identity/whoami",y,p=>yr(p)),g.get("/identity/identities",y,p=>vr(p,a)),g.post("/identity/users",y,p=>wr(p,a)),g.get("/identity/users",y,p=>br(p,a)),g.get("/identity/users/:userId",y,p=>xr(p,a)),g.patch("/identity/users/:userId",y,p=>Ir(p,a)),g.delete("/identity/users/:userId",y,p=>Ar(p,a)),g.post("/identity/service-accounts",y,p=>kr(p,a)),g.get("/identity/service-accounts",y,p=>Pr(p,a)),g.get("/identity/service-accounts/:serviceAccountId",y,p=>Er(p,a)),g.patch("/identity/service-accounts/:serviceAccountId",y,p=>Tr(p,a)),g.delete("/identity/service-accounts/:serviceAccountId",y,p=>jr(p,a)),g.post("/identity/service-accounts/:serviceAccountId/rotate-key",y,p=>Or(p,a)),g.post("/identity/roles",y,p=>Ur(p,a)),g.get("/identity/roles",y,p=>$r(p,a)),g.get("/identity/roles/:roleId",y,p=>Mr(p,a)),g.patch("/identity/roles/:roleId",y,p=>Nr(p,a)),g.delete("/identity/roles/:roleId",y,p=>Dr(p,a)),g.post("/applications",y,p=>Xr(p,k,u)),g.get("/applications",y,p=>Zr(p,k,u)),g.get("/applications/:id",y,p=>Yr(p,k,u)),g.patch("/applications/:id",y,p=>Qr(p,k,u)),g.delete("/applications/:id",y,p=>es(p,k,u)),g.post("/schemas",y,p=>ts(p,J,u)),g.get("/schemas",y,p=>rs(p,J,u)),g.get("/schemas/:name",y,p=>Et(p,J,u)),g.get("/schemas/:name/:version",y,p=>Et(p,J,u)),g.put("/schemas/:name",y,p=>ss(p,J,u)),g.delete("/schemas/:name",y,p=>is(p,J,u)),g.get("/contexts",y,p=>os(p,_,u)),g.post("/contexts",y,p=>as(p,_,u)),g.get("/contexts/:contextName",y,p=>ns(p,_,u)),g.patch("/contexts/:contextName",y,p=>cs(p,_,u)),g.delete("/contexts/:contextName",y,p=>ls(p,_,u)),g.delete("/contexts/:contextName/resources",y,p=>us(p,_,u,P=>Dt({serviceUrls:{databases:M.services.databases.url,storage:M.services.storage.url,functions:M.services.functions.url,sites:M.services.sites.url,identity:M.identity.apiUrl,applications:M.identity.apiUrl,schemas:`${M.identity.apiUrl}/schemas`},authToken:P}))),g.post("/iac/validate",y,p=>ds(p,oe,u)),g.post("/iac/apply",y,p=>ps(p,oe,u)),g.post("/iac/diff",y,p=>ms(p,oe,u)),g.post("/contexts/:contextName/generate",y,p=>hs(p,re,u)),g.get("/contexts/:contextName/generations",y,p=>gs(p,re,u)),g.get("/generations/:generationId",y,p=>fs(p,re,u)),g.post("/generations/:generationId/apply",y,p=>ys(p,re,u)),g.post("/generations/:generationId/discard",y,p=>vs(p,re,u)),g.delete("/generations/:generationId",y,p=>Ss(p,re,u)),g.get("/databases/*",y,T,j),g.post("/databases/*",y,T,j),g.put("/databases/*",y,T,j),g.patch("/databases/*",y,T,j),g.delete("/databases/*",y,T,j);async function be(p,P){if(p.path.match(/^\/functions\/run\//)){let L=p.headers.authorization;if(L)try{let O=await a.getUserFromToken(L);O&&(p.state.user=O,p.state.requestingIdentity=O)}catch{}return P()}return y(p,P)}g.get("/functions/*",be,T,j),g.post("/functions/*",be,T,j),g.put("/functions/*",be,T,j),g.patch("/functions/*",be,T,j),g.delete("/functions/*",be,T,j),g.get("/sites/projects/:projectId/*",T,async p=>p.text("Not Found",404)),g.get("/sites/*",y,T,j),g.post("/sites/*",y,T,j),g.put("/sites/*",y,T,j),g.patch("/sites/*",y,T,j),g.delete("/sites/*",y,T,j);async function xe(p,P){let I=p.req.method;if(p.path.match(/^\/storage\/buckets\/[^/]+\/objects\/.+/)&&(I==="GET"||I==="HEAD")){let O=p.headers.authorization;if(O)try{let se=await a.getUserFromToken(O);se&&(p.state.user=se,p.state.requestingIdentity=se)}catch{}return P()}return y(p,P)}g.get("/storage/*",xe,T,j),g.post("/storage/*",xe,T,j),g.put("/storage/*",xe,T,j),g.patch("/storage/*",xe,T,j),g.delete("/storage/*",xe,T,j),g.get("/observability/*",y,T,j),g.post("/observability/*",y,T,j),g.put("/observability/*",y,T,j),g.patch("/observability/*",y,T,j),g.delete("/observability/*",y,T,j);function Js(p,P,I,D){if(P!=="POST")return;let L=null,O=null;p==="/functions/deploy"&&D.function?.id?(L="function",O=D.function.id):p.match(/^\/databases\/tables\/[^/]+$/)&&D.name?(L="database",O=D.name):p.match(/^\/storage\/buckets\/[^/]+$/)&&D.bucket?(L="storage",O=D.bucket):p==="/sites/projects"&&D.projectId&&(L="site",O=D.projectId),L&&O&&_.registerResource(I,L,O).catch(se=>{console.error(`[Server] Failed to register ${L} '${O}' with context '${I}':`,se.message)})}async function T(p,P){try{let I=p.path,D=Object.keys(p.query).length>0?`?${new URLSearchParams(p.query).toString()}`:"",L=p.req.method||"",O,se=0,Xs=await N.getServices();for(let H of Xs)H.active&&I.startsWith(H.prefix)&&H.prefix.length>se&&(O=H,se=H.prefix.length);if(!O)return P();let _t=p.state.user;if(!(I.match(/^\/sites\/projects\/[^/]+.*/)&&L==="GET")&&_t&&Us(_t,L,I),O.healthCheck&&O.healthCheck.healthy===!1)return p.json({error:"Service unavailable (unhealthy)"},503);let Ft=(I.substring(O.prefix.length)||"/")+D,B=null,ht=null,ft=null;if(["POST","PUT","PATCH","DELETE"].includes(L)){let H=p.headers["content-type"]||"";if(H.includes("application/json"))try{let ne=await b(p);ft=ne,B=JSON.stringify(ne)}catch{B=null}else if(H.includes("multipart/form-data"))try{B=JSON.stringify(p.body),ht="application/json"}catch{B=null}else try{B=Buffer.isBuffer(p.body)?p.body:Buffer.from(p.body)}catch{B=null}}let De=O.name,Vt=q?.mode==="core"?q.workers?.[De]:void 0;if(Vt&&te){if(!te.isHealthy(De))return p.json({error:`Worker for ${De} is unavailable`},503);try{let H=await At(Vt,Ft,L,B,p.headers,q?.secret);return kt(p,H)}catch(H){return console.error(`[Server] Worker proxy error for ${De}:`,H.message),p.json({error:H.message},H.statusCode||503)}}return new Promise(H=>{let ne={...p.headers,host:`127.0.0.1:${O.port}`};ht&&(ne["content-type"]=ht),B&&(typeof B=="string"?ne["content-length"]=Buffer.byteLength(B).toString():ne["content-length"]=B.length.toString());let Ys={method:L,hostname:"127.0.0.1",port:O.port,path:Ft,headers:ne},Ce=Oo.request(Ys,z=>{let Bt=[];z.on("data",he=>{Bt.push(he)}),z.on("end",()=>{let he=Buffer.concat(Bt),gt={};Object.entries(z.headers).forEach(([Ae,ie])=>{ie!==void 0&&(gt[Ae]=Array.isArray(ie)?ie.join(", "):ie)});let Ie=z.headers["content-type"]||"",K;if(Ie.includes("application/json"))try{let Ae=JSON.parse(he.toString("utf-8")),ie=z.statusCode||200;Ae.success&&ie>=200&&ie<300&&ft?.context&&Js(I,L,ft.context,Ae),K=p.json(Ae,ie)}catch{K=p.text(he.toString("utf-8"),z.statusCode||200)}else Ie.startsWith("text/")||Ie.includes("javascript")||Ie.includes("xml")?K=p.text(he.toString("utf-8"),z.statusCode||200):(K=p.binary(he,Ie||"application/octet-stream"),z.statusCode&&z.statusCode!==200&&(K.statusCode=z.statusCode));K.headers?K.headers={...K.headers,...gt}:K.headers=gt,H(K)})});Ce.on("error",z=>{H(p.json({error:"Proxy Error",message:z.message},502))}),Ce.on("timeout",()=>{Ce.destroy(),H(p.json({error:"Gateway Timeout"},504))}),B&&Ce.write(B),Ce.end()})}catch(I){return Ht(p,I)}}async function y(p,P){try{let I=p.headers.authorization;if(!I)return p.text("Unauthorized",401);let D=await a.getUserFromToken(I);return D?(p.state.user=D,p.state.requestingIdentity=D,P()):p.text("Unauthorized",401)}catch(I){return Ht(p,I)}}function Ht(p,P){let I=P.message||P,D=P?.cause?.statusCode||400;return p.json({error:I},D)}let qt=g.start();async function Ks(){mt||(mt=!0,await new Promise((p,P)=>{qt.close(I=>{I?P(I):p()})}),console.log("[Server] Stopping managed services..."),await N.shutdown(),d&&d.shutdown(),console.log("[Server] Stopping AI service..."),re.stop(),await r.close())}return{server:qt,shutdown:Ks,processManager:N,identityService:a}}import $o from"node:http";import{join as Mo}from"node:path";async function Hs(t){let{config:e,dataPath:r,cluster:s}=t,i=new Ee({...e});if(s.secret){let l=Re(s.secret);i.use(l)}let o=new ve({dbPath:Mo(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 u=l.path,d=Object.keys(l.query).length>0?`?${new URLSearchParams(l.query).toString()}`:"",f=l.req.method||"GET",k=(await o.getServices()).find(V=>u.startsWith(`/${V.name}`)&&V.active);if(!k)return l.json({error:"Service not found"},404);let J=(u.substring(`/${k.name}`.length)||"/")+d,we=null;["POST","PUT","PATCH","DELETE"].includes(f)&&(l.headers["content-type"]||"").includes("application/json")&&l.body&&(we=JSON.stringify(l.body));let N={};for(let[V,q]of Object.entries(l.headers))V.toLowerCase()!==de&&q&&(N[V]=typeof q=="string"?q:q[0]);return new Promise(V=>{let q={method:f,hostname:"127.0.0.1",port:k.port,path:J,headers:N},te=$o.request(q,_=>{let M="";_.on("data",oe=>{M+=oe}),_.on("end",()=>{if((_.headers["content-type"]||"").includes("application/json"))try{V(l.json(JSON.parse(M),_.statusCode||200))}catch{V(l.text(M,_.statusCode||200))}else V(l.text(M,_.statusCode||200))})});te.on("error",()=>{V(l.json({error:"Service unavailable"},503))}),we&&te.write(we),te.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(!n.includes(u))return l.json({error:`This worker does not handle capability: ${u}`},400);let d=await o.startService(u);return l.json({serviceName:u,isStarted:d})}),i.post("/management/service/:serviceName/stop",async l=>{let u=l.params?.serviceName;if(!u)return l.json({error:"Service name required"},400);if(!n.includes(u))return l.json({error:`This worker does not handle capability: ${u}`},400);let d=await o.stopService(u);return l.json({serviceName:u,isStopped:d})}),i.post("/management/service/:serviceName/restart",async l=>{let u=l.params?.serviceName;if(!u)return l.json({error:"Service name required"},400);if(!n.includes(u))return l.json({error:`This worker does not handle capability: ${u}`},400);let d=await o.restartService(u);return l.json({serviceName:u,isRestarted:d})});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 _s=()=>{let t=qs(process.env.DEBUG)||!1,e=qs(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||$e(),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 qs(t){return t==="true"||t===!0}var A=_s(),Fs={configFilePath:"molnos.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:A.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:A.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:A.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:A.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:A.auth.maxActiveSessions},{flag:"--consoleUrl",path:"auth.consoleUrl",defaultValue:A.auth.consoleUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:A.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:A.email.host},{flag:"--emailUser",path:"email.user",defaultValue:A.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:A.email.password},{flag:"--emailPort",path:"email.port",defaultValue:A.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:A.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:A.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:A.email.debug},{flag:"--db",path:"storage.databaseDirectory",defaultValue:A.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:A.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:A.storage.debug},{flag:"--port",path:"server.port",defaultValue:A.server.port},{flag:"--host",path:"server.host",defaultValue:A.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:A.server.useHttps},{flag:"--http2",path:"server.useHttp2",isFlag:!0,defaultValue:A.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:A.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:A.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:A.server.sslCa},{flag:"--allowed",path:"server.allowedDomains",defaultValue:A.server.allowedDomains,parser:ce.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:A.server.debug},{flag:"--data-path",path:"dataPath",defaultValue:A.molnos.dataPath},{flag:"--initialUserId",path:"molnos.initialUser.id",defaultValue:A.molnos.initialUser.id},{flag:"--initialUserName",path:"molnos.initialUser.userName",defaultValue:A.molnos.initialUser.userName},{flag:"--initialUserEmail",path:"molnos.initialUser.email",defaultValue:A.molnos.initialUser.email}]};function Vs(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",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`
|
|
404
405
|
${l}
|
|
405
406
|
|
|
406
407
|
${u}
|
|
@@ -408,15 +409,15 @@ ${u}
|
|
|
408
409
|
${e}
|
|
409
410
|
|
|
410
411
|
${c?"":`For CLI/Terminal users:
|
|
411
|
-
Run: molnos auth verify ${
|
|
412
|
+
Run: molnos auth verify ${o} ${n}
|
|
412
413
|
`}
|
|
413
414
|
This link expires in ${r} minutes and can only be used once.
|
|
414
415
|
If you didn't request this, please ignore this email.
|
|
415
|
-
`},htmlVersion:(e,r,s)=>{let i=new URL(e),
|
|
416
|
+
`},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",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.",d=c?"":`
|
|
416
417
|
<div style="margin-top: 2rem; padding: 1rem; background-color: #f8f8f8; border-radius: 6px; border-left: 3px solid #3e63dd;">
|
|
417
418
|
<p style="font-size: 0.85rem; font-weight: 600; margin: 0 0 0.5rem 0; color: #202020;">CLI/Terminal Users</p>
|
|
418
419
|
<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>
|
|
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 ${
|
|
420
|
+
<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>
|
|
420
421
|
</div>
|
|
421
422
|
`;return`
|
|
422
423
|
<!DOCTYPE html>
|
|
@@ -431,10 +432,10 @@ If you didn't request this, please ignore this email.
|
|
|
431
432
|
<h1 style="font-size: 1.5rem; font-weight: 600; margin: 0 0 1rem 0; color: #202020;">${l}</h1>
|
|
432
433
|
<p style="font-size: 0.9rem; line-height: 1.5; margin: 0 0 1.5rem 0; color: #646464;">${u}</p>
|
|
433
434
|
<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>
|
|
434
|
-
${
|
|
435
|
+
${d}
|
|
435
436
|
<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>
|
|
436
437
|
</div>
|
|
437
438
|
</body>
|
|
438
439
|
</html>
|
|
439
|
-
`}}}}}function
|
|
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
|
|
440
|
+
`}}}}}function Bs(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 Uo,mkdirSync as No,existsSync as Do}from"node:fs";import{randomBytes as Lo,createHmac as Ho}from"node:crypto";import{join as qo}from"node:path";function Gs(t){let e=t.molnos.dataPath||"data";Do(e)||No(e,{recursive:!0});let r=qo(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 u=i[l]||{},d=u.host||s,f=u.port||o[l],w=u.secure?"https":"http";return{host:d,port:f,url:`${w}://${d}:${f}`}},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}`},internalServiceSecret:t.molnos.cluster?.secret?Ho("sha256",t.molnos.cluster.secret).update("molnos-internal-service").digest("hex"):Lo(32).toString("hex"),services:a,storage:t.storage};return Uo(r,JSON.stringify(c,null,2),"utf-8"),r}async function Fo(){let t=Vo(),e=Vs(t),r=Bs(e);if(!r.success)throw console.error(`Found configuration validation errors: ${JSON.stringify(r.errors)}`),new Fe("Invalid configuration provided. Please see the validation errors and fix these and then retry again.");Gs(e);let s=e.molnos.dataPath||"data",i=e.molnos?.cluster;if(i?.mode==="worker"){let d=await Hs({config:e.server,dataPath:s,cluster:i});zs(d);return}let o=new X({databaseDirectory:_o(s,"molnosdb")});await o.start();let n=new Zt(o),a=new Qt(e.email),c={...e,auth:{...e.auth,appUrl:e.auth.consoleUrl}},l=new Yt(c,a,n),u=await Ls({config:e.server,molnos:e.molnos,auth:l,db:o,oauth:e.oauth,ai:e.ai});zs(u)}function zs(t){let e=async r=>{console.log(`
|
|
441
|
+
[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 Vo(){return new ae(Fs).get()}Fo();export{Fo as start};
|