molnos 1.0.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/LICENSE +89 -0
- package/README.md +66 -0
- package/dist/bin.mjs +5 -0
- package/dist/databases.mjs +2 -0
- package/dist/functions.mjs +16 -0
- package/dist/molnos_core.mjs +152 -0
- package/dist/observability.mjs +5 -0
- package/dist/sites.mjs +2 -0
- package/dist/storage.mjs +2 -0
- package/package.json +80 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// MolnOS Core - See LICENSE file for copyright and license details.
|
|
2
|
+
import X from"crypto";import{URL as Ys}from"url";var tt=class extends Error{constructor(e){super(e),this.name="ValidationError",this.message=e||"Validation did not pass",this.cause={statusCode:400}}};import{existsSync as _s,readFileSync as Ws}from"node:fs";var N=class{config={};options=[];validators=[];autoValidate=!0;constructor(e){let t=e?.configFilePath,r=e?.args||[],s=e?.config||{};this.options=e?.options||[],this.validators=e?.validators||[],e?.autoValidate!==void 0&&(this.autoValidate=e.autoValidate),this.config=this.createConfig(t,r,s)}deepMerge(e,t){let r={...e};for(let s in t)t[s]!==void 0&&(t[s]!==null&&typeof t[s]=="object"&&!Array.isArray(t[s])&&s in e&&e[s]!==null&&typeof e[s]=="object"&&!Array.isArray(e[s])?r[s]=this.deepMerge(e[s],t[s]):t[s]!==void 0&&(r[s]=t[s]));return r}setValueAtPath(e,t,r){let s=t.split("."),i=e;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(e,t){let r=t.split("."),s=e;for(let i of r){if(s==null)return;s=s[i]}return s}createConfig(e,t=[],r={}){let s={};for(let a of this.options)a.defaultValue!==void 0&&this.setValueAtPath(s,a.path,a.defaultValue);let i={};if(e&&_s(e))try{let a=Ws(e,"utf8");i=JSON.parse(a),console.log(`Loaded configuration from ${e}`)}catch(a){console.error(`Error reading config file: ${a instanceof Error?a.message:String(a)}`)}let o=this.parseCliArgs(t),n=this.deepMerge({},s);return n=this.deepMerge(n,i),n=this.deepMerge(n,r),n=this.deepMerge(n,o),n}parseCliArgs(e){let t={},r=e[0]?.endsWith("node")||e[0]?.endsWith("node.exe")?2:0;for(;r<e.length;){let s=e[r++],i=this.options.find(o=>o.flag===s);if(i)if(i.isFlag)this.setValueAtPath(t,i.path,!0);else if(r<e.length&&!e[r].startsWith("-")){let o=e[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(t,i.path,o)}else console.error(`Missing value for option ${s}`)}return t}validate(){for(let e of this.validators){let t=this.getValueAtPath(this.config,e.path),r=e.validator(t,this.config);if(r===!1)throw new tt(e.message);if(typeof r=="string")throw new tt(r)}}get(){return this.autoValidate&&this.validate(),this.config}getValue(e,t){let r=this.getValueAtPath(this.config,e);return r!==void 0?r:t}setValue(e,t){if(typeof t=="object"&&t!==null&&!Array.isArray(t)){let r=this.getValueAtPath(this.config,e)||{};if(typeof r=="object"&&!Array.isArray(r)){let s=this.deepMerge(r,t);this.setValueAtPath(this.config,e,s);return}}this.setValueAtPath(this.config,e,t)}getHelpText(){let e=`Available configuration options:
|
|
3
|
+
|
|
4
|
+
`;for(let t of this.options)e+=`${t.flag}${t.isFlag?"":" <value>"}
|
|
5
|
+
`,t.description&&(e+=` ${t.description}
|
|
6
|
+
`),t.defaultValue!==void 0&&(e+=` Default: ${JSON.stringify(t.defaultValue)}
|
|
7
|
+
`),e+=`
|
|
8
|
+
`;return e}};var J={int:e=>{let t=e.trim();if(!/^[+-]?\d+$/.test(t))throw new Error(`Cannot parse "${e}" as an integer`);let r=Number.parseInt(t,10);if(Number.isNaN(r))throw new Error(`Cannot parse "${e}" as an integer`);return r},float:e=>{let t=e.trim();if(!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(t)){if(t==="Infinity"||t==="-Infinity")return t==="Infinity"?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY;throw new Error(`Cannot parse "${e}" as a number`)}let r=Number.parseFloat(t);if(Number.isNaN(r))throw new Error(`Cannot parse "${e}" as a number`);return r},boolean:e=>{let t=e.trim().toLowerCase();if(["true","yes","1","y"].includes(t))return!0;if(["false","no","0","n"].includes(t))return!1;throw new Error(`Cannot parse "${e}" as a boolean`)},array:e=>e.split(",").map(t=>t.trim()),json:e=>{try{return JSON.parse(e)}catch{throw new Error(`Cannot parse "${e}" as JSON`)}}};import{EventEmitter as Zs}from"events";var Lt=class extends Error{constructor(e){super(),this.name="ValidationError",this.message=e,this.cause={statusCode:400}}};import{existsSync as qs,readFileSync as zs}from"node:fs";var $t=class{config;defaults={configFilePath:"mikromail.config.json",args:[]};constructor(e){let t=e?.config||{},r=e?.configFilePath||this.defaults.configFilePath,s=e?.args||this.defaults.args;this.config=this.create(r,s,t)}create(e,t,r){let s={host:"",user:"",password:"",port:465,secure:!0,debug:!1,maxRetries:2},i={};if(qs(e))try{let n=zs(e,"utf8");i=JSON.parse(n),console.log(`Loaded configuration from ${e}`)}catch(n){console.error(`Error reading config file: ${n instanceof Error?n.message:String(n)}`)}let o=this.parseCliArgs(t);return{...s,...r,...i,...o}}parseCliArgs(e){let t={};for(let r=2;r<e.length;r++)switch(e[r]){case"--host":r+1<e.length&&(t.host=e[++r]);break;case"--user":r+1<e.length&&(t.user=e[++r]);break;case"--password":r+1<e.length&&(t.password=e[++r]);break;case"--port":if(r+1<e.length){let i=Number.parseInt(e[++r],10);Number.isNaN(i)||(t.port=i)}break;case"--secure":t.secure=!0;break;case"--debug":t.debug=!0;break;case"--retries":if(r+1<e.length){let i=Number.parseInt(e[++r],10);Number.isNaN(i)||(t.maxRetries=i)}break}return t}validate(){if(!this.config.host)throw new Lt("Host value not found")}get(){return this.validate(),this.config}};import{promises as Gs}from"node:dns";function he(e){try{let[t,r]=e.split("@");if(!t||t.length>64||t.startsWith(".")||t.endsWith(".")||t.includes("..")||!/^[a-zA-Z0-9!#$%&'*+\-/=?^_`{|}~.]+$/.test(t)||!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 Ks(e){try{let t=await Gs.resolveMx(e);return!!t&&t.length>0}catch{return!1}}async function Mt(e){try{let t=e.split("@")[1];return t?await Ks(t):!1}catch{return!1}}import{Buffer as fe}from"node:buffer";import rt from"node:crypto";import Js from"node:net";import Xs from"node:os";import Ot from"node:tls";var Dt=class{config;socket;connected;lastCommand;serverCapabilities;secureMode;retryCount;maxEmailSize=10485760;constructor(e){this.config={host:e.host,user:e.user,password:e.password,port:e.port??(e.secure?465:587),secure:e.secure??!0,debug:e.debug??!1,timeout:e.timeout??1e4,clientName:e.clientName??Xs.hostname(),maxRetries:e.maxRetries??3,retryDelay:e.retryDelay??1e3,skipAuthentication:e.skipAuthentication||!1},this.socket=null,this.connected=!1,this.lastCommand="",this.serverCapabilities=[],this.secureMode=this.config.secure,this.retryCount=0}log(e,t=!1){this.config.debug&&console.log(`${t?"SMTP ERROR: ":"SMTP: "}${e}`)}async connect(){return new Promise((e,t)=>{let r=setTimeout(()=>{t(new Error(`Connection timeout after ${this.config.timeout}ms`)),this.socket?.destroy()},this.config.timeout);try{this.config.secure?this.createTLSConnection(r,e,t):this.createPlainConnection(r,e,t)}catch(s){clearTimeout(r),this.log(`Failed to create socket: ${s.message}`,!0),t(s)}})}createTLSConnection(e,t,r){this.socket=Ot.connect({host:this.config.host,port:this.config.port,rejectUnauthorized:!0,minVersion:"TLSv1.2",ciphers:"HIGH:!aNULL:!MD5:!RC4"}),this.setupSocketEventHandlers(e,t,r)}createPlainConnection(e,t,r){this.socket=Js.createConnection({host:this.config.host,port:this.config.port}),this.setupSocketEventHandlers(e,t,r)}setupSocketEventHandlers(e,t,r){this.socket&&(this.socket.once("error",s=>{clearTimeout(e),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(e),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,t()):(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(e),r(new Error("Connection closed before initialization completed"))),this.connected=!1}))}async upgradeToTLS(){if(!(!this.socket||this.secureMode))return new Promise((e,t)=>{let s={socket:this.socket,host:this.config.host,rejectUnauthorized:!0,minVersion:"TLSv1.2",ciphers:"HIGH:!aNULL:!MD5:!RC4"},i=Ot.connect(s);i.once("error",o=>{this.log(`TLS upgrade error: ${o.message}`,!0),t(new Error(`STARTTLS error: ${o.message}`))}),i.once("secureConnect",()=>{this.log("Connection upgraded to TLS"),i.authorized?(this.socket=i,this.secureMode=!0,e()):t(new Error(`TLS certificate verification failed: ${i.authorizationError}`))})})}async sendCommand(e,t,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: ${e}`))},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]||"",f=/^(\d{3})(.?)/.exec(u);f?.[1]&&f[2]!=="-"&&(this.socket?.removeListener("data",a),clearTimeout(o),this.log(`SMTP Response: ${n.trim()}`),f[1]===t.toString()?s(n.trim()):i(new Error(`SMTP Error: ${n.trim()}`)))}};this.socket.on("data",a),e.startsWith("AUTH PLAIN")||e.startsWith("AUTH LOGIN")||this.lastCommand==="AUTH LOGIN"&&!e.startsWith("AUTH")?this.log("SMTP Command: [Credentials hidden]"):this.log(`SMTP Command: ${e}`),this.lastCommand=e,this.socket.write(`${e}\r
|
|
10
|
+
`)})}parseCapabilities(e){let t=e.split(`\r
|
|
11
|
+
`);this.serverCapabilities=[];for(let r=1;r<t.length;r++){let s=t[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(t=>t.split(" ")[0]).includes("AUTH")){let t=this.serverCapabilities.find(r=>r.startsWith("AUTH "));if(t){let r=t.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 e=fe.from(`\0${this.config.user}\0${this.config.password}`).toString("base64");await this.sendCommand(`AUTH PLAIN ${e}`,235)}async authenticateLogin(){await this.sendCommand("AUTH LOGIN",334),await this.sendCommand(fe.from(this.config.user).toString("base64"),334),await this.sendCommand(fe.from(this.config.password).toString("base64"),235)}async authenticateCramMD5(){let e=await this.sendCommand("AUTH CRAM-MD5",334),t=fe.from(e.substr(4),"base64").toString("utf8"),r=rt.createHmac("md5",this.config.password);r.update(t);let s=r.digest("hex"),i=`${this.config.user} ${s}`,o=fe.from(i).toString("base64");await this.sendCommand(o,235)}generateMessageId(){let e=rt.randomBytes(16).toString("hex"),t=this.config.user.split("@")[1]||"localhost";return`<${e}@${t}>`}generateBoundary(){return`----=_NextPart_${rt.randomBytes(12).toString("hex")}`}encodeHeaderValue(e){return/^[\x00-\x7F]*$/.test(e)?e:`=?UTF-8?Q?${e.replace(/[^\x00-\x7F]/g,t=>{let r=t.charCodeAt(0).toString(16).toUpperCase();return`=${r.length<2?`0${r}`:r}`})}?=`}sanitizeHeader(e){let t=e.replace(/[\r\n\t]+/g," ").replace(/\s{2,}/g," ").trim();return this.encodeHeaderValue(t)}createEmailHeaders(e){let t=this.generateMessageId(),r=new Date().toUTCString(),s=e.from||this.config.user,i=Array.isArray(e.to)?e.to.join(", "):e.to,o=[`From: ${this.sanitizeHeader(s)}`,`To: ${this.sanitizeHeader(i)}`,`Subject: ${this.sanitizeHeader(e.subject)}`,`Message-ID: ${t}`,`Date: ${r}`,"MIME-Version: 1.0"];if(e.cc){let n=Array.isArray(e.cc)?e.cc.join(", "):e.cc;o.push(`Cc: ${this.sanitizeHeader(n)}`)}if(e.replyTo&&o.push(`Reply-To: ${this.sanitizeHeader(e.replyTo)}`),e.headers)for(let[n,a]of Object.entries(e.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(e){let{text:t,html:r}=e,s=this.createEmailHeaders(e),i=this.generateBoundary();return r&&t?(s.push(`Content-Type: multipart/alternative; boundary="${i}"`),`${s.join(`\r
|
|
12
|
+
`)}\r
|
|
13
|
+
\r
|
|
14
|
+
--${i}\r
|
|
15
|
+
Content-Type: text/plain; charset=utf-8\r
|
|
16
|
+
\r
|
|
17
|
+
${t||""}\r
|
|
18
|
+
\r
|
|
19
|
+
--${i}\r
|
|
20
|
+
Content-Type: text/html; charset=utf-8\r
|
|
21
|
+
\r
|
|
22
|
+
${r||""}\r
|
|
23
|
+
\r
|
|
24
|
+
--${i}--\r
|
|
25
|
+
`):(s.push("Content-Type: text/html; charset=utf-8"),r?`${s.join(`\r
|
|
26
|
+
`)}\r
|
|
27
|
+
\r
|
|
28
|
+
${r}`:`${s.join(`\r
|
|
29
|
+
`)}\r
|
|
30
|
+
\r
|
|
31
|
+
${t||""}`)}async smtpHandshake(){let e=await this.sendCommand(`EHLO ${this.config.clientName}`,250);if(this.parseCapabilities(e),!this.secureMode&&this.serverCapabilities.includes("STARTTLS")){await this.sendCommand("STARTTLS",220),await this.upgradeToTLS();let t=await this.sendCommand(`EHLO ${this.config.clientName}`,250);this.parseCapabilities(t)}this.config.skipAuthentication?this.log("Authentication skipped (testing mode)"):await this.authenticate()}async sendEmail(e){let t=e.from||this.config.user,{to:r,subject:s}=e,i=e.text||"",o=e.html||"";if(!t||!r||!s||!i&&!o)return{success:!1,error:"Missing required email parameters (from, to, subject, and either text or html)"};if(!he(t))return{success:!1,error:"Invalid email address format"};let n=Array.isArray(e.to)?e.to:[e.to];for(let a of n)if(!he(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:<${t}>`,250);for(let u of n)await this.sendCommand(`RCPT TO:<${u}>`,250);if(e.cc){let u=Array.isArray(e.cc)?e.cc:[e.cc];for(let f of u)he(f)&&await this.sendCommand(`RCPT TO:<${f}>`,250)}if(e.bcc){let u=Array.isArray(e.bcc)?e.bcc:[e.bcc];for(let f of u)he(f)&&await this.sendCommand(`RCPT TO:<${f}>`,250)}await this.sendCommand("DATA",354);let a=this.createMultipartEmail(e);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(e){this.log(`Error during QUIT: ${e.message}`,!0)}finally{this.socket&&(this.socket.destroy(),this.socket=null,this.connected=!1)}}};var st=class{smtpClient;constructor(e){let t=new $t(e).get(),r=new Dt(t);this.smtpClient=r}async send(e){try{let t=Array.isArray(e.to)?e.to:[e.to];for(let s of t)await Mt(s)||console.error(`Warning: No MX records found for recipient domain: ${s}`);let r=await this.smtpClient.sendEmail(e);r.success?console.log(`Message ID: ${r.messageId}`):console.error(`Failed to send email: ${r.error}`),await this.smtpClient.close()}catch(t){console.error("Error in email sending process:",t.message)}}};var it=()=>{let e=Qs(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:e},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:e},storage:{databaseDirectory:"mikroauth",encryptionKey:process.env.STORAGE_KEY||"",debug:e},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:e}}};function Qs(e){return e==="true"||e===!0}var ei=class{algorithm="HS256";secret="HS256";constructor(e){if(process.env.NODE_ENV==="production"&&(!e||e.length<32||e===it().auth.jwtSecret))throw new Error("Production environment requires a strong JWT secret (min 32 chars)");this.secret=e}sign(e,t={}){let r={alg:this.algorithm,typ:"JWT"},s=Math.floor(Date.now()/1e3),i={...e,iat:s};t.exp!==void 0&&(i.exp=s+t.exp),t.notBefore!==void 0&&(i.nbf=s+t.notBefore),t.issuer&&(i.iss=t.issuer),t.audience&&(i.aud=t.audience),t.subject&&(i.sub=t.subject),t.jwtid&&(i.jti=t.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(e,t={}){let r=this.decode(e);if(r.header.alg!==this.algorithm)throw new Error(`Invalid algorithm. Expected ${this.algorithm}, got ${r.header.alg}`);let[s,i]=e.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=t.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(t.issuer&&n.iss!==t.issuer)throw new Error("Invalid issuer");if(t.audience&&n.aud!==t.audience)throw new Error("Invalid audience");if(t.subject&&n.sub!==t.subject)throw new Error("Invalid subject");return n}decode(e){let t=e.split(".");if(t.length!==3)throw new Error("Invalid token format");try{let[r,s,i]=t,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(e){let t=X.createHmac("sha256",this.secret).update(e).digest();return this.base64UrlEncode(t)}base64UrlEncode(e){let t;return typeof e=="string"?t=Buffer.from(e):t=e,t.toString("base64").replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}base64UrlDecode(e){let t=e.replace(/-/g,"+").replace(/_/g,"/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw new Error("Invalid base64 string")}return Buffer.from(t,"base64").toString()}},ti=class{templates;constructor(e){e?this.templates=e:this.templates=ri}getText(e,t,r){return this.templates.textVersion(e,t,r).trim()}getHtml(e,t,r){return this.templates.htmlVersion(e,t,r).trim()}},ri={textVersion:(e,t,r)=>`
|
|
33
|
+
Click this link to login: ${e}
|
|
34
|
+
|
|
35
|
+
Security Information:
|
|
36
|
+
- Expires in ${t} minutes
|
|
37
|
+
- Can only be used once
|
|
38
|
+
- Should only be used by you
|
|
39
|
+
|
|
40
|
+
If you didn't request this link, please ignore this email.
|
|
41
|
+
`,htmlVersion:(e,t,r)=>`
|
|
42
|
+
<!DOCTYPE html>
|
|
43
|
+
<html>
|
|
44
|
+
<head>
|
|
45
|
+
<meta charset="utf-8">
|
|
46
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
47
|
+
<title>Your Login Link</title>
|
|
48
|
+
<style>
|
|
49
|
+
body {
|
|
50
|
+
font-family: Arial, sans-serif;
|
|
51
|
+
line-height: 1.6;
|
|
52
|
+
color: #333;
|
|
53
|
+
max-width: 600px;
|
|
54
|
+
margin: 0 auto;
|
|
55
|
+
padding: 20px;
|
|
56
|
+
}
|
|
57
|
+
.container {
|
|
58
|
+
border: 1px solid #e1e1e1;
|
|
59
|
+
border-radius: 5px;
|
|
60
|
+
padding: 20px;
|
|
61
|
+
}
|
|
62
|
+
.button {
|
|
63
|
+
display: inline-block;
|
|
64
|
+
background-color: #4CAF50;
|
|
65
|
+
color: white;
|
|
66
|
+
text-decoration: none;
|
|
67
|
+
padding: 10px 20px;
|
|
68
|
+
border-radius: 5px;
|
|
69
|
+
margin: 20px 0;
|
|
70
|
+
}
|
|
71
|
+
.security-info {
|
|
72
|
+
background-color: #f8f8f8;
|
|
73
|
+
padding: 15px;
|
|
74
|
+
border-radius: 5px;
|
|
75
|
+
margin-top: 20px;
|
|
76
|
+
}
|
|
77
|
+
.footer {
|
|
78
|
+
margin-top: 20px;
|
|
79
|
+
font-size: 12px;
|
|
80
|
+
color: #888;
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
83
|
+
</head>
|
|
84
|
+
<body>
|
|
85
|
+
<div class="container">
|
|
86
|
+
<h2>Your Secure Login Link</h2>
|
|
87
|
+
<p>Click the button below to log in to your account:</p>
|
|
88
|
+
<a href="${e}" class="button">Login to Your Account</a>
|
|
89
|
+
|
|
90
|
+
<p>
|
|
91
|
+
Hello, this is a test email! Hall\xE5, MikroMail has international support for, among others, espa\xF1ol, fran\xE7ais, portugu\xEAs, \u4E2D\u6587, \u65E5\u672C\u8A9E, and \u0420\u0443\u0441\u0441\u043A\u0438\u0439!
|
|
92
|
+
</p>
|
|
93
|
+
|
|
94
|
+
<div class="security-info">
|
|
95
|
+
<h3>Security Information:</h3>
|
|
96
|
+
<ul>
|
|
97
|
+
<li>This link expires in ${t} minutes</li>
|
|
98
|
+
<li>Can only be used once</li>
|
|
99
|
+
<li>Should only be used by you</li>
|
|
100
|
+
</ul>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<p>If you didn't request this link, please ignore this email.</p>
|
|
104
|
+
|
|
105
|
+
<div class="footer">
|
|
106
|
+
<p>This is an automated message, please do not reply to this email.</p>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</body>
|
|
110
|
+
</html>
|
|
111
|
+
`},si=class{constructor(e){this.options=e}sentEmails=[];async sendMail(e){this.sentEmails.push(e),this.options?.logToConsole&&(console.log("Email sent:"),console.log(`From: ${e.from}`),console.log(`To: ${e.to}`),console.log(`Subject: ${e.subject}`),console.log(`Text: ${e.text}`)),this.options?.onSend&&this.options.onSend(e)}getSentEmails(){return[...this.sentEmails]}clearSentEmails(){this.sentEmails=[]}},ii=class{data=new Map;collections=new Map;expiryEmitter=new Zs;expiryCheckInterval;constructor(e=1e3){this.expiryCheckInterval=setInterval(()=>this.checkExpiredItems(),e)}destroy(){clearInterval(this.expiryCheckInterval),this.data.clear(),this.collections.clear(),this.expiryEmitter.removeAllListeners()}checkExpiredItems(){let e=Date.now();for(let[t,r]of this.data.entries())r.expiry&&r.expiry<e&&(this.data.delete(t),this.expiryEmitter.emit("expired",t));for(let[t,r]of this.collections.entries())r.expiry&&r.expiry<e&&(this.collections.delete(t),this.expiryEmitter.emit("expired",t))}async set(e,t,r){let s=r?Date.now()+r*1e3:null;this.data.set(e,{value:t,expiry:s})}async get(e){let t=this.data.get(e);return t?t.expiry&&t.expiry<Date.now()?(this.data.delete(e),null):t.value:null}async delete(e){this.data.delete(e),this.collections.delete(e)}async addToCollection(e,t,r){this.collections.has(e)||this.collections.set(e,{items:[],expiry:r?Date.now()+r*1e3:null});let s=this.collections.get(e);s&&(r&&(s.expiry=Date.now()+r*1e3),s.items.push(t))}async removeFromCollection(e,t){let r=this.collections.get(e);r&&(r.items=r.items.filter(s=>s!==t))}async getCollection(e){let t=this.collections.get(e);return t?[...t.items]:[]}async getCollectionSize(e){let t=this.collections.get(e);return t?t.items.length:0}async removeOldestFromCollection(e){let t=this.collections.get(e);return!t||t.items.length===0?null:t.items.shift()||null}async findKeys(e){let t=e.replace(/\*/g,".*").replace(/\?/g,"."),r=new RegExp(`^${t}$`),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 Ut(e){if(!e||e.trim()===""||(e.match(/@/g)||[]).length!==1)return!1;let[t,r]=e.split("@");return!(!t||!r||e.includes("..")||!oi(t)||!ni(r))}function oi(e){return e.startsWith('"')&&e.endsWith('"')?!e.slice(1,-1).includes('"'):e.length>64||e.startsWith(".")||e.endsWith(".")?!1:/^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$/.test(e)}function ni(e){if(e.startsWith("[")&&e.endsWith("]")){let r=e.slice(1,-1);return r.startsWith("IPv6:")?ci(r.slice(5)):ai(r)}let t=e.split(".");if(t.length===0)return!1;for(let r of t)if(!r||r.length>63||!/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/.test(r))return!1;if(t.length>1){let r=t[t.length-1];if(!/^[a-zA-Z]{2,}$/.test(r))return!1}return!0}function ai(e){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(e)}function ci(e){if(!/^[a-fA-F0-9:]+$/.test(e))return!1;let t=e.split(":");return!(t.length<2||t.length>8)}var w=it(),li=e=>{let t={configFilePath:"mikroauth.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:w.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:w.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:w.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:w.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:w.auth.maxActiveSessions},{flag:"--appUrl",path:"auth.appUrl",defaultValue:w.auth.appUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:w.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:w.email.host},{flag:"--emailUser",path:"email.user",defaultValue:w.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:w.email.password},{flag:"--emailPort",path:"email.port",defaultValue:w.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:w.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:w.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:w.email.debug},{flag:"--dir",path:"storage.databaseDirectory",defaultValue:w.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:w.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:w.storage.debug},{flag:"--port",path:"server.port",defaultValue:w.server.port},{flag:"--host",path:"server.host",defaultValue:w.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:w.server.useHttps},{flag:"--https",path:"server.useHttp2",isFlag:!0,defaultValue:w.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:w.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:w.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:w.server.sslCa},{flag:"--ratelimit",path:"server.rateLimit.enabled",defaultValue:w.server.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"server.rateLimit.requestsPerMinute",defaultValue:w.server.rateLimit.requestsPerMinute},{flag:"--allowed",path:"server.allowedDomains",defaultValue:w.server.allowedDomains,parser:J.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:w.server.debug}]};return e&&(t.config=e),t},Ae={linkSent:"If a matching account was found, a magic link has been sent.",revokedSuccess:"All other sessions revoked successfully.",logoutSuccess:"Logged out successfully."},Bt=class{config;email;storage;jwtService;templates;constructor(e,t,r){let s=new N(li({auth:e.auth,email:e.email})).get();s.auth.debug&&console.log("Using configuration:",s),this.config=s,this.email=t||new si,this.storage=r||new ii,this.jwtService=new ei(s.auth.jwtSecret),this.templates=new ti(s?.auth.templates),this.checkIfUsingDefaultCredentialsInProduction()}checkIfUsingDefaultCredentialsInProduction(){process.env.NODE_ENV==="production"&&this.config.auth.jwtSecret===it().auth.jwtSecret&&(console.error("WARNING: Using default secrets in production environment!"),process.exit(1))}generateToken(e){let t=Date.now().toString(),r=X.randomBytes(32).toString("hex");return X.createHash("sha256").update(`${e}:${t}:${r}`).digest("hex")}generateJsonWebToken(e){return this.jwtService.sign({sub:e.id,email:e.email,username:e.username,role:e.role,exp:Math.floor(Date.now()/1e3)+3600*24})}generateRefreshToken(){return X.randomBytes(40).toString("hex")}async trackSession(e,t,r){let s=`sessions:${e}`;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,t,this.config.auth.refreshTokenExpirySeconds),await this.storage.set(`refresh:${t}`,JSON.stringify(r),this.config.auth.refreshTokenExpirySeconds)}generateMagicLinkUrl(e){let{token:t,email:r,appUrl:s}=e,i=s||this.config.auth.appUrl;try{return new Ys(i),`${i}?token=${encodeURIComponent(t)}&email=${encodeURIComponent(r)}`}catch{throw new Error("Invalid base URL configuration")}}async createMagicLink(e){let{email:t,ip:r,metadata:s,appUrl:i,subject:o}=e;if(!Ut(t))throw new Error("Valid email required");try{let n=this.generateToken(t),a=`magic_link:${n}`,c={email:t,ipAddress:r||"unknown",createdAt:Date.now()};await this.storage.set(a,JSON.stringify(c),this.config.auth.magicLinkExpirySeconds);let l=await this.storage.findKeys("magic_link:*");for(let h of l){if(h===a)continue;let y=await this.storage.get(h);if(y)try{JSON.parse(y).email===t&&await this.storage.delete(h)}catch{}}let u=this.generateMagicLinkUrl({token:n,email:t,appUrl:i}),f=Math.ceil(this.config.auth.magicLinkExpirySeconds/60);return await this.email.sendMail({from:this.config.email.user,to:t,subject:o||this.config.email.emailSubject,text:this.templates.getText(u,f,s),html:this.templates.getHtml(u,f,s)}),{message:Ae.linkSent}}catch(n){throw console.error(`Failed to process magic link request: ${n}`),new Error("Failed to process magic link request")}}async createToken(e){let{email:t,username:r,role:s,ip:i}=e;if(!Ut(t))throw new Error("Valid email required");try{let o=X.randomBytes(16).toString("hex"),n=this.generateRefreshToken(),a=Date.now(),c={sub:t,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:t,username:r,role:s,ipAddress:i||"unknown",tokenId:o,createdAt:a,lastLogin:a};return await this.trackSession(t,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(e){let{token:t,email:r}=e;try{let s=`magic_link:${t}`,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=X.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},f=this.jwtService.sign(u,{exp:this.config.auth.jwtExpirySeconds});return await this.trackSession(r,l,{...o,tokenId:c,createdAt:Date.now()}),{accessToken:f,refreshToken:l,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(s){throw console.error("Token verification error:",s),new Error("Verification failed")}}async refreshAccessToken(e){try{let t=await this.storage.get(`refresh:${e}`);if(!t)throw new Error("Invalid or expired refresh token");let r=JSON.parse(t),s=r.email;if(!s)throw new Error("Invalid refresh token data");let i=r.username,o=r.role,n=X.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:${e}`,JSON.stringify(r),this.config.auth.refreshTokenExpirySeconds),{accessToken:c,refreshToken:e,exp:this.config.auth.jwtExpirySeconds,tokenType:"Bearer"}}catch(t){throw console.error("Token refresh error:",t),new Error("Token refresh failed")}}verify(e){try{return this.jwtService.verify(e)}catch{throw new Error("Invalid token")}}async logout(e){try{if(!e||typeof e!="string")throw new Error("Refresh token is required");let t=await this.storage.get(`refresh:${e}`);if(!t)return{message:Ae.logoutSuccess};let r=JSON.parse(t).email;if(!r)throw new Error("Invalid refresh token data");await this.storage.delete(`refresh:${e}`);let s=`sessions:${r}`;return await this.storage.removeFromCollection(s,e),{message:Ae.logoutSuccess}}catch(t){throw console.error("Logout error:",t),new Error("Logout failed")}}async getSessions(e){try{if(!e.user?.email)throw new Error("User not authenticated");let t=e.user.email,r=e.body?.refreshToken,s=`sessions:${t}`,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(t){throw console.error("Get sessions error:",t),new Error("Failed to fetch sessions")}}async revokeSessions(e){try{if(!e.user?.email)throw new Error("User not authenticated");let t=e.user.email,r=e.body?.refreshToken,s=`sessions:${t}`,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:Ae.revokedSuccess}}catch(t){throw console.error("Revoke sessions error:",t),new Error("Failed to revoke sessions")}}authenticate(e,t){try{let r=e.headers?.authorization;if(!r||!r.startsWith("Bearer "))throw new Error("Authentication required");let s=r.split(" ")[1];try{let i=this.verify(s);e.user={email:i.sub},t()}catch{throw new Error("Invalid or expired token")}}catch(r){t(r)}}},Ht=class{db;PREFIX_KV="kv:";PREFIX_COLLECTION="coll:";TABLE_NAME="mikroauth";constructor(e){this.db=e}async start(){await this.db.start()}async close(){await this.db.close()}async set(e,t,r){let s=`${this.PREFIX_KV}${e}`,i=r?Date.now()+r*1e3:void 0;await this.db.write({tableName:this.TABLE_NAME,key:s,value:t,expiration:i})}async get(e){let t=`${this.PREFIX_KV}${e}`;return await this.db.get({tableName:this.TABLE_NAME,key:t})||null}async delete(e){let t=`${this.PREFIX_KV}${e}`;await this.db.delete({tableName:this.TABLE_NAME,key:t})}async addToCollection(e,t,r){let s=`${this.PREFIX_COLLECTION}${e}`,i=await this.db.get({tableName:this.TABLE_NAME,key:s}),o=[];i&&(o=JSON.parse(i)),o.includes(t)||o.push(t);let n=r?Date.now()+r*1e3:void 0;await this.db.write({tableName:this.TABLE_NAME,key:s,value:JSON.stringify(o),expiration:n})}async removeFromCollection(e,t){let r=`${this.PREFIX_COLLECTION}${e}`,s=await this.db.get({tableName:this.TABLE_NAME,key:r});if(!s)return;let i=JSON.parse(s);i=i.filter(o=>o!==t),await this.db.write({tableName:this.TABLE_NAME,key:r,value:JSON.stringify(i)})}async getCollection(e){let t=`${this.PREFIX_COLLECTION}${e}`,r=await this.db.get({tableName:this.TABLE_NAME,key:t});return r?JSON.parse(r):[]}async getCollectionSize(e){return(await this.getCollection(e)).length}async removeOldestFromCollection(e){let t=`${this.PREFIX_COLLECTION}${e}`,r=await this.db.get({tableName:this.TABLE_NAME,key:t});if(!r)return null;let s=JSON.parse(r);if(s.length===0)return null;let i=s.shift();return await this.db.write({tableName:this.TABLE_NAME,key:t,value:JSON.stringify(s)}),i}async findKeys(e){let t=e.replace(/\./g,"\\.").replace(/\*/g,".*").replace(/\?/g,"."),r=new RegExp(`^${t}$`);return(await this.db.get({tableName:this.TABLE_NAME})).filter(s=>{let i=s[0];return typeof i=="string"&&i.startsWith(this.PREFIX_KV)}).map(s=>s[0].substring(this.PREFIX_KV.length)).filter(s=>r.test(s))}},Ft=class{email;sender;constructor(e){this.sender=e.user,this.email=new st({config:e})}async sendMail(e){await this.email.send({from:this.sender,to:e.to,cc:e.cc,bcc:e.bcc,subject:e.subject,text:e.text,html:e.html})}};var ke=class extends Error{constructor(e){super(),this.name="NotFoundError",this.message=e||"Resource not found",this.cause={statusCode:404}}},pe=class extends Error{constructor(e){super(),this.name="CheckpointError",this.message=e,this.cause={statusCode:500}}};var L=()=>Date.now(),Vt=(e,t)=>t==="D"||e.length===0||e.join(" ")==="null"?null:Nt(e),Nt=e=>{try{return JSON.parse(e.join(" "))}catch{return}};function ot(e){return e==="true"||e===!0}function _t(e){let t=(n,a)=>{if(n){if(a==="json")return Nt(n)||n;if(a==="number")return Number.parseInt(n,10)}},r=t(e?.filter,"json"),s=t(e?.sort,"json"),i=t(e?.limit,"number"),o=t(e?.offset,"number");if(!(!r&&!s&&!i&&!o))return{filter:r,sort:s,limit:i,offset:o}}import{existsSync as nt}from"fs";import{readFile as Wt,unlink as ui,writeFile as qt}from"fs/promises";var zt=class{checkpointInterval;defaultCheckpointIntervalMs=10*1e3;isCheckpointing=!1;lastCheckpointTime=0;walFile;checkpointTimer=null;wal;table;constructor(e){let{table:t,wal:r,walFile:s,checkpointIntervalMs:i}=e;this.defaultCheckpointIntervalMs=i||this.defaultCheckpointIntervalMs,this.table=t,this.wal=r,this.walFile=s,this.checkpointInterval=i,this.lastCheckpointTime=L()}async start(){let e=`${this.walFile}.checkpoint`;if(nt(e)){console.log("Incomplete checkpoint detected, running recovery...");try{let t=await Wt(e,"utf8");console.log(`Incomplete checkpoint from: ${new Date(Number.parseInt(t))}`),await this.checkpoint(!0)}catch(t){throw new ke(`Error reading checkpoint file: ${t}`)}}this.checkpointTimer=setInterval(async()=>{try{await this.checkpoint()}catch(t){throw new pe(`Checkpoint interval failed: ${t}`)}},this.checkpointInterval)}stop(){this.checkpointTimer&&(clearInterval(this.checkpointTimer),this.checkpointTimer=null),this.isCheckpointing=!1}async checkpoint(e=!1){if(this.isCheckpointing){process.env.DEBUG==="true"&&console.log("Checkpoint already in progress, skipping");return}let t=L();if(!e&&t-this.lastCheckpointTime<this.checkpointInterval)return;this.isCheckpointing=!0;let r=`${this.walFile}.checkpoint`;try{if(nt(r)){process.env.DEBUG==="true"&&console.log("Checkpoint file exists, another process is checkpointing");return}await this.wal.flushWAL(),await qt(r,t.toString(),"utf8");let s=await this.getTablesFromWAL();await this.persistTables(s),await qt(this.walFile,"","utf8"),process.env.DEBUG==="true"&&console.log("WAL truncated successfully");try{await ui(r)}catch(i){if(i.code!=="ENOENT")throw new pe(`Failed to delete checkpoint file: ${i}`)}this.wal.clearPositions(),this.lastCheckpointTime=t,process.env.DEBUG==="true"&&console.log("Checkpoint complete")}catch(s){throw new pe(`Checkpoint failed: ${s}`)}finally{this.isCheckpointing=!1}}async getTablesFromWAL(){let e=new Set;if(!nt(this.walFile))return e;try{let t=await Wt(this.walFile,"utf8");if(!t.trim())return e;let r=t.trim().split(`
|
|
112
|
+
`);for(let s of r){if(!s.trim())continue;let i=s.split(" ");i.length>=3&&e.add(i[2])}}catch(t){throw new pe(`Error reading WAL file: ${t}`)}return e}async persistTables(e){let t=Array.from(e).map(async r=>{try{await this.table.flushTableToDisk(r),console.log(`Checkpointed table "${r}"`)}catch(s){console.error(`Failed to checkpoint table "${r}": ${s.message}`),console.error("Skipping corrupted table and continuing checkpoint...")}});await Promise.allSettled(t)}};import{existsSync as Gt,statSync as Kt,writeFileSync as di}from"fs";import{appendFile as hi,readFile as Jt}from"fs/promises";var Xt=class{walFile;walInterval;walBuffer=[];maxWalBufferEntries=Number.parseInt(process.env.MAX_WAL_BUFFER_ENTRIES||"100");maxWalBufferSize=Number.parseInt(process.env.MAX_WAL_BUFFER_SIZE||(1024*1024*.1).toString());maxWalSizeBeforeCheckpoint=Number.parseInt(process.env.MAX_WAL_BUFFER_SIZE||(1024*1024*.1).toString());lastProcessedEntryCount=new Map;checkpointCallback=null;walTimer=null;constructor(e,t){this.walFile=e,this.walInterval=t,this.start()}setCheckpointCallback(e){this.checkpointCallback=e}start(){Gt(this.walFile)||di(this.walFile,"","utf-8"),this.walTimer=setInterval(async()=>{try{this.walBuffer.length>0&&await this.flushWAL()}catch(e){console.error("WAL flush interval failed:",e)}},this.walInterval)}stop(){this.walTimer&&(clearInterval(this.walTimer),this.walTimer=null)}checkWalFileExists(){if(!Gt(this.walFile))throw new ke(`WAL file "${this.walFile}" does not exist`)}async loadWAL(e){this.checkWalFileExists();let t=[];if((Kt(this.walFile)?.size||0)===0)return t;try{let i=(await Jt(this.walFile,"utf8")).trim().split(`
|
|
113
|
+
`),o=L();for(let n=0;n<i.length;n++){if(!i[n].trim())continue;let c=this.lastProcessedEntryCount.get(e||"")||0;if(e&&n<c)continue;let[l,u,f,h,y,C,...g]=i[n].split(" ");if(e&&f!==e)continue;let I=Number(h.split(":")[1]),T=y==="0"?null:Number(y.split(":")[1]);if(T&&T<o)continue;let H=Vt(g,u);H!==void 0&&(e&&this.lastProcessedEntryCount.set(e,n+1),u==="W"?t.push({operation:"W",tableName:f,key:C,data:{value:H,version:I,timestamp:o,expiration:T}}):u==="D"&&t.push({operation:"D",tableName:f,key:C}))}return t}catch(s){return console.error(e?`Failed to replay WAL for table "${e}": ${s.message}`:`Failed to replay WAL: ${s.message}`),t}}async hasNewWALEntriesForTable(e){this.checkWalFileExists();try{let t=await Jt(this.walFile,"utf8");if(!t.trim())return!1;let r=t.trim().split(`
|
|
114
|
+
`),s=this.lastProcessedEntryCount.get(e)||0;if(s>=r.length)return!1;for(let i=s;i<r.length;i++){let o=r[i];if(!o.trim())continue;let n=o.split(" ");if(n.length>=3&&n[2]===e)return!0}return!1}catch(t){return console.error(`Error checking WAL for ${e}:`,t),!0}}async flushWAL(){if(this.checkWalFileExists(),this.walBuffer.length===0)return;let e=[...this.walBuffer];this.walBuffer=[];try{await hi(this.walFile,e.join(""),"utf8");let t=Kt(this.walFile);t.size>this.maxWalSizeBeforeCheckpoint&&(process.env.DEBUG==="true"&&console.log(`WAL size (${t.size}) exceeds limit (${this.maxWalSizeBeforeCheckpoint}), triggering checkpoint`),this.checkpointCallback&&setImmediate(async()=>{try{await this.checkpointCallback()}catch(r){console.error("Error during automatic checkpoint:",r)}}))}catch(t){throw console.error(`Failed to flush WAL: ${t.message}`),this.walBuffer=[...e,...this.walBuffer],t}}async appendToWAL(e,t,r,s,i,o=0){this.checkWalFileExists();let a=`${L()} ${t} ${e} v:${i} x:${o} ${r} ${JSON.stringify(s)}
|
|
115
|
+
`;this.walBuffer.push(a),this.walBuffer.length>=this.maxWalBufferEntries&&await this.flushWAL(),this.walBuffer.reduce((l,u)=>l+u.length,0)>=this.maxWalBufferSize&&await this.flushWAL()}clearPositions(){this.lastProcessedEntryCount.clear()}};var se=()=>({db:{dbName:"mikrodb",databaseDirectory:"mikrodb",walFileName:"wal.log",walInterval:2e3,encryptionKey:"",maxWriteOpsBeforeFlush:100,debug:ot(process.env.DEBUG)||!1},events:{},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:ot(process.env.DEBUG)||!1}});import{createCipheriv as fi,createDecipheriv as pi,randomBytes as mi,scryptSync as gi}from"crypto";var Te=class{algo="aes-256-gcm";KEY_LENGTH=32;IV_LENGTH=12;generateKey(e,t){return gi(`${t}#${e}`,t,this.KEY_LENGTH)}generateIV(){return mi(this.IV_LENGTH)}encrypt(e,t,r){if(t.length!==this.KEY_LENGTH)throw new Error(`Invalid key length: ${t.length} bytes. Expected: ${this.KEY_LENGTH} bytes`);if(r.length!==this.IV_LENGTH)throw new Error(`Invalid IV length: ${r.length} bytes. Expected: ${this.IV_LENGTH} bytes`);let s=fi(this.algo,t,r),i=Buffer.concat([s.update(e,"utf8"),s.final()]),o=s.getAuthTag();return{iv:r,encrypted:i,authTag:o}}decrypt(e,t){let{iv:r,encrypted:s,authTag:i}=e;if(t.length!==this.KEY_LENGTH)throw new Error(`Invalid key length: ${t.length} bytes. Expected: ${this.KEY_LENGTH} bytes`);if(r.length!==this.IV_LENGTH)throw new Error(`Invalid IV length: ${r.length} bytes. Expected: ${this.IV_LENGTH} bytes`);let o=pi(this.algo,t,r);return o.setAuthTag(i),Buffer.concat([o.update(s),o.final()]).toString("utf8")}serialize(e){return Buffer.concat([Buffer.from([1]),Buffer.from([e.iv.length]),e.iv,Buffer.from([e.authTag.length]),e.authTag,e.encrypted])}deserialize(e){let t=0,r=e[t++];if(r!==1)throw new Error(`Unsupported encryption format version: ${r}`);let s=e[t++],i=e.subarray(t,t+s);t+=s;let o=e[t++],n=e.subarray(t,t+o);t+=o;let a=e.subarray(t);return{iv:i,authTag:n,encrypted:a}}toHex(e){return e.toString("hex")}toUtf8(e){return e.toString("utf8")}toBuffer(e){return Buffer.from(e,"hex")}};var Re=class{readTableFromBinaryBuffer(e){if(e.length<8||e[0]!==77||e[1]!==68||e[2]!==66||e[3]!==1)throw new Error("Invalid table file format");let t=e.readUInt32LE(4),r=new Map,s=8,i=L();for(let o=0;o<t&&s+26<=e.length;o++){let n=e.readUInt16LE(s);s+=2;let a=e.readUInt32LE(s);s+=4;let c=e.readUInt32LE(s);s+=4;let l=Number(e.readBigUInt64LE(s));s+=8;let u=Number(e.readBigUInt64LE(s));if(s+=8,s+n+a>e.length)break;if(u&&u<=i){s+=n+a;continue}let f=e.toString("utf8",s,s+n);s+=n;let h=e.slice(s,s+a);s+=a;let y=this.decodeValue(h);r.set(f,{value:y,version:c,timestamp:l,expiration:u||null})}return r}toBinaryBuffer(e){let t=[],r=Buffer.from([77,68,66,1]);t.push(r);let s=Array.from(e.entries()).filter(([o])=>typeof o=="string"),i=Buffer.alloc(4);i.writeUInt32LE(s.length,0),t.push(i);for(let[o,n]of s){if(o===null||typeof o!="string")continue;let a=Buffer.from(o),c=this.encodeValue(n.value),l=Buffer.alloc(2);l.writeUInt16LE(a.length,0),t.push(l);let u=Buffer.alloc(4);u.writeUInt32LE(c.length,0),t.push(u);let f=Buffer.alloc(4);f.writeUInt32LE(n.version||0,0),t.push(f);let h=Buffer.alloc(8);h.writeBigUInt64LE(BigInt(n.timestamp||0),0),t.push(h);let y=Buffer.alloc(8);y.writeBigUInt64LE(BigInt(n.expiration||0),0),t.push(y),t.push(a),t.push(c)}return Buffer.concat(t)}encodeValue(e){if(e==null)return Buffer.from([0]);if(typeof e=="boolean")return Buffer.from([1,e?1:0]);if(typeof e=="number"){if(Number.isInteger(e)&&e>=-2147483648&&e<=2147483647){let r=Buffer.alloc(5);return r[0]=2,r.writeInt32LE(e,1),r}let t=Buffer.alloc(9);return t[0]=3,t.writeDoubleLE(e,1),t}if(typeof e=="string"){let t=Buffer.from(e,"utf8"),r=Buffer.alloc(5+t.length);return r[0]=4,r.writeUInt32LE(t.length,1),t.copy(r,5),r}if(Array.isArray(e)){let t=[],r=Buffer.alloc(5);r[0]=5,r.writeUInt32LE(e.length,1),t.push(r);for(let s of e)t.push(this.encodeValue(s));return Buffer.concat(t)}if(typeof e=="object"){if(e instanceof Date){let i=Buffer.alloc(9);return i[0]=7,i.writeBigInt64LE(BigInt(e.getTime()),1),i}let t=Object.keys(e),r=[],s=Buffer.alloc(5);s[0]=6,s.writeUInt32LE(t.length,1),r.push(s);for(let i of t){let o=Buffer.from(i,"utf8"),n=Buffer.alloc(2);n.writeUInt16LE(o.length,0),r.push(n),r.push(o),r.push(this.encodeValue(e[i]))}return Buffer.concat(r)}return this.encodeValue(String(e))}decodeValue(e){if(e.length===0)return null;let t=e[0];switch(t){case 0:return null;case 1:return e[1]===1;case 2:return e.readInt32LE(1);case 3:return e.readDoubleLE(1);case 4:{let r=e.readUInt32LE(1);return e.toString("utf8",5,5+r)}case 5:{let r=e.readUInt32LE(1),s=new Array(r),i=5;for(let o=0;o<r;o++){let{value:n,bytesRead:a}=this.decodeValueWithSize(e,i);s[o]=n,i+=a}return s}case 6:{let r=e.readUInt32LE(1),s={},i=5;for(let o=0;o<r;o++){let n=e.readUInt16LE(i);i+=2;let a=e.toString("utf8",i,i+n);i+=n;let{value:c,bytesRead:l}=this.decodeValueWithSize(e,i);s[a]=c,i+=l}return s}case 7:return new Date(Number(e.readBigInt64LE(1)));default:return console.warn(`Unknown type byte: ${t}`),null}}decodeValueWithSize(e,t=0){if(t>=e.length)return{value:null,bytesRead:0};let r=e[t];switch(r){case 0:return{value:null,bytesRead:1};case 1:return{value:e[t+1]===1,bytesRead:2};case 2:return{value:e.readInt32LE(t+1),bytesRead:5};case 3:return{value:e.readDoubleLE(t+1),bytesRead:9};case 4:{let s=e.readUInt32LE(t+1);return{value:e.toString("utf8",t+5,t+5+s),bytesRead:5+s}}case 5:{let s=e.readUInt32LE(t+1),i=new Array(s),o=t+5;for(let n=0;n<s;n++){let a=this.decodeValueWithSize(e,o);i[n]=a.value,o+=a.bytesRead}return{value:i,bytesRead:o-t}}case 6:{let s=e.readUInt32LE(t+1),i={},o=t+5;for(let n=0;n<s;n++){let a=e.readUInt16LE(o);o+=2;let c=e.toString("utf8",o,o+a);o+=a;let l=this.decodeValueWithSize(e,o);i[c]=l.value,o+=l.bytesRead}return{value:i,bytesRead:o-t}}case 7:return{value:new Date(Number(e.readBigInt64LE(t+1))),bytesRead:9};default:return console.warn(`Unknown type byte: ${r} at offset ${t}`),{value:null,bytesRead:1}}}};import{writeFile as yi,rename as vi,unlink as wi}from"fs/promises";async function Yt(e,t,r){let s=new Te,o=new Re().toBinaryBuffer(t);if(!o){console.log("Buffer is empty, skipping...");return}if(r)try{let l=s.generateKey(r,"salt"),u=o.toString("binary"),f=s.generateIV(),h=s.encrypt(u,l,f);o=s.serialize(h)}catch(l){console.error("Encryption failed:",l)}let n=Date.now(),a=Math.random().toString(36).substring(7),c=`${e}.tmp.${n}.${a}`;try{await yi(c,o),await vi(c,e)}catch(l){try{await wi(c)}catch{}throw l}}var Zt=class{cacheLimit;tableAccessTimes=new Map;constructor(e={}){this.cacheLimit=e.cacheLimit??20}trackTableAccess(e){this.tableAccessTimes.set(e,L())}findTablesForEviction(e){if(e<=this.cacheLimit)return[];let t=e-this.cacheLimit,r=Array.from(this.tableAccessTimes.entries()).sort((s,i)=>s[1]-i[1]).slice(0,t).map(([s])=>s);for(let s of r)this.tableAccessTimes.delete(s);return r}removeTable(e){this.tableAccessTimes.delete(e)}findExpiredItems(e){let t=L(),r=[];for(let[s,i]of e.entries())i.x&&i.x<t&&r.push([s,i]);return r}clear(){this.tableAccessTimes.clear()}};var Qt=class{async query(e,t,r=50){let s=new Map;for(let[i,o]of e.entries())if((!t||(typeof t=="function"?t(o.value):this.evaluateFilter(o.value,t)))&&(s.set(i,o.value),r&&s.size>=r))break;return Array.from(s.values())}evaluateCondition(e,t){if(!t||typeof t!="object"||!t.operator)return e===t;let{operator:r,value:s}=t;switch(r){case"eq":return e===s;case"neq":return e!==s;case"gt":return e>s;case"gte":return e>=s;case"lt":return e<s;case"lte":return e<=s;case"in":return Array.isArray(s)&&s.includes(e);case"nin":return Array.isArray(s)&&!s.includes(e);case"like":return typeof e=="string"&&typeof s=="string"&&e.toLowerCase().includes(s.toLowerCase());case"between":return Array.isArray(s)&&s.length===2&&e>=s[0]&&e<=s[1];case"regex":try{let i=new RegExp(s);return typeof e=="string"&&i.test(e)}catch(i){return console.error("Invalid regex pattern:",i),!1}case"contains":return Array.isArray(e)&&e.includes(s);case"containsAll":return Array.isArray(e)&&Array.isArray(s)&&s.every(i=>e.includes(i));case"containsAny":return Array.isArray(e)&&Array.isArray(s)&&s.some(i=>e.includes(i));case"size":return Array.isArray(e)&&e.length===s;default:return!1}}evaluateFilter(e,t){if(e==null)return!1;if("$or"in t)return t.$or.some(r=>this.evaluateFilter(e,r));for(let[r,s]of Object.entries(t))if(!r.startsWith("$"))if(r.includes(".")){let i=r.split("."),o=e;for(let n of i)if(o=o?.[n],o==null)return!1;if(!this.evaluateCondition(o,s))return!1}else if(s&&typeof s=="object"&&!("operator"in s)){let i=e[r];if(i==null||!this.evaluateFilter(i,s))return!1}else{let i=e[r];if(!this.evaluateCondition(i,s))return!1}return!0}};import{existsSync as er,mkdirSync as bi}from"fs";import{readFile as Ei,writeFile as Ci}from"fs/promises";import{join as ct}from"path";import{EventEmitter as Si}from"events";var at=class{emitter;targets={};options;constructor(e){this.emitter=new Si,e?.maxListeners===0?this.emitter.setMaxListeners(0):this.emitter.setMaxListeners(e?.maxListeners||10),this.options={errorHandler:e?.errorHandler||(t=>console.error(t)),isSilent:e?.isSilent||!1}}addTarget(e){return(Array.isArray(e)?e:[e]).map(s=>this.targets[s.name]?(this.options.isSilent||console.error(`Target with name '${s.name}' already exists.`),!1):(this.targets[s.name]={name:s.name,url:s.url,headers:s.headers||{},events:s.events||[]},!0)).every(s=>s===!0)}updateTarget(e,t){if(!this.targets[e])return console.error(`Target with name '${e}' does not exist.`),!1;let r=this.targets[e];return t.url!==void 0&&(r.url=t.url),t.headers&&(r.headers={...r.headers,...t.headers}),t.events&&(r.events=t.events),!0}removeTarget(e){return this.targets[e]?(delete this.targets[e],!0):(console.error(`Target with name '${e}' does not exist.`),!1)}addEventToTarget(e,t){if(!this.targets[e])return console.error(`Target with name '${e}' does not exist.`),!1;let r=Array.isArray(t)?t:[t],s=this.targets[e];return r.forEach(i=>{s.events.includes(i)||s.events.push(i)}),!0}on(e,t){return this.emitter.on(e,t),this}off(e,t){return this.emitter.off(e,t),this}once(e,t){return this.emitter.once(e,t),this}async emit(e,t){let r={success:!0,errors:[]},s=(n,a,c)=>({target:n,event:a,error:c}),i=Object.values(this.targets).filter(n=>n.events.includes(e)||n.events.includes("*"));i.filter(n=>!n.url).forEach(n=>{try{this.emitter.emit(e,t)}catch(a){let c=a instanceof Error?a:new Error(String(a));r.errors.push({target:n.name,event:e,error:c}),this.options.errorHandler(c,e,t),r.success=!1}});let o=i.filter(n=>n.url);if(o.length>0){let n=o.map(async a=>{try{let c=await fetch(a.url,{method:"POST",headers:{"Content-Type":"application/json",...a.headers},body:JSON.stringify({eventName:e,data:t})});if(!c.ok){let l=`HTTP error! Status: ${c.status}: ${c.statusText}`,u=new Error(l);r.errors.push(s(a.name,e,u)),this.options.errorHandler(u,e,t),r.success=!1}}catch(c){let l=c instanceof Error?c:new Error(String(c));r.errors.push(s(a.name,e,l)),this.options.errorHandler(l,e,t),r.success=!1}});await Promise.allSettled(n)}return r}async handleIncomingEvent(e){try{let{eventName:t,data:r}=typeof e=="string"?JSON.parse(e):e;process.nextTick(()=>{try{this.emitter.emit(t,r)}catch(s){this.options.errorHandler(s instanceof Error?s:new Error(String(s)),t,r)}})}catch(t){throw this.options.errorHandler(t instanceof Error?t:new Error(String(t)),"parse_event"),t}}createMiddleware(){return async(e,t,r)=>{if(e.method!=="POST"){r&&r();return}if(e.body)try{await this.handleIncomingEvent(e.body),t.statusCode=202,t.end()}catch(s){t.statusCode=400,t.end(JSON.stringify({error:"Invalid event format"})),r&&r(s)}else{let s="";e.on("data",i=>s+=i.toString()),e.on("end",async()=>{try{await this.handleIncomingEvent(s),t.statusCode=202,t.end()}catch(i){t.statusCode=400,t.end(JSON.stringify({error:"Invalid event format"})),r&&r(i)}})}}}};var tr=class{databaseDirectory;walFile;activeTable=null;data=new Map;writeBuffer=[];maxWriteOpsBeforeFlush=process.env.MAX_WRITE_OPS_BEFORE_FLUSH?Number.parseInt(process.env.MAX_WRITE_OPS_BEFORE_FLUSH,10):se().db.maxWriteOpsBeforeFlush;encryptionKey;cache;encryption;persistence;query;wal;mikroEvent;constructor(e,t){let{databaseDirectory:r,walFileName:s,walInterval:i}=e;this.databaseDirectory=r,this.walFile=ct(this.databaseDirectory,s),this.encryptionKey=e.encryptionKey?e.encryptionKey:null,er(this.databaseDirectory)||bi(this.databaseDirectory),this.cache=new Zt,this.encryption=new Te,this.persistence=new Re,this.query=new Qt,this.wal=new Xt(this.walFile,i),this.mikroEvent=new at,this.setupEvents(t)}async start(){await this.applyWALEntries()}setupEvents(e){e?.targets?.forEach(t=>{this.mikroEvent.addTarget({name:t.name,url:t.url,headers:t.headers,events:t.events})}),e?.listeners?.map(t=>this.mikroEvent.on(t.event,t.handler))}async setActiveTable(e){this.activeTable!==e&&(this.hasTable(e)||await this.loadTable(e),await this.applyWALEntries(e),await this.evictTablesIfNeeded(),this.activeTable=e)}async applyWALEntries(e){let t=await this.wal.loadWAL(e);if(t.length===0)return;let r=e?[e]:[...new Set(t.map(s=>s.tableName))];for(let s of r){let i=t.filter(o=>o.tableName===s);e&&!this.hasTable(s)?await this.loadTable(s):this.createTable(s);for(let o of i)o.operation==="W"&&o.data?this.setItem(s,o.key,o.data):o.operation==="D"&&await this.deleteItem(s,o.key)}}async loadTable(e){if(this.hasTable(e))return;let t=ct(this.databaseDirectory,e);if(!er(t)){this.createTable(e);return}let r=await Ei(t),s=r;if(this.encryptionKey&&r.length>0&&r[0]===1)try{let o=this.encryption.deserialize(r),n=this.encryption.generateKey(this.encryptionKey,"salt"),a=this.encryption.decrypt(o,n);s=Buffer.from(a,"binary")}catch(o){console.error(`Failed to decrypt ${e}:`,o)}if(r.length<8){console.warn(`Table file ${e} is too small, recreating...`),this.createTable(e);return}let i=this.persistence.readTableFromBinaryBuffer(s);this.data.set(e,i),this.data.size>this.cache.cacheLimit&&setImmediate(()=>this.evictTablesIfNeeded())}async get(e){let{tableName:t}=e,r=e.key,s=e.options;if(await this.setActiveTable(t),!s)return r?this.getItem(t,r)?.value:[...this.getAll(t)];let i=this.getTable(t),o=await this.query.query(i,s.filter,s.limit);if(s.sort&&(o=o.sort(s.sort)),s.offset!=null||s.limit!=null){let n=s.offset||0,a=s.limit?n+s.limit:void 0;o=o.slice(n,a)}return o}async write(e,t={}){let{concurrencyLimit:r=10,flushImmediately:s=!1}=t,i=Array.isArray(e)?e:[e],o=i.length,n=0;for(;n<o;){let a=i.slice(n,n+r),c=a.map(u=>this.writeItem(u,!1));if((await Promise.all(c)).includes(!1))return!1;n+=a.length,this.writeBuffer.length>=this.maxWriteOpsBeforeFlush&&await this.flushWrites()}return(s||o>=0)&&await this.flush(),!0}async writeItem(e,t=!1){let{tableName:r,key:s,value:i,expectedVersion:o=null,expiration:n=0}=e;await this.setActiveTable(r);let{success:a,newVersion:c}=this.getItemVersion(r,s,o);return a?(await this.wal.appendToWAL(r,"W",s,i,c,n),this.setItem(r,s,{value:i,v:c,t:L(),x:n}),this.addToWriteBuffer(r,s),t&&await this.flush(),!0):!1}async delete(e,t,r=null,s=!1){if(await this.setActiveTable(e),!this.hasTable(e)||!this.hasKey(e,t))return console.log(`Key ${t} not found in table ${e}`),!1;let{success:i,currentVersion:o,expiration:n}=this.getItemVersion(e,t,r);return i?(await this.wal.appendToWAL(e,"D",t,null,o,n),await this.deleteItem(e,t),s&&await this.flush(),!0):!1}getItemVersion(e,t,r){let s=this.getItem(e,t),i=s?s.version:0,o=i+1,n=s&&s.expiration||0,a=!0;return r!==null&&i!==r&&(console.log(`Version mismatch for ${e}:${t}. Expected ${r}, found ${i}`),a=!1),{success:a,currentRecord:s,currentVersion:i,newVersion:o,expiration:n}}createTable(e){this.trackTableAccess(e),this.hasTable(e)||this.data.set(e,new Map)}getTable(e){return this.trackTableAccess(e),this.hasTable(e)?this.data.get(e):new Map}async getTableSize(e){return await this.setActiveTable(e),this.trackTableAccess(e),this.data.get(e)?.size}async deleteTable(e){this.trackTableAccess(e),this.data.delete(e);let t="table.deleted",{success:r,errors:s}=await this.mikroEvent.emit(t,{operation:t,table:e});r||console.error("Error when emitting events:",s)}hasTable(e){return this.trackTableAccess(e),this.data.has(e)}hasKey(e,t){return this.trackTableAccess(e),this.data.get(e)?.has(t)}getItem(e,t){this.trackTableAccess(e);let r=this.data.get(e)?.get(t);if(r){if(r?.x!==0&&Date.now()>r?.x){this.deleteItem(e,t);return}return{value:r.value,version:r.v,timestamp:r.t,expiration:r.x}}}getAll(e){this.trackTableAccess(e);let t=this.data.get(e);return t?Array.from(t):[]}setItem(e,t,r){this.trackTableAccess(e),this.createTable(e),this.data.get(e)?.set(t,r)}async deleteItem(e,t){this.data.get(e)?.delete(t);let r="item.deleted",{success:s,errors:i}=await this.mikroEvent.emit(r,{operation:r,table:e,key:t});s||console.error("Error when emitting events:",i)}addToWriteBuffer(e,t){let r=this.getItem(e,t);this.writeBuffer.push(JSON.stringify({tableName:e,key:t,record:r}))}trackTableAccess(e){this.cache.trackTableAccess(e)}async flush(){await this.flushWAL(),await this.flushWrites()}async flushWAL(){await this.wal.flushWAL()}async flushWrites(){if(this.writeBuffer.length!==0)try{let e=new Map,t=[...this.writeBuffer];for(let s of t){let i=JSON.parse(s);e.has(i.tableName)||e.set(i.tableName,new Map),e.get(i.tableName).set(i.key,i.record);let n="item.written",{success:a,errors:c}=await this.mikroEvent.emit(n,{operation:n,table:i.tableName,key:i.key,record:i.record});a||console.error("Error when emitting events:",c)}let r=Array.from(e.entries()).map(async([s])=>{let i=this.getTable(s),o=ct(this.databaseDirectory,s);await Yt(o,i,this.encryptionKey)});await Promise.all(r),this.writeBuffer=this.writeBuffer.slice(t.length)}catch(e){console.error(`Failed to flush writes: ${e.message}`)}}async flushTableToDisk(e){await this.setActiveTable(e);let t=this.getTable(e);if(t.size!==0){for(let[r,s]of t.entries())this.addToWriteBuffer(e,r);await this.flushWrites()}}async evictTablesIfNeeded(){let e=this.cache.findTablesForEviction(this.data.size);for(let t of e)await this.flushTableToDisk(t),this.data.delete(t)}async cleanupExpiredItems(){for(let[e,t]of this.data.entries()){let r=this.cache.findExpiredItems(t);for(let[s,i]of r){await this.wal.appendToWAL(e,"D",s,null,i.v,i.x),t.delete(s);let o="item.expired",{success:n,errors:a}=await this.mikroEvent.emit(o,{operation:o,table:e,key:s,record:i});n||console.error("Error when emitting events:",a)}}}async dump(e){e&&await this.setActiveTable(e);let t=this.getAll(this.activeTable);await Ci(`${this.databaseDirectory}/${this.activeTable}_dump.json`,JSON.stringify(t),"utf8")}getWAL(){return this.wal}getPersistence(){return this.persistence}};import{join as xi}from"path";var me=class{table;checkpoint;constructor(e){let t=se(),r=e?.databaseDirectory||t.db.databaseDirectory,s=e?.walFileName||t.db.walFileName,i=e?.walInterval||t.db.walInterval,o=e?.encryptionKey||t.db.encryptionKey,n=e?.maxWriteOpsBeforeFlush||t.db.maxWriteOpsBeforeFlush,a=e?.events||{};e?.debug&&(process.env.DEBUG="true"),e?.maxWriteOpsBeforeFlush&&(process.env.MAX_WRITE_OPS_BEFORE_FLUSH=n.toString()),this.table=new tr({databaseDirectory:r,walFileName:s,walInterval:i,encryptionKey:o},a);let c=this.table.getWAL();this.table.getWAL().setCheckpointCallback(()=>this.checkpoint.checkpoint(!0)),this.checkpoint=new zt({table:this.table,wal:c,walFile:xi(r,s),checkpointIntervalMs:i})}async start(){await this.table.start(),await this.checkpoint.start()}async get(e){return await this.table.get(e)}async getTableSize(e){return await this.table.getTableSize(e)}async write(e,t){return await this.table.write(e,t)}async delete(e){let{tableName:t,key:r}=e,s=e?.expectedVersion||null;return await this.table.delete(t,r,s)}async deleteTable(e){return await this.table.deleteTable(e)}async close(){this.checkpoint&&this.checkpoint.stop(),this.table?.getWAL()&&this.table.getWAL().stop();try{await this.flush()}catch(e){console.error("Error flushing during close:",e)}}async flush(){await this.table.flush()}async flushWAL(){await this.table.flushWAL()}async dump(e){await this.table.dump(e)}async cleanupExpiredItems(){await this.table.cleanupExpiredItems()}};var rr=class{requests=new Map;limit;windowMs;constructor(e=100,t=60){this.limit=e,this.windowMs=t*1e3,setInterval(()=>this.cleanup(),this.windowMs)}getLimit(){return this.limit}isAllowed(e){let t=Date.now(),r=e||"unknown",s=this.requests.get(r);return(!s||s.resetTime<t)&&(s={count:0,resetTime:t+this.windowMs},this.requests.set(r,s)),s.count++,s.count<=this.limit}getRemainingRequests(e){let t=Date.now(),r=e||"unknown",s=this.requests.get(r);return!s||s.resetTime<t?this.limit:Math.max(0,this.limit-s.count)}getResetTime(e){let t=Date.now(),r=e||"unknown",s=this.requests.get(r);return!s||s.resetTime<t?Math.floor((t+this.windowMs)/1e3):Math.floor(s.resetTime/1e3)}cleanup(){let e=Date.now();for(let[t,r]of this.requests.entries())r.resetTime<e&&this.requests.delete(t)}};import{URL as Ii}from"node:url";var sr=class{routes=[];globalMiddlewares=[];pathPatterns=new Map;use(e){return this.globalMiddlewares.push(e),this}get(e,...t){let r=t.pop();return this.register("GET",e,r,t)}post(e,...t){let r=t.pop();return this.register("POST",e,r,t)}put(e,...t){let r=t.pop();return this.register("PUT",e,r,t)}delete(e,...t){let r=t.pop();return this.register("DELETE",e,r,t)}patch(e,...t){let r=t.pop();return this.register("PATCH",e,r,t)}any(e,...t){let r=t.pop(),s=t;return this.register("GET",e,r,s),this.register("POST",e,r,s),this.register("PUT",e,r,s),this.register("DELETE",e,r,s),this.register("PATCH",e,r,s),this.register("OPTIONS",e,r,s),this}options(e,...t){let r=t.pop();return this.register("OPTIONS",e,r,t)}match(e,t){for(let r of this.routes){if(r.method!==e)continue;let s=this.pathPatterns.get(r.path);if(!s)continue;let i=s.pattern.exec(t);if(!i)continue;let o={};return s.paramNames.forEach((n,a)=>{o[n]=i[a+1]||""}),{route:r,params:o}}return null}async handle(e,t){let r=e.method||"GET",s=new Ii(e.url||"/",`http://${e.headers.host}`),i=s.pathname,o=this.match(r,i);if(!o)return null;let{route:n,params:a}=o,c={};s.searchParams.forEach((f,h)=>{c[h]=f});let l={req:e,res:t,params:a,query:c,body:e.body||{},headers:e.headers,path:i,state:{},raw:()=>t,binary:(f,h="application/octet-stream",y=200)=>({statusCode:y,body:f,headers:{"Content-Type":h,"Content-Length":f.length.toString()},isRaw:!0}),text:(f,h=200)=>({statusCode:h,body:f,headers:{"Content-Type":"text/plain"}}),form:(f,h=200)=>({statusCode:h,body:f,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),json:(f,h=200)=>({statusCode:h,body:f,headers:{"Content-Type":"application/json"}}),html:(f,h=200)=>({statusCode:h,body:f,headers:{"Content-Type":"text/html"}}),redirect:(f,h=302)=>({statusCode:h,body:null,headers:{Location:f}}),status:function(f){return{raw:()=>t,binary:(h,y="application/octet-stream")=>({statusCode:f,body:h,headers:{"Content-Type":y,"Content-Length":h.length.toString()},isRaw:!0}),text:h=>({statusCode:f,body:h,headers:{"Content-Type":"text/plain"}}),json:h=>({statusCode:f,body:h,headers:{"Content-Type":"application/json"}}),html:h=>({statusCode:f,body:h,headers:{"Content-Type":"text/html"}}),form:h=>({statusCode:f,body:h,headers:{"Content-Type":"application/x-www-form-urlencoded"}}),redirect:(h,y=302)=>({statusCode:y,body:null,headers:{Location:h}}),status:h=>this.status(h)}}},u=[...this.globalMiddlewares,...n.middlewares];return this.executeMiddlewareChain(l,u,n.handler)}register(e,t,r,s=[]){return this.routes.push({method:e,path:t,handler:r,middlewares:s}),this.pathPatterns.set(t,this.createPathPattern(t)),this}createPathPattern(e){let t=[],r=e.replace(/\/:[^/]+/g,s=>{let i=s.slice(2);return t.push(i),"/([^/]+)"});return r.endsWith("/*")?(r=`${r.slice(0,-2)}(?:/(.*))?`,t.push("wildcard")):r=r.replace(/\/$/,"/?"),{pattern:new RegExp(`^${r}$`),paramNames:t}}async executeMiddlewareChain(e,t,r){let s=0,i=async()=>{if(s<t.length){let o=t[s++];return o(e,i)}return r(e)};return i()}};var Pe=()=>({port:Number(process.env.PORT)||3e3,host:process.env.HOST||"0.0.0.0",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",debug:Ai(process.env.DEBUG)||!1,rateLimit:{enabled:!0,requestsPerMinute:100},allowedDomains:["*"]});function Ai(e){return e==="true"||e===!0}var M=Pe(),ir=e=>({configFilePath:"mikroserve.config.json",args:process.argv,options:[{flag:"--port",path:"port",defaultValue:M.port},{flag:"--host",path:"host",defaultValue:M.host},{flag:"--https",path:"useHttps",defaultValue:M.useHttps,isFlag:!0},{flag:"--http2",path:"useHttp2",defaultValue:M.useHttp2,isFlag:!0},{flag:"--cert",path:"sslCert",defaultValue:M.sslCert},{flag:"--key",path:"sslKey",defaultValue:M.sslKey},{flag:"--ca",path:"sslCa",defaultValue:M.sslCa},{flag:"--ratelimit",path:"rateLimit.enabled",defaultValue:M.rateLimit.enabled,isFlag:!0},{flag:"--rps",path:"rateLimit.requestsPerMinute",defaultValue:M.rateLimit.requestsPerMinute},{flag:"--allowed",path:"allowedDomains",defaultValue:M.allowedDomains,parser:J.array},{flag:"--debug",path:"debug",defaultValue:M.debug,isFlag:!0}],config:e});import{readFileSync as ie}from"node:fs";import lt from"node:http";import ki from"node:http2";import Ti from"node:https";var ut=class{config;rateLimiter;router;constructor(e){let t=new N(ir(e||{})).get();t.debug&&console.log("Using configuration:",t),this.config=t,this.router=new sr;let r=t.rateLimit.requestsPerMinute||Pe().rateLimit.requestsPerMinute;this.rateLimiter=new rr(r,60),t.rateLimit.enabled===!0&&this.use(this.rateLimitMiddleware.bind(this))}use(e){return this.router.use(e),this}get(e,...t){return this.router.get(e,...t),this}post(e,...t){return this.router.post(e,...t),this}put(e,...t){return this.router.put(e,...t),this}delete(e,...t){return this.router.delete(e,...t),this}patch(e,...t){return this.router.patch(e,...t),this}any(e,...t){return this.router.any(e,...t),this}options(e,...t){return this.router.options(e,...t),this}start(){let e=this.createServer(),{port:t,host:r}=this.config;return this.setupGracefulShutdown(e),e.listen(t,r,()=>{let s=e.address(),i=this.config.useHttps||this.config.useHttp2?"https":"http";console.log(`MikroServe running at ${i}://${s.address!=="::"?s.address:"localhost"}:${s.port}`)}),e}createServer(){let e=this.requestHandler.bind(this);if(this.config.useHttp2){if(!this.config.sslCert||!this.config.sslKey)throw new Error("SSL certificate and key paths are required when useHttp2 is true");try{let t={key:ie(this.config.sslKey),cert:ie(this.config.sslCert),...this.config.sslCa?{ca:ie(this.config.sslCa)}:{}};return ki.createSecureServer(t,e)}catch(t){throw t.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${t.message}`):t}}else if(this.config.useHttps){if(!this.config.sslCert||!this.config.sslKey)throw new Error("SSL certificate and key paths are required when useHttps is true");try{let t={key:ie(this.config.sslKey),cert:ie(this.config.sslCert),...this.config.sslCa?{ca:ie(this.config.sslCa)}:{}};return Ti.createServer(t,e)}catch(t){throw t.message.includes("key values mismatch")?new Error(`SSL certificate and key do not match: ${t.message}`):t}}return lt.createServer(e)}async rateLimitMiddleware(e,t){let r=e.req.socket.remoteAddress||"unknown";return e.res.setHeader("X-RateLimit-Limit",this.rateLimiter.getLimit().toString()),e.res.setHeader("X-RateLimit-Remaining",this.rateLimiter.getRemainingRequests(r).toString()),e.res.setHeader("X-RateLimit-Reset",this.rateLimiter.getResetTime(r).toString()),this.rateLimiter.isAllowed(r)?t():{statusCode:429,body:{error:"Too Many Requests",message:"Rate limit exceeded, please try again later"},headers:{"Content-Type":"application/json"}}}async requestHandler(e,t){let r=Date.now(),s=e.method||"UNKNOWN",i=e.url||"/unknown",o=this.config.debug;try{if(this.setCorsHeaders(t,e),this.setSecurityHeaders(t,this.config.useHttps),o&&console.log(`${s} ${i}`),e.method==="OPTIONS"){if(t instanceof lt.ServerResponse)t.statusCode=204,t.end();else{let a=t;a.writeHead(204),a.end()}return}try{e.body=await this.parseBody(e)}catch(a){return o&&console.error("Body parsing error:",a.message),this.respond(t,{statusCode:400,body:{error:"Bad Request",message:a.message}})}let n=await this.router.handle(e,t);return n?n._handled?void 0:this.respond(t,n):this.respond(t,{statusCode:404,body:{error:"Not Found",message:"The requested endpoint does not exist"}})}catch(n){return console.error("Server error:",n),this.respond(t,{statusCode:500,body:{error:"Internal Server Error",message:o?n.message:"An unexpected error occurred"}})}finally{o&&this.logDuration(r,s,i)}}logDuration(e,t,r){let s=Date.now()-e;console.log(`${t} ${r} completed in ${s}ms`)}async parseBody(e){return new Promise((t,r)=>{let s=[],i=0,o=1024*1024,n=!1,a=this.config.debug,c=e.headers["content-type"]||"";a&&console.log("Content-Type:",c),e.on("data",l=>{if(i+=l.length,a&&console.log(`Received chunk: ${l.length} bytes, total size: ${i}`),i>o&&!n){n=!0,a&&console.log(`Body size exceeded limit: ${i} > ${o}`),r(new Error("Request body too large"));return}n||s.push(l)}),e.on("end",()=>{if(!n){a&&console.log(`Request body complete: ${i} bytes`);try{if(s.length>0){let l=Buffer.concat(s).toString("utf8");if(c.includes("application/json"))try{t(JSON.parse(l))}catch(u){r(new Error(`Invalid JSON in request body: ${u.message}`))}else if(c.includes("application/x-www-form-urlencoded")){let u={};new URLSearchParams(l).forEach((f,h)=>{u[h]=f}),t(u)}else t(l)}else t({})}catch(l){r(new Error(`Invalid request body: ${l}`))}}}),e.on("error",l=>{n||r(new Error(`Error reading request body: ${l.message}`))})})}setCorsHeaders(e,t){let r=t.headers.origin,{allowedDomains:s=["*"]}=this.config;!r||s.length===0||s.includes("*")?e.setHeader("Access-Control-Allow-Origin","*"):s.includes(r)&&(e.setHeader("Access-Control-Allow-Origin",r),e.setHeader("Vary","Origin")),e.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),e.setHeader("Access-Control-Max-Age","86400")}setSecurityHeaders(e,t=!1){let 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((t||this.config.useHttp2)&&(r["Strict-Transport-Security"]="max-age=31536000; includeSubDomains"),e instanceof lt.ServerResponse)Object.entries(r).forEach(([s,i])=>{e.setHeader(s,i)});else{let s=e;Object.entries(r).forEach(([i,o])=>{s.setHeader(i,o)})}}respond(e,t){let r={...t.headers||{}};(i=>typeof i.writeHead=="function"&&typeof i.end=="function")(e)?(e.writeHead(t.statusCode,r),t.body===null||t.body===void 0?e.end():t.isRaw||typeof t.body=="string"?e.end(t.body):e.end(JSON.stringify(t.body))):(console.warn("Unexpected response object type without writeHead/end methods"),e.writeHead?.(t.statusCode,r),t.body===null||t.body===void 0?e.end?.():t.isRaw||typeof t.body=="string"?e.end?.(t.body):e.end?.(JSON.stringify(t.body)))}setupGracefulShutdown(e){let t=r=>{console.log("Shutting down MikroServe server..."),r&&console.error("Error:",r),e.close(()=>{console.log("Server closed successfully"),setImmediate(()=>process.exit(r?1:0))})};process.on("SIGINT",()=>t()),process.on("SIGTERM",()=>t()),process.on("uncaughtException",t),process.on("unhandledRejection",t)}};async function or(e){let t=new me({...e.db,events:e?.events});await t.start();let r=new ut(e.server);return r.get("/table",async s=>{let i=s.req.body;if(!i.tableName)return s.json({statusCode:400,body:"tableName is required"});let o=await t.getTableSize(i.tableName);return o||s.json({statusCode:404,body:null}),s.json({statusCode:200,body:o})}),r.post("/get",async s=>{let i=s.req.body;if(!i.tableName)return s.json({statusCode:400,body:"tableName is required"});let o={tableName:i.tableName,key:i.key},n=_t(i?.options);n&&(o.options=n);let a=await t.get(o);return a||s.json({statusCode:404,body:null}),s.json({statusCode:200,body:a})}),r.post("/write",async s=>{let i=s.req.body;if(!i.tableName||i.value===void 0)return s.json({statusCode:400,body:"tableName and value are required"});let o={tableName:i.tableName,key:i.key,value:i.value,expectedVersion:i.expectedVersion,expiration:i.expiration},n={concurrencyLimit:i.concurrencyLimit,flushImmediately:i.flushImmediately},a=await t.write(o,n);return s.json({statusCode:200,body:a})}),r.delete("/delete",async s=>{let i=s.params;if(!i.tableName||!i.key)return s.json({statusCode:400,body:"tableName and key are required"});let o={tableName:i.tableName,key:i.key},n=await t.delete(o);return s.json({statusCode:200,body:n})}),r.start(),r}async function Ri(){let t=process.argv[1]?.includes("node_modules/.bin/mikrodb"),r=(process.argv[2]||"")==="--force";if(t||r){console.log("\u{1F5C2}\uFE0F Welcome to MikroDB! \u2728");try{let s=se(),i=new N({configFilePath:"mikrodb.config.json",args:process.argv,options:[{flag:"--db",path:"db.dbName",defaultValue:s.db.dbName},{flag:"--dir",path:"db.databaseDirectory",defaultValue:s.db.databaseDirectory},{flag:"--wal",path:"db.walFileName",defaultValue:s.db.walFileName},{flag:"--interval",path:"db.walInterval",defaultValue:s.db.walInterval},{flag:"--encryptionKey",path:"db.encryptionKey",defaultValue:s.db.encryptionKey},{flag:"--maxWrites",path:"db.maxWriteOpsBeforeFlush",defaultValue:s.db.maxWriteOpsBeforeFlush},{flag:"--debug",path:"db.debug",isFlag:!0,defaultValue:s.db.debug},{path:"events",defaultValue:s.events},{flag:"--port",path:"server.port",defaultValue:s.server.port},{flag:"--host",path:"server.host",defaultValue:s.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:s.server.useHttps},{flag:"--http2",path:"server.useHttp2",isFlag:!0,defaultValue:s.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:s.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:s.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:s.server.sslCa},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:s.server.debug}]}).get();or(i)}catch(s){console.error(s)}}}Ri();import{join as Wo}from"node:path";import Do from"node:http";import{join as Rt}from"node:path";var dt=(e,t,r)=>(s,i)=>{let o=-1;return n(0);async function n(a){if(a<=o)throw new Error("next() called multiple times");o=a;let c,l=!1,u;if(e[a]?(u=e[a][0][0],s.req.routeIndex=a):u=a===e.length&&i||void 0,u)try{c=await u(s,()=>n(a+1))}catch(f){if(f instanceof Error&&t)s.error=f,c=await t(f,s),l=!0;else throw f}else s.finalized===!1&&r&&(c=await r(s));return c&&(s.finalized===!1||l)&&(s.res=c),s}};var nr=Symbol();var ar=async(e,t=Object.create(null))=>{let{all:r=!1,dot:s=!1}=t,o=(e instanceof je?e.raw.headers:e.headers).get("Content-Type");return o?.startsWith("multipart/form-data")||o?.startsWith("application/x-www-form-urlencoded")?Pi(e,{all:r,dot:s}):{}};async function Pi(e,t){let r=await e.formData();return r?ji(r,t):{}}function ji(e,t){let r=Object.create(null);return e.forEach((s,i)=>{t.all||i.endsWith("[]")?Li(r,i,s):r[i]=s}),t.dot&&Object.entries(r).forEach(([s,i])=>{s.includes(".")&&($i(r,s,i),delete r[s])}),r}var Li=(e,t,r)=>{e[t]!==void 0?Array.isArray(e[t])?e[t].push(r):e[t]=[e[t],r]:t.endsWith("[]")?e[t]=[r]:e[t]=r},$i=(e,t,r)=>{let s=e,i=t.split(".");i.forEach((o,n)=>{n===i.length-1?s[o]=r:((!s[o]||typeof s[o]!="object"||Array.isArray(s[o])||s[o]instanceof File)&&(s[o]=Object.create(null)),s=s[o])})};var ft=e=>{let t=e.split("/");return t[0]===""&&t.shift(),t},cr=e=>{let{groups:t,path:r}=Mi(e),s=ft(r);return Oi(s,t)},Mi=e=>{let t=[];return e=e.replace(/\{[^}]+\}/g,(r,s)=>{let i=`@${s}`;return t.push([i,r]),i}),{groups:t,path:e}},Oi=(e,t)=>{for(let r=t.length-1;r>=0;r--){let[s]=t[r];for(let i=e.length-1;i>=0;i--)if(e[i].includes(s)){e[i]=e[i].replace(s,t[r][1]);break}}return e},Le={},lr=(e,t)=>{if(e==="*")return"*";let r=e.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);if(r){let s=`${e}#${t}`;return Le[s]||(r[2]?Le[s]=t&&t[0]!==":"&&t[0]!=="*"?[s,r[1],new RegExp(`^${r[2]}(?=/${t})`)]:[e,r[1],new RegExp(`^${r[2]}$`)]:Le[s]=[e,r[1],!0]),Le[s]}return null},$e=(e,t)=>{try{return t(e)}catch{return e.replace(/(?:%[0-9A-Fa-f]{2})+/g,r=>{try{return t(r)}catch{return r}})}},Di=e=>$e(e,decodeURI),pt=e=>{let t=e.url,r=t.indexOf("/",t.indexOf(":")+4),s=r;for(;s<t.length;s++){let i=t.charCodeAt(s);if(i===37){let o=t.indexOf("?",s),n=t.slice(r,o===-1?void 0:o);return Di(n.includes("%25")?n.replace(/%25/g,"%2525"):n)}else if(i===63)break}return t.slice(r,s)};var ur=e=>{let t=pt(e);return t.length>1&&t.at(-1)==="/"?t.slice(0,-1):t},Y=(e,t,...r)=>(r.length&&(t=Y(t,...r)),`${e?.[0]==="/"?"":"/"}${e}${t==="/"?"":`${e?.at(-1)==="/"?"":"/"}${t?.[0]==="/"?t.slice(1):t}`}`),Me=e=>{if(e.charCodeAt(e.length-1)!==63||!e.includes(":"))return null;let t=e.split("/"),r=[],s="";return t.forEach(i=>{if(i!==""&&!/\:/.test(i))s+="/"+i;else if(/\:/.test(i))if(/\?/.test(i)){r.length===0&&s===""?r.push("/"):r.push(s);let o=i.replace("?","");s+="/"+o,r.push(s)}else s+="/"+i}),r.filter((i,o,n)=>n.indexOf(i)===o)},ht=e=>/[%+]/.test(e)?(e.indexOf("+")!==-1&&(e=e.replace(/\+/g," ")),e.indexOf("%")!==-1?$e(e,mt):e):e,dr=(e,t,r)=>{let s;if(!r&&t&&!/[%+]/.test(t)){let n=e.indexOf("?",8);if(n===-1)return;for(e.startsWith(t,n+1)||(n=e.indexOf(`&${t}`,n+1));n!==-1;){let a=e.charCodeAt(n+t.length+1);if(a===61){let c=n+t.length+2,l=e.indexOf("&",c);return ht(e.slice(c,l===-1?void 0:l))}else if(a==38||isNaN(a))return"";n=e.indexOf(`&${t}`,n+1)}if(s=/[%+]/.test(e),!s)return}let i={};s??=/[%+]/.test(e);let o=e.indexOf("?",8);for(;o!==-1;){let n=e.indexOf("&",o+1),a=e.indexOf("=",o);a>n&&n!==-1&&(a=-1);let c=e.slice(o+1,a===-1?n===-1?void 0:n:a);if(s&&(c=ht(c)),o=n,c==="")continue;let l;a===-1?l="":(l=e.slice(a+1,n===-1?void 0:n),s&&(l=ht(l))),r?(i[c]&&Array.isArray(i[c])||(i[c]=[]),i[c].push(l)):i[c]??=l}return t?i[t]:i},hr=dr,fr=(e,t)=>dr(e,t,!0),mt=decodeURIComponent;var pr=e=>$e(e,mt),je=class{raw;#t;#e;routeIndex=0;path;bodyCache={};constructor(e,t="/",r=[[]]){this.raw=e,this.path=t,this.#e=r,this.#t={}}param(e){return e?this.#r(e):this.#o()}#r(e){let t=this.#e[0][this.routeIndex][1][e],r=this.#i(t);return r&&/\%/.test(r)?pr(r):r}#o(){let e={},t=Object.keys(this.#e[0][this.routeIndex][1]);for(let r of t){let s=this.#i(this.#e[0][this.routeIndex][1][r]);s!==void 0&&(e[r]=/\%/.test(s)?pr(s):s)}return e}#i(e){return this.#e[1]?this.#e[1][e]:e}query(e){return hr(this.url,e)}queries(e){return fr(this.url,e)}header(e){if(e)return this.raw.headers.get(e)??void 0;let t={};return this.raw.headers.forEach((r,s)=>{t[s]=r}),t}async parseBody(e){return this.bodyCache.parsedBody??=await ar(this,e)}#s=e=>{let{bodyCache:t,raw:r}=this,s=t[e];if(s)return s;let i=Object.keys(t)[0];return i?t[i].then(o=>(i==="json"&&(o=JSON.stringify(o)),new Response(o)[e]())):t[e]=r[e]()};json(){return this.#s("text").then(e=>JSON.parse(e))}text(){return this.#s("text")}arrayBuffer(){return this.#s("arrayBuffer")}blob(){return this.#s("blob")}formData(){return this.#s("formData")}addValidatedData(e,t){this.#t[e]=t}valid(e){return this.#t[e]}get url(){return this.raw.url}get method(){return this.raw.method}get[nr](){return this.#e}get matchedRoutes(){return this.#e[0].map(([[,e]])=>e)}get routePath(){return this.#e[0].map(([[,e]])=>e)[this.routeIndex].path}};var mr={Stringify:1,BeforeStream:2,Stream:3},Ui=(e,t)=>{let r=new String(e);return r.isEscaped=!0,r.callbacks=t,r};var gt=async(e,t,r,s,i)=>{typeof e=="object"&&!(e instanceof String)&&(e instanceof Promise||(e=e.toString()),e instanceof Promise&&(e=await e));let o=e.callbacks;if(!o?.length)return Promise.resolve(e);i?i[0]+=e:i=[e];let n=Promise.all(o.map(a=>a({phase:t,buffer:i,context:s}))).then(a=>Promise.all(a.filter(Boolean).map(c=>gt(c,t,!1,s,i))).then(()=>i[0]));return r?Ui(await n,o):n};var Bi="text/plain; charset=UTF-8",yt=(e,t)=>({"Content-Type":e,...t}),gr=class{#t;#e;env={};#r;finalized=!1;error;#o;#i;#s;#u;#c;#l;#a;#d;#h;constructor(e,t){this.#t=e,t&&(this.#i=t.executionCtx,this.env=t.env,this.#l=t.notFoundHandler,this.#h=t.path,this.#d=t.matchResult)}get req(){return this.#e??=new je(this.#t,this.#h,this.#d),this.#e}get event(){if(this.#i&&"respondWith"in this.#i)return this.#i;throw Error("This context has no FetchEvent")}get executionCtx(){if(this.#i)return this.#i;throw Error("This context has no ExecutionContext")}get res(){return this.#s||=new Response(null,{headers:this.#a??=new Headers})}set res(e){if(this.#s&&e){e=new Response(e.body,e);for(let[t,r]of this.#s.headers.entries())if(t!=="content-type")if(t==="set-cookie"){let s=this.#s.headers.getSetCookie();e.headers.delete("set-cookie");for(let i of s)e.headers.append("set-cookie",i)}else e.headers.set(t,r)}this.#s=e,this.finalized=!0}render=(...e)=>(this.#c??=t=>this.html(t),this.#c(...e));setLayout=e=>this.#u=e;getLayout=()=>this.#u;setRenderer=e=>{this.#c=e};header=(e,t,r)=>{this.finalized&&(this.#s=new Response(this.#s.body,this.#s));let s=this.#s?this.#s.headers:this.#a??=new Headers;t===void 0?s.delete(e):r?.append?s.append(e,t):s.set(e,t)};status=e=>{this.#o=e};set=(e,t)=>{this.#r??=new Map,this.#r.set(e,t)};get=e=>this.#r?this.#r.get(e):void 0;get var(){return this.#r?Object.fromEntries(this.#r):{}}#n(e,t,r){let s=this.#s?new Headers(this.#s.headers):this.#a??new Headers;if(typeof t=="object"&&"headers"in t){let o=t.headers instanceof Headers?t.headers:new Headers(t.headers);for(let[n,a]of o)n.toLowerCase()==="set-cookie"?s.append(n,a):s.set(n,a)}if(r)for(let[o,n]of Object.entries(r))if(typeof n=="string")s.set(o,n);else{s.delete(o);for(let a of n)s.append(o,a)}let i=typeof t=="number"?t:t?.status??this.#o;return new Response(e,{status:i,headers:s})}newResponse=(...e)=>this.#n(...e);body=(e,t,r)=>this.#n(e,t,r);text=(e,t,r)=>!this.#a&&!this.#o&&!t&&!r&&!this.finalized?new Response(e):this.#n(e,t,yt(Bi,r));json=(e,t,r)=>this.#n(JSON.stringify(e),t,yt("application/json",r));html=(e,t,r)=>{let s=i=>this.#n(i,t,yt("text/html; charset=UTF-8",r));return typeof e=="object"?gt(e,mr.Stringify,!1,{}).then(s):s(e)};redirect=(e,t)=>{let r=String(e);return this.header("Location",/[^\x00-\xFF]/.test(r)?encodeURI(r):r),this.newResponse(null,t??302)};notFound=()=>(this.#l??=()=>new Response,this.#l(this))};var x="ALL",yr="all",vr=["get","post","put","delete","options","patch"],Oe="Can not add a route since the matcher is already built.",De=class extends Error{};var wr="__COMPOSED_HANDLER";var Hi=e=>e.text("404 Not Found",404),Sr=(e,t)=>{if("getResponse"in e){let r=e.getResponse();return t.newResponse(r.body,r)}return console.error(e),t.text("Internal Server Error",500)},br=class Er{get;post;put;delete;options;patch;all;on;use;router;getPath;_basePath="/";#t="/";routes=[];constructor(t={}){[...vr,yr].forEach(o=>{this[o]=(n,...a)=>(typeof n=="string"?this.#t=n:this.#o(o,this.#t,n),a.forEach(c=>{this.#o(o,this.#t,c)}),this)}),this.on=(o,n,...a)=>{for(let c of[n].flat()){this.#t=c;for(let l of[o].flat())a.map(u=>{this.#o(l.toUpperCase(),this.#t,u)})}return this},this.use=(o,...n)=>(typeof o=="string"?this.#t=o:(this.#t="*",n.unshift(o)),n.forEach(a=>{this.#o(x,this.#t,a)}),this);let{strict:s,...i}=t;Object.assign(this,i),this.getPath=s??!0?t.getPath??pt:ur}#e(){let t=new Er({router:this.router,getPath:this.getPath});return t.errorHandler=this.errorHandler,t.#r=this.#r,t.routes=this.routes,t}#r=Hi;errorHandler=Sr;route(t,r){let s=this.basePath(t);return r.routes.map(i=>{let o;r.errorHandler===Sr?o=i.handler:(o=async(n,a)=>(await dt([],r.errorHandler)(n,()=>i.handler(n,a))).res,o[wr]=i.handler),s.#o(i.method,i.path,o)}),this}basePath(t){let r=this.#e();return r._basePath=Y(this._basePath,t),r}onError=t=>(this.errorHandler=t,this);notFound=t=>(this.#r=t,this);mount(t,r,s){let i,o;s&&(typeof s=="function"?o=s:(o=s.optionHandler,s.replaceRequest===!1?i=c=>c:i=s.replaceRequest));let n=o?c=>{let l=o(c);return Array.isArray(l)?l:[l]}:c=>{let l;try{l=c.executionCtx}catch{}return[c.env,l]};i||=(()=>{let c=Y(this._basePath,t),l=c==="/"?0:c.length;return u=>{let f=new URL(u.url);return f.pathname=f.pathname.slice(l)||"/",new Request(f,u)}})();let a=async(c,l)=>{let u=await r(i(c.req.raw),...n(c));if(u)return u;await l()};return this.#o(x,Y(t,"*"),a),this}#o(t,r,s){t=t.toUpperCase(),r=Y(this._basePath,r);let i={basePath:this._basePath,path:r,method:t,handler:s};this.router.add(t,r,[s,i]),this.routes.push(i)}#i(t,r){if(t instanceof Error)return this.errorHandler(t,r);throw t}#s(t,r,s,i){if(i==="HEAD")return(async()=>new Response(null,await this.#s(t,r,s,"GET")))();let o=this.getPath(t,{env:s}),n=this.router.match(i,o),a=new gr(t,{path:o,matchResult:n,env:s,executionCtx:r,notFoundHandler:this.#r});if(n[0].length===1){let l;try{l=n[0][0][0][0](a,async()=>{a.res=await this.#r(a)})}catch(u){return this.#i(u,a)}return l instanceof Promise?l.then(u=>u||(a.finalized?a.res:this.#r(a))).catch(u=>this.#i(u,a)):l??this.#r(a)}let c=dt(n[0],this.errorHandler,this.#r);return(async()=>{try{let l=await c(a);if(!l.finalized)throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");return l.res}catch(l){return this.#i(l,a)}})()}fetch=(t,...r)=>this.#s(t,r[1],r[0],t.method);request=(t,r,s,i)=>t instanceof Request?this.fetch(r?new Request(t,r):t,s,i):(t=t.toString(),this.fetch(new Request(/^https?:\/\//.test(t)?t:`http://localhost${Y("/",t)}`,r),s,i));fire=()=>{addEventListener("fetch",t=>{t.respondWith(this.#s(t.request,t,void 0,t.request.method))})}};var Ue=[];function vt(e,t){let r=this.buildAllMatchers(),s=((i,o)=>{let n=r[i]||r[x],a=n[2][o];if(a)return a;let c=o.match(n[0]);if(!c)return[[],Ue];let l=c.indexOf("",1);return[n[1][l],c]});return this.match=s,s(e,t)}var Be="[^/]+",ge=".*",ye="(?:|/.*)",Z=Symbol(),Fi=new Set(".\\+*[^]$()");function Vi(e,t){return e.length===1?t.length===1?e<t?-1:1:-1:t.length===1||e===ge||e===ye?1:t===ge||t===ye?-1:e===Be?1:t===Be?-1:e.length===t.length?e<t?-1:1:t.length-e.length}var Cr=class wt{#t;#e;#r=Object.create(null);insert(t,r,s,i,o){if(t.length===0){if(this.#t!==void 0)throw Z;if(o)return;this.#t=r;return}let[n,...a]=t,c=n==="*"?a.length===0?["","",ge]:["","",Be]:n==="/*"?["","",ye]:n.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/),l;if(c){let u=c[1],f=c[2]||Be;if(u&&c[2]&&(f===".*"||(f=f.replace(/^\((?!\?:)(?=[^)]+\)$)/,"(?:"),/\((?!\?:)/.test(f))))throw Z;if(l=this.#r[f],!l){if(Object.keys(this.#r).some(h=>h!==ge&&h!==ye))throw Z;if(o)return;l=this.#r[f]=new wt,u!==""&&(l.#e=i.varIndex++)}!o&&u!==""&&s.push([u,l.#e])}else if(l=this.#r[n],!l){if(Object.keys(this.#r).some(u=>u.length>1&&u!==ge&&u!==ye))throw Z;if(o)return;l=this.#r[n]=new wt}l.insert(a,r,s,i,o)}buildRegExpStr(){let r=Object.keys(this.#r).sort(Vi).map(s=>{let i=this.#r[s];return(typeof i.#e=="number"?`(${s})@${i.#e}`:Fi.has(s)?`\\${s}`:s)+i.buildRegExpStr()});return typeof this.#t=="number"&&r.unshift(`#${this.#t}`),r.length===0?"":r.length===1?r[0]:"(?:"+r.join("|")+")"}};var xr=class{#t={varIndex:0};#e=new Cr;insert(e,t,r){let s=[],i=[];for(let n=0;;){let a=!1;if(e=e.replace(/\{[^}]+\}/g,c=>{let l=`@\\${n}`;return i[n]=[l,c],n++,a=!0,l}),!a)break}let o=e.match(/(?::[^\/]+)|(?:\/\*$)|./g)||[];for(let n=i.length-1;n>=0;n--){let[a]=i[n];for(let c=o.length-1;c>=0;c--)if(o[c].indexOf(a)!==-1){o[c]=o[c].replace(a,i[n][1]);break}}return this.#e.insert(o,t,s,this.#t,r),s}buildRegExp(){let e=this.#e.buildRegExpStr();if(e==="")return[/^$/,[],[]];let t=0,r=[],s=[];return e=e.replace(/#(\d+)|@(\d+)|\.\*\$/g,(i,o,n)=>o!==void 0?(r[++t]=Number(o),"$()"):(n!==void 0&&(s[Number(n)]=++t),"")),[new RegExp(`^${e}`),r,s]}};var Ni=[/^$/,[],Object.create(null)],Ir=Object.create(null);function Ar(e){return Ir[e]??=new RegExp(e==="*"?"":`^${e.replace(/\/\*$|([.\\+*[^\]$()])/g,(t,r)=>r?`\\${r}`:"(?:|/.*)")}$`)}function _i(){Ir=Object.create(null)}function Wi(e){let t=new xr,r=[];if(e.length===0)return Ni;let s=e.map(l=>[!/\*|\/:/.test(l[0]),...l]).sort(([l,u],[f,h])=>l?1:f?-1:u.length-h.length),i=Object.create(null);for(let l=0,u=-1,f=s.length;l<f;l++){let[h,y,C]=s[l];h?i[y]=[C.map(([I])=>[I,Object.create(null)]),Ue]:u++;let g;try{g=t.insert(y,u,h)}catch(I){throw I===Z?new De(y):I}h||(r[u]=C.map(([I,T])=>{let H=Object.create(null);for(T-=1;T>=0;T--){let[d,E]=g[T];H[d]=E}return[I,H]}))}let[o,n,a]=t.buildRegExp();for(let l=0,u=r.length;l<u;l++)for(let f=0,h=r[l].length;f<h;f++){let y=r[l][f]?.[1];if(!y)continue;let C=Object.keys(y);for(let g=0,I=C.length;g<I;g++)y[C[g]]=a[y[C[g]]]}let c=[];for(let l in n)c[l]=r[n[l]];return[o,c,i]}function oe(e,t){if(e){for(let r of Object.keys(e).sort((s,i)=>i.length-s.length))if(Ar(r).test(t))return[...e[r]]}}var He=class{name="RegExpRouter";#t;#e;constructor(){this.#t={[x]:Object.create(null)},this.#e={[x]:Object.create(null)}}add(e,t,r){let s=this.#t,i=this.#e;if(!s||!i)throw new Error(Oe);s[e]||[s,i].forEach(a=>{a[e]=Object.create(null),Object.keys(a[x]).forEach(c=>{a[e][c]=[...a[x][c]]})}),t==="/*"&&(t="*");let o=(t.match(/\/:/g)||[]).length;if(/\*$/.test(t)){let a=Ar(t);e===x?Object.keys(s).forEach(c=>{s[c][t]||=oe(s[c],t)||oe(s[x],t)||[]}):s[e][t]||=oe(s[e],t)||oe(s[x],t)||[],Object.keys(s).forEach(c=>{(e===x||e===c)&&Object.keys(s[c]).forEach(l=>{a.test(l)&&s[c][l].push([r,o])})}),Object.keys(i).forEach(c=>{(e===x||e===c)&&Object.keys(i[c]).forEach(l=>a.test(l)&&i[c][l].push([r,o]))});return}let n=Me(t)||[t];for(let a=0,c=n.length;a<c;a++){let l=n[a];Object.keys(i).forEach(u=>{(e===x||e===u)&&(i[u][l]||=[...oe(s[u],l)||oe(s[x],l)||[]],i[u][l].push([r,o-c+a+1]))})}}match=vt;buildAllMatchers(){let e=Object.create(null);return Object.keys(this.#e).concat(Object.keys(this.#t)).forEach(t=>{e[t]||=this.#r(t)}),this.#t=this.#e=void 0,_i(),e}#r(e){let t=[],r=e===x;return[this.#t,this.#e].forEach(s=>{let i=s[e]?Object.keys(s[e]).map(o=>[o,s[e][o]]):[];i.length!==0?(r||=!0,t.push(...i)):e!==x&&t.push(...Object.keys(s[x]).map(o=>[o,s[x][o]]))}),r?Wi(t):null}};var St=class{name="SmartRouter";#t=[];#e=[];constructor(e){this.#t=e.routers}add(e,t,r){if(!this.#e)throw new Error(Oe);this.#e.push([e,t,r])}match(e,t){if(!this.#e)throw new Error("Fatal error");let r=this.#t,s=this.#e,i=r.length,o=0,n;for(;o<i;o++){let a=r[o];try{for(let c=0,l=s.length;c<l;c++)a.add(...s[c]);n=a.match(e,t)}catch(c){if(c instanceof De)continue;throw c}this.match=a.match.bind(a),this.#t=[a],this.#e=void 0;break}if(o===i)throw new Error("Fatal error");return this.name=`SmartRouter + ${this.activeRouter.name}`,n}get activeRouter(){if(this.#e||this.#t.length!==1)throw new Error("No active router has been determined yet.");return this.#t[0]}};var ve=Object.create(null),kr=class Tr{#t;#e;#r;#o=0;#i=ve;constructor(t,r,s){if(this.#e=s||Object.create(null),this.#t=[],t&&r){let i=Object.create(null);i[t]={handler:r,possibleKeys:[],score:0},this.#t=[i]}this.#r=[]}insert(t,r,s){this.#o=++this.#o;let i=this,o=cr(r),n=[];for(let a=0,c=o.length;a<c;a++){let l=o[a],u=o[a+1],f=lr(l,u),h=Array.isArray(f)?f[0]:l;if(h in i.#e){i=i.#e[h],f&&n.push(f[1]);continue}i.#e[h]=new Tr,f&&(i.#r.push(f),n.push(f[1])),i=i.#e[h]}return i.#t.push({[t]:{handler:s,possibleKeys:n.filter((a,c,l)=>l.indexOf(a)===c),score:this.#o}}),i}#s(t,r,s,i){let o=[];for(let n=0,a=t.#t.length;n<a;n++){let c=t.#t[n],l=c[r]||c[x],u={};if(l!==void 0&&(l.params=Object.create(null),o.push(l),s!==ve||i&&i!==ve))for(let f=0,h=l.possibleKeys.length;f<h;f++){let y=l.possibleKeys[f],C=u[l.score];l.params[y]=i?.[y]&&!C?i[y]:s[y]??i?.[y],u[l.score]=!0}}return o}search(t,r){let s=[];this.#i=ve;let o=[this],n=ft(r),a=[];for(let c=0,l=n.length;c<l;c++){let u=n[c],f=c===l-1,h=[];for(let y=0,C=o.length;y<C;y++){let g=o[y],I=g.#e[u];I&&(I.#i=g.#i,f?(I.#e["*"]&&s.push(...this.#s(I.#e["*"],t,g.#i)),s.push(...this.#s(I,t,g.#i))):h.push(I));for(let T=0,H=g.#r.length;T<H;T++){let d=g.#r[T],E=g.#i===ve?{}:{...g.#i};if(d==="*"){let j=g.#e["*"];j&&(s.push(...this.#s(j,t,g.#i)),j.#i=E,h.push(j));continue}let[k,R,D]=d;if(!u&&!(D instanceof RegExp))continue;let P=g.#e[k],$=n.slice(c).join("/");if(D instanceof RegExp){let j=D.exec($);if(j){if(E[R]=j[0],s.push(...this.#s(P,t,g.#i,E)),Object.keys(P.#e).length){P.#i=E;let q=j[0].match(/\//)?.length??0;(a[q]||=[]).push(P)}continue}}(D===!0||D.test(u))&&(E[R]=u,f?(s.push(...this.#s(P,t,E,g.#i)),P.#e["*"]&&s.push(...this.#s(P.#e["*"],t,E,g.#i))):(P.#i=E,h.push(P)))}}o=h.concat(a.shift()??[])}return s.length>1&&s.sort((c,l)=>c.score-l.score),[s.map(({handler:c,params:l})=>[c,l])]}};var bt=class{name="TrieRouter";#t;constructor(){this.#t=new kr}add(e,t,r){let s=Me(t);if(s){for(let i=0,o=s.length;i<o;i++)this.#t.insert(e,s[i],r);return}this.#t.insert(e,t,r)}match(e,t){return this.#t.search(e,t)}};var Et=class extends br{constructor(e={}){super(e),this.router=e.router??new St({routers:[new He,new bt]})}};var Rr=e=>{let r={...{origin:"*",allowMethods:["GET","HEAD","PUT","POST","DELETE","PATCH"],allowHeaders:[],exposeHeaders:[]},...e},s=(o=>typeof o=="string"?o==="*"?()=>o:n=>o===n?n:null:typeof o=="function"?o:n=>o.includes(n)?n:null)(r.origin),i=(o=>typeof o=="function"?o:Array.isArray(o)?()=>o:()=>[])(r.allowMethods);return async function(n,a){function c(u,f){n.res.headers.set(u,f)}let l=await s(n.req.header("origin")||"",n);if(l&&c("Access-Control-Allow-Origin",l),r.credentials&&c("Access-Control-Allow-Credentials","true"),r.exposeHeaders?.length&&c("Access-Control-Expose-Headers",r.exposeHeaders.join(",")),n.req.method==="OPTIONS"){r.origin!=="*"&&c("Vary","Origin"),r.maxAge!=null&&c("Access-Control-Max-Age",r.maxAge.toString());let u=await i(n.req.header("origin")||"",n);u.length&&c("Access-Control-Allow-Methods",u.join(","));let f=r.allowHeaders;if(!f?.length){let h=n.req.header("Access-Control-Request-Headers");h&&(f=h.split(/\s*,\s*/))}return f?.length&&(c("Access-Control-Allow-Headers",f.join(",")),n.res.headers.append("Vary","Access-Control-Request-Headers")),n.res.headers.delete("Content-Length"),n.res.headers.delete("Content-Type"),new Response(null,{headers:n.res.headers,status:204,statusText:"No Content"})}await a(),r.origin!=="*"&&n.header("Vary","Origin",{append:!0})}};import{createServer as qi}from"http";import{Http2ServerRequest as zi}from"http2";import{Http2ServerRequest as Ct}from"http2";import{Readable as Pr}from"stream";import io from"crypto";var Q=class extends Error{constructor(e,t){super(e,t),this.name="RequestError"}},Gi=e=>e instanceof Q?e:new Q(e.message,{cause:e}),Ki=global.Request,we=class extends Ki{constructor(e,t){typeof e=="object"&&ce in e&&(e=e[ce]()),typeof t?.body?.getReader<"u"&&(t.duplex??="half"),super(e,t)}},Ji=e=>{let t=[],r=e.rawHeaders;for(let s=0;s<r.length;s+=2){let{[s]:i,[s+1]:o}=r;i.charCodeAt(0)!==58&&t.push([i,o])}return new Headers(t)},Lr=Symbol("wrapBodyStream"),Xi=(e,t,r,s,i)=>{let o={method:e,headers:r,signal:i.signal};if(e==="TRACE"){o.method="GET";let n=new we(t,o);return Object.defineProperty(n,"method",{get(){return"TRACE"}}),n}if(!(e==="GET"||e==="HEAD"))if("rawBody"in s&&s.rawBody instanceof Buffer)o.body=new ReadableStream({start(n){n.enqueue(s.rawBody),n.close()}});else if(s[Lr]){let n;o.body=new ReadableStream({async pull(a){try{n||=Pr.toWeb(s).getReader();let{done:c,value:l}=await n.read();c?a.close():a.enqueue(l)}catch(c){a.error(c)}}})}else o.body=Pr.toWeb(s);return new we(t,o)},ce=Symbol("getRequestCache"),Yi=Symbol("requestCache"),Fe=Symbol("incomingKey"),Ve=Symbol("urlKey"),Zi=Symbol("headersKey"),ae=Symbol("abortControllerKey"),Qi=Symbol("getAbortController"),Ne={get method(){return this[Fe].method||"GET"},get url(){return this[Ve]},get headers(){return this[Zi]||=Ji(this[Fe])},[Qi](){return this[ce](),this[ae]},[ce](){return this[ae]||=new AbortController,this[Yi]||=Xi(this.method,this[Ve],this.headers,this[Fe],this[ae])}};["body","bodyUsed","cache","credentials","destination","integrity","mode","redirect","referrer","referrerPolicy","signal","keepalive"].forEach(e=>{Object.defineProperty(Ne,e,{get(){return this[ce]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(Ne,e,{value:function(){return this[ce]()[e]()}})});Object.setPrototypeOf(Ne,we.prototype);var eo=(e,t)=>{let r=Object.create(Ne);r[Fe]=e;let s=e.url||"";if(s[0]!=="/"&&(s.startsWith("http://")||s.startsWith("https://"))){if(e instanceof Ct)throw new Q("Absolute URL for :path is not allowed in HTTP/2");try{let a=new URL(s);r[Ve]=a.href}catch(a){throw new Q("Invalid absolute URL",{cause:a})}return r}let i=(e instanceof Ct?e.authority:e.headers.host)||t;if(!i)throw new Q("Missing host header");let o;if(e instanceof Ct){if(o=e.scheme,!(o==="http"||o==="https"))throw new Q("Unsupported scheme")}else o=e.socket&&e.socket.encrypted?"https":"http";let n=new URL(`${o}://${i}${s}`);if(n.hostname.length!==i.length&&n.hostname!==i.replace(/:\d+$/,""))throw new Q("Invalid host header");return r[Ve]=n.href,r},jr=Symbol("responseCache"),ne=Symbol("getResponseCache"),ee=Symbol("cache"),It=global.Response,Se=class $r{#t;#e;[ne](){return delete this[ee],this[jr]||=new It(this.#t,this.#e)}constructor(t,r){let s;if(this.#t=t,r instanceof $r){let i=r[jr];if(i){this.#e=i,this[ne]();return}else this.#e=r.#e,s=new Headers(r.#e.headers)}else this.#e=r;(typeof t=="string"||typeof t?.getReader<"u"||t instanceof Blob||t instanceof Uint8Array)&&(s||=r?.headers||{"content-type":"text/plain; charset=UTF-8"},this[ee]=[r?.status||200,t,s])}get headers(){let t=this[ee];return t?(t[2]instanceof Headers||(t[2]=new Headers(t[2])),t[2]):this[ne]().headers}get status(){return this[ee]?.[0]??this[ne]().status}get ok(){let t=this.status;return t>=200&&t<300}};["body","bodyUsed","redirected","statusText","trailers","type","url"].forEach(e=>{Object.defineProperty(Se.prototype,e,{get(){return this[ne]()[e]}})});["arrayBuffer","blob","clone","formData","json","text"].forEach(e=>{Object.defineProperty(Se.prototype,e,{value:function(){return this[ne]()[e]()}})});Object.setPrototypeOf(Se,It);Object.setPrototypeOf(Se.prototype,It.prototype);async function to(e){return Promise.race([e,Promise.resolve().then(()=>Promise.resolve(void 0))])}function Mr(e,t,r){let s=a=>{e.cancel(a).catch(()=>{})};return t.on("close",s),t.on("error",s),(r??e.read()).then(n,i),e.closed.finally(()=>{t.off("close",s),t.off("error",s)});function i(a){a&&t.destroy(a)}function o(){e.read().then(n,i)}function n({done:a,value:c}){try{if(a)t.end();else if(!t.write(c))t.once("drain",o);else return e.read().then(n,i)}catch(l){i(l)}}}function ro(e,t){if(e.locked)throw new TypeError("ReadableStream is locked.");return t.destroyed?void 0:Mr(e.getReader(),t)}var Or=e=>{let t={};e instanceof Headers||(e=new Headers(e??void 0));let r=[];for(let[s,i]of e)s==="set-cookie"?r.push(i):t[s]=i;return r.length>0&&(t["set-cookie"]=r),t["content-type"]??="text/plain; charset=UTF-8",t},so="x-hono-already-sent",oo=global.fetch;typeof global.crypto>"u"&&(global.crypto=io);global.fetch=(e,t)=>(t={compress:!1,...t},oo(e,t));var At=Symbol("outgoingEnded"),no=()=>new Response(null,{status:400}),Dr=e=>new Response(null,{status:e instanceof Error&&(e.name==="TimeoutError"||e.constructor.name==="TimeoutError")?504:500}),xt=(e,t)=>{let r=e instanceof Error?e:new Error("unknown error",{cause:e});r.code==="ERR_STREAM_PREMATURE_CLOSE"?console.info("The user aborted a request."):(console.error(e),t.headersSent||t.writeHead(500,{"Content-Type":"text/plain"}),t.end(`Error: ${r.message}`),t.destroy(r))},Ur=e=>{"flushHeaders"in e&&e.writable&&e.flushHeaders()},Br=async(e,t)=>{let[r,s,i]=e[ee];i instanceof Headers&&(i=Or(i)),typeof s=="string"?i["Content-Length"]=Buffer.byteLength(s):s instanceof Uint8Array?i["Content-Length"]=s.byteLength:s instanceof Blob&&(i["Content-Length"]=s.size),t.writeHead(r,i),typeof s=="string"||s instanceof Uint8Array?t.end(s):s instanceof Blob?t.end(new Uint8Array(await s.arrayBuffer())):(Ur(t),await ro(s,t)?.catch(o=>xt(o,t))),t[At]?.()},ao=e=>typeof e.then=="function",co=async(e,t,r={})=>{if(ao(e))if(r.errorHandler)try{e=await e}catch(i){let o=await r.errorHandler(i);if(!o)return;e=o}else e=await e.catch(Dr);if(ee in e)return Br(e,t);let s=Or(e.headers);if(e.body){let i=e.body.getReader(),o=[],n=!1,a;if(s["transfer-encoding"]!=="chunked"){let c=2;for(let l=0;l<c;l++){a||=i.read();let u=await to(a).catch(f=>{console.error(f),n=!0});if(!u){if(l===1){await new Promise(f=>setTimeout(f)),c=3;continue}break}if(a=void 0,u.value&&o.push(u.value),u.done){n=!0;break}}n&&!("content-length"in s)&&(s["content-length"]=o.reduce((l,u)=>l+u.length,0))}t.writeHead(e.status,s),o.forEach(c=>{t.write(c)}),n?t.end():(o.length===0&&Ur(t),await Mr(i,t,a))}else s[so]||(t.writeHead(e.status,s),t.end());t[At]?.()},lo=(e,t={})=>{let r=t.autoCleanupIncoming??!0;return t.overrideGlobalObjects!==!1&&global.Request!==we&&(Object.defineProperty(global,"Request",{value:we}),Object.defineProperty(global,"Response",{value:Se})),async(s,i)=>{let o,n;try{n=eo(s,t.hostname);let a=!r||s.method==="GET"||s.method==="HEAD";if(a||(s[Lr]=!0,s.on("end",()=>{a=!0}),s instanceof zi&&(i[At]=()=>{a||setTimeout(()=>{a||setTimeout(()=>{s.destroy(),i.destroy()})})})),i.on("close",()=>{n[ae]&&(s.errored?n[ae].abort(s.errored.toString()):i.writableFinished||n[ae].abort("Client connection prematurely closed.")),a||setTimeout(()=>{a||setTimeout(()=>{s.destroy()})})}),o=e(n,{incoming:s,outgoing:i}),ee in o)return Br(o,i)}catch(a){if(o)return xt(a,i);if(t.errorHandler){if(o=await t.errorHandler(n?a:Gi(a)),!o)return}else n?o=Dr(a):o=no()}try{return await co(o,i,t)}catch(a){return xt(a,i)}}},uo=e=>{let t=e.fetch,r=lo(t,{hostname:e.hostname,overrideGlobalObjects:e.overrideGlobalObjects,autoCleanupIncoming:e.autoCleanupIncoming});return(e.createServer||qi)(e.serverOptions||{},r)},Hr=(e,t)=>{let r=uo(e);return r.listen(e?.port??3e3,e.hostname,()=>{let s=r.address();t&&t(s)}),r};import{getRandomValues as ho}from"node:crypto";var _=class{options;defaultLength=16;defaultOnlyLowerCase=!1;defaultStyle="extended";defaultUrlSafe=!0;constructor(e){if(this.options={},e)for(let[t,r]of Object.entries(e))this.options[t]=this.generateConfig(r)}add(e){if(!e?.name)throw new Error("Missing name for the ID configuration");let t=this.generateConfig(e);this.options[e.name]=t}remove(e){if(!e?.name)throw new Error("Missing name for the ID configuration");delete this.options[e.name]}create(e,t,r,s){let i=this.generateConfig({length:e,style:t,onlyLowerCase:r,urlSafe:s});return this.generateId(i)}custom(e){if(this.options[e])return this.generateId(this.options[e]);throw new Error(`No configuration found with name: ${e}`)}generateConfig(e){return{name:e?.name||"",length:e?.length||this.defaultLength,onlyLowerCase:e?.onlyLowerCase??this.defaultOnlyLowerCase,style:e?.style||this.defaultStyle,urlSafe:e?.urlSafe??this.defaultUrlSafe}}getCharacterSet(e,t,r){if(e==="hex")return t?"0123456789abcdef":"0123456789ABCDEFabcdef";if(e==="alphanumeric")return t?"abcdefghijklmnopqrstuvwxyz0123456789":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";if(e==="extended")return r?t?"abcdefghijklmnopqrstuvwxyz0123456789-._~":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~":t?"abcdefghijklmnopqrstuvwxyz0123456789-._~!$()*+,;=:":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$()*+,;=:";throw new Error(`Unknown ID style "${e} provided. Must be one of "extended" (default), "alphanumeric", or "hex".`)}generateId(e){let{length:t,onlyLowerCase:r,style:s,urlSafe:i}=e;if(t<0||t===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*t/o.length),c="";for(;c.length<t;){let l=new Uint8Array(a);ho(l);for(let u=0;u<a;u++){let f=l[u]&n;if(f<o.length&&(c+=o[f],c.length===t))break}}return c}};import fo from"node:crypto";function Vr(e,t,r){if(!r)return!1;let s=typeof e=="string"?[e]:e,i=typeof t=="string"?[t]:t;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=>Fr(u?.permissions,a)&&Fr(u?.targets,c)))return!1;return!0}function Fr(e,t){return!e||e.length===0?!1:e.some(r=>{if(r==="*"||r===t)return!0;if(r.endsWith("*")&&r!=="*"){let s=r.slice(0,-1);return t.startsWith(s)}return!1})}var b=class extends Error{constructor(t){super(),this.name="ValidationError",this.message=t||"Invalid input",this.cause={statusCode:400}}},be=class extends Error{constructor(t){super(),this.name="IdentityAlreadyExistsError",this.message=t||"Identity already exists",this.cause={statusCode:400}}},G=class extends Error{constructor(t){super(),this.name="NotFoundError",this.message=t||"Resource not found",this.cause={statusCode:404}}},_e=class extends Error{constructor(t){super(),this.name="InvalidInputError",this.message=t||"Invalid input",this.cause={statusCode:400}}};var We=class extends Error{constructor(t){super(),this.name="ConfigurationError",this.message=t||"Invalid configuration",this.cause={statusCode:400}}};var le=class extends Error{constructor(t){super(),this.name="PermissionDeniedError",this.message=t||"Permission denied",this.cause={statusCode:403}}},K=class extends Error{constructor(t){super(),this.name="AlreadyExistsError",this.message=t||"Resource already exists",this.cause={statusCode:409}}},qe=class extends Error{constructor(t){super(),this.name="PortInUseError",this.message=t||"Port already in use",this.cause={statusCode:409}}},Ee=class extends Error{constructor(t){super(),this.name="RoleNotFoundError",this.message=t||"Role not found",this.cause={statusCode:404}}},ze=class extends Error{constructor(t){super(),this.name="ProtectedResourceError",this.message=t||"Cannot modify protected resource",this.cause={statusCode:403}}},Ge=class extends Error{constructor(t){super(),this.name="ServiceRequestError",this.message=t||"Service request failed",this.cause={statusCode:502}}};var te=class{id;name;type;roles;metadata;constructor(t){let{id:r,name:s,type:i,roles:o,metadata:n}=this.createIdentity(t);this.id=r,this.name=s,this.type=i,this.roles=o,this.metadata=n}createIdentity(t){let r=t?.id||this.createId(),s=t?.name||"",i=t?.type||"service_account",o=t?.metadata||{},n=t?.roles||["user"];return t&&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(t){this.name=t}changeEmail(t){this.metadata||(this.metadata={}),this.metadata.email=t}updateMetadata(t){let r=this.metadata?JSON.parse(JSON.stringify(this.metadata)):{};this.metadata={...r,...t}}updateRoles(t){this.validateRoles(t),this.roles=t}createId(){return new _().create()}isValidRoleId(t){return typeof t!="string"||t.length===0?!1:/^[a-z0-9]+(-[a-z0-9]+)*$/.test(t)}isValidType(t){return["user","service_account"].includes(t)}validate(t){let r=t.id||"",s=t.name||"",i=t.type||"",o=t.metadata||{},n=t.roles||[];if(!r)throw new b("Missing ID");if(!s)throw new b("Missing name");if(!i||!this.isValidType(i))throw new b("Missing or invalid type");if(i==="user"&&!o?.email)throw new b("Missing email for user identity");if(!n||n.length===0)throw new b("Must have at least one role");this.validateRoles(n)}validateRoles(t){(t||[]).forEach(r=>{let s=r.id||r;if(!this.isValidRoleId(s))throw new b(`Invalid role ID '${s}'`)})}can(t,r,s){return Vr(t,r,s)}fromDTO(t){return this.validate(t),this.id=t.id,this.name=t.name,this.type=t.type,this.metadata=t.metadata||{},this.roles=t.roles,this}toDTO(){return{id:this.id,name:this.name,type:this.type,metadata:this.metadata,roles:this.roles}}};function Nr(){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 Ke=class{mikroAuth;db;tableName="identity_service";initialUser;roles;identities;serviceAccountTokens;constructor(t,r,s){this.mikroAuth=t,this.db=r,this.initialUser=s,this.roles=[],this.identities=[],this.serviceAccountTokens=new Map}async start(){await this.loadState(),this.roles.find(t=>t.id==="administrator")||this.createBaseRoles(),this.identities.length===0&&this.createInitialUser()}createBaseRoles(){let t=Nr();for(let r of t)this.roles.push(r)}async createInitialUser(){let t=this.initialUser.email,r=this.initialUser.userName,s=await this.addUser(t,r,["administrator"]);return await this.mikroAuth.createMagicLink({email:t}),s}async getUserByEmail(t){let r=this.identities.find(s=>s.type==="user"&&s.metadata?.email===t&&s.metadata?.active!==!1);if(r)return this.enrichIdentityWithRoles(r)}async addUser(t,r,s=["user"],i=!0){if((await this.getUsers()).find(c=>c.metadata.email===t))throw new be(`User with email ${t} already exists`);let a=new te({name:r,type:"user",metadata:{email:t,active:i},roles:s}).toDTO();return this.identities.push(a),await this.saveState(),this.enrichIdentityWithRoles(a)}async addServiceAccount(t,r,s){if((await this.getServiceAccounts()).find(c=>c.name===t))throw new be(`Service account with name ${t} already exists`);let n=new te({name:t,type:"service_account",metadata:{description:r},roles:s}).toDTO(),a=this.generateServiceAccountToken();return this.serviceAccountTokens.set(a,n.id),this.identities.push(n),await this.saveState(),{...this.enrichIdentityWithRoles(n),apiKey:a}}async rotateServiceAccountKey(t){let r=await this.getIdentityById(t);if(!r||r.type!=="service_account")return;for(let[i,o]of this.serviceAccountTokens.entries())o===t&&this.serviceAccountTokens.delete(i);let s=this.generateServiceAccountToken();return this.serviceAccountTokens.set(s,t),await this.saveState(),s}async deleteIdentity(t){for(let[s,i]of this.serviceAccountTokens.entries())i===t&&this.serviceAccountTokens.delete(s);let r=this.identities.filter(s=>s.id!==t);this.identities=r,await this.saveState()}async updateIdentity(t,r){let s=await this.getIdentityById(t);if(!s)return;let i=new te().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(t){if(!t)throw new b("Cannot update identity list: updatedIdentity is null or undefined");let r=JSON.parse(JSON.stringify(this.identities)),s=r.find(i=>i.id===t.id);s&&Object.assign(s,t),this.identities=r}generateServiceAccountToken(){return`sa.${new _().create()}.${fo.randomBytes(32).toString("hex")}`}async getUserFromToken(t){if(t&&t.startsWith("Bearer ")){let r=t.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(t){return this.identities.find(r=>r.id===t)}async getUserById(t){let r=await this.getIdentityById(t);if(!(!r||r.type!=="user"))return this.enrichIdentityWithRoles(r)}async getServiceAccountById(t){let r=await this.getIdentityById(t);if(!(!r||r.type!=="service_account"))return this.enrichIdentityWithRoles(r)}async updateUser(t,r){let s=await this.getIdentityById(t);if(!(!s||s.type!=="user"))return this.updateIdentity(t,r)}async updateServiceAccount(t,r){let s=await this.getIdentityById(t);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(t,i)}async deleteUser(t){let r=await this.getIdentityById(t);return!r||r.type!=="user"?!1:(await this.deleteIdentity(t),!0)}async deleteServiceAccount(t){let r=await this.getIdentityById(t);return!r||r.type!=="service_account"?!1:(await this.deleteIdentity(t),!0)}enrichIdentityWithRoles(t){let r=JSON.parse(JSON.stringify(t));return t.roles?r.roles=t.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(t=>t.type==="user")}async getServiceAccounts(){return this.identities.filter(t=>t.type==="service_account")}can(t,r,s){return new te(s).can(t,r,s)}async createCustomRole(t,r,s,i,o){if(this.roles.find(l=>l.id===t))throw new K(`Role with ID ${t} already exists`);let c={id:t,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(t,r){let s=this.roles.find(i=>i.id===t);if(!s)throw new Ee(`Role with ID ${t} 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(t){let r=this.roles.findIndex(s=>s.id===t);if(r===-1)throw new Ee(`Role with ID ${t} not found`);if(t==="administrator"||t==="user")throw new ze("Cannot delete base roles");this.roles.splice(r,1),await this.saveState()}async getRoles(){return this.roles}async getRole(t){return this.roles.find(r=>r.id===t)}async loadState(){let t=await this.load("identities");t&&(this.identities=t);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 t=Object.fromEntries(this.serviceAccountTokens);await this.write("identities",this.identities),await this.write("roles",this.roles),await this.write("serviceAccountTokens",t)}async load(t){return await this.db.get({tableName:this.tableName,key:t})}async write(t,r){await this.db.write({tableName:this.tableName,key:t,value:r})}};import{existsSync as Co}from"node:fs";function re(e){if(!e||typeof e!="string")throw new Error("Table name must be a non-empty string");if(e.length>255)throw new Error("Table name must not exceed 255 characters");if(e.includes("/")||e.includes("\\"))throw new Error("Table name must not contain path separators");if(e.includes(".."))throw new Error('Table name must not contain ".."');if(e.startsWith("."))throw new Error('Table name must not start with "."');if(e.includes("\0"))throw new Error("Table name must not contain null bytes");if(["CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"].includes(e.toUpperCase()))throw new Error(`Table name "${e}" is reserved by the filesystem`)}function Je(e){if(e==null)throw new Error("Key must be defined");if(typeof e!="string")throw new Error("Key must be a string");if(e.length===0)throw new Error("Key must not be empty");if(e.length>1024)throw new Error("Key must not exceed 1024 characters");if(e.includes("\0"))throw new Error("Key must not contain null bytes")}function _r(e){if(e===void 0)throw new Error("Value must not be undefined (use null instead)");let t=typeof e;if(t==="function")throw new Error("Value must be JSON-serializable: functions are not supported");if(t==="symbol")throw new Error("Value must be JSON-serializable: symbols are not supported");try{if(JSON.stringify(e)===void 0)throw new Error("Value must be JSON-serializable: value cannot be serialized")}catch(r){throw new Error(`Value must be JSON-serializable: ${r instanceof Error?r.message:String(r)}`)}}function Xe(e){if(!e.deflate&&!e.inflate)throw new Error("Dictionary must provide either deflate or inflate mapping");if(e.deflate&&e.inflate)throw new Error("Dictionary should provide only one of deflate or inflate (not both). The inverse will be auto-generated.");return e.deflate?{deflate:e.deflate,inflate:Wr(e.deflate)}:{deflate:Wr(e.inflate),inflate:e.inflate}}function Wr(e){let t={};for(let[r,s]of Object.entries(e))t[s]=r;return t}function ue(e,t){if(e==null||typeof e!="object")return e;if(Array.isArray(e))return e.map(s=>ue(s,t));let r={};for(let[s,i]of Object.entries(e)){let o=t[s]||s;r[o]=ue(i,t)}return r}import{existsSync as kt,mkdirSync as po,readdirSync as mo,openSync as go,closeSync as yo}from"fs";import{readFile as vo,writeFile as wo,rename as So,unlink as qr,open as bo}from"fs/promises";import{join as Tt,dirname as Eo}from"path";var Ce=class{data=new Map;databaseDirectory;dictionaries=new Map;useFsync;constructor(e){this.databaseDirectory=e.databaseDirectory,this.useFsync=e.durableWrites??!1,e.dictionaries&&Object.entries(e.dictionaries).forEach(([t,r])=>{let s=Xe(r);this.dictionaries.set(t,s)}),kt(this.databaseDirectory)||po(this.databaseDirectory,{recursive:!0})}async start(){try{let e=mo(this.databaseDirectory);for(let t of e)!t.endsWith(".tmp")&&!t.startsWith(".")&&await this.loadTable(t)}catch(e){throw console.error("Failed to start database:",e),e}}async write(e,t,r,s,i){if(re(e),Je(t),_r(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(e)||this.data.set(e,new Map);let o=this.data.get(e),a=(o.get(t)?.version||0)+1,c={value:r,version:a,timestamp:Date.now(),expiration:s||null,dictionaryName:i||void 0};return o.set(t,c),await this.persistTable(e),!0}catch(o){return console.error(`Write failed for ${e}:${t}:`,o),!1}}async get(e,t){re(e),t!==void 0&&Je(t);try{this.data.has(e)||await this.loadTable(e);let r=this.data.get(e);if(!r)return t?void 0:[];if(t!==void 0){let o=r.get(t);if(!o)return;if(this.isExpired(o)){r.delete(t),await this.persistTable(e);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(e)}return s}catch(r){return console.error(`Read failed for ${e}:${t}:`,r),t?void 0:[]}}async delete(e,t){re(e),Je(t);try{this.data.has(e)||await this.loadTable(e);let r=this.data.get(e);if(!r||!r.has(t))return!1;let s=r.get(t);return s?this.isExpired(s)?(r.delete(t),await this.persistTable(e),!1):(r.delete(t),await this.persistTable(e),!0):!1}catch(r){return console.error(`Delete failed for ${e}:${t}:`,r),!1}}async getTableSize(e){re(e);try{this.data.has(e)||await this.loadTable(e);let t=this.data.get(e);if(!t)return 0;let r=0,s=[];for(let[i,o]of t.entries())this.isExpired(o)?s.push(i):r++;if(s.length>0){for(let i of s)t.delete(i);await this.persistTable(e)}return r}catch(t){return console.error(`Get table size failed for ${e}:`,t),0}}isExpired(e){return e.expiration===null?!1:Date.now()>e.expiration}async cleanupExpired(e){re(e);try{this.data.has(e)||await this.loadTable(e);let t=this.data.get(e);if(!t)return 0;let r=[];for(let[s,i]of t.entries())this.isExpired(i)&&r.push(s);for(let s of r)t.delete(s);return r.length>0&&await this.persistTable(e),r.length}catch(t){return console.error(`Cleanup failed for ${e}:`,t),0}}async cleanupAllExpired(){let e=0;for(let t of this.data.keys())e+=await this.cleanupExpired(t);return e}async deleteTable(e){re(e);try{this.data.delete(e);let t=Tt(this.databaseDirectory,e);return kt(t)&&await qr(t),!0}catch(t){return console.error(`Delete table failed for ${e}:`,t),!1}}listTables(){return Array.from(this.data.keys())}async flush(){try{let e=Array.from(this.data.keys()).map(t=>this.persistTable(t));await Promise.all(e)}catch(e){throw console.error("Flush failed:",e),e}}async close(){await this.flush()}addDictionary(e,t){let r=Xe(t);this.dictionaries.set(e,r)}removeDictionary(e){return this.dictionaries.delete(e)}listDictionaries(){return Array.from(this.dictionaries.keys())}async loadTable(e){let t=Tt(this.databaseDirectory,e);if(!kt(t)){this.data.set(e,new Map);return}try{let r=await vo(t);if(r.length===0){this.data.set(e,new Map);return}let s=this.deserializeTable(r);this.data.set(e,s)}catch(r){console.error(`Failed to load table ${e}:`,r),this.data.set(e,new Map)}}async persistTable(e){let t=this.data.get(e);if(!t)return;let r=this.serializeTable(t),s=Tt(this.databaseDirectory,e),i=`${s}.tmp.${Date.now()}.${Math.random().toString(36).substring(7)}`;try{if(await wo(i,r),this.useFsync){let o=await bo(i,"r+");try{await o.sync()}finally{await o.close()}}if(await So(i,s),this.useFsync){let o=Eo(s),n=go(o,"r");try{yo(n)}catch{}}}catch(o){try{await qr(i)}catch{}throw o}}serializeTable(e){let t=Array.from(e.entries()).map(([r,s])=>{let i=s.dictionaryName?this.dictionaries.get(s.dictionaryName):void 0,o={d:i?ue(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(t),"utf8")}deserializeTable(e){let r=JSON.parse(e.toString("utf8")).map(([s,i])=>{let o=i.n,n=o?this.dictionaries.get(o):void 0;return[s,{value:n?ue(i.d,n.inflate):i.d,version:i.v,timestamp:i.t,expiration:i.x,dictionaryName:o||void 0}]});return new Map(r)}};import{spawn as xo}from"node:child_process";import{createServer as Io}from"node:net";var zr={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"]}},Ye=class{db;services=new Map;tableName="molnosmanagement";environmentVariables={};setEnvironmentVariables(t){this.environmentVariables={...this.environmentVariables,...t}}async isPortInUse(t){return new Promise(r=>{let s=Io();s.once("error",i=>{i.code==="EADDRINUSE"?r(!0):r(!1)}),s.once("listening",()=>{s.close(),r(!1)}),s.listen(t,"localhost")})}constructor(t){this.db=new Ce({databaseDirectory:t.dbPath})}getServiceDefinition(t){let r=t.toLowerCase(),s=zr[r];if(!s)throw new G(`Unknown service: ${t}. Valid services are: ${Object.keys(zr).join(", ")}`);return s}async start(){await this.db.start();let t=await this.db.get(this.tableName,"services")||[];for(let r of t)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),r.active&&await this.startService(r.name)}async stopAllServices(){let t=[];for(let[r,s]of this.services.entries())(s.active||s.process)&&(console.log(`[ManagementService] Stopping ${r}...`),t.push(this.stopService(r)));await Promise.all(t),console.log("[ManagementService] All services stopped")}async shutdown(){console.log("[ManagementService] External shutdown requested"),await this.stopAllServices()}validateServiceConfig(t){if(!t.name||t.name.trim()==="")throw new b("Service name is required");if(!t.path||t.path.trim()==="")throw new b("Service path is required");if(!Co(t.path))throw new We(`Service path does not exist: ${t.path}`);if(!t.port||t.port<1||t.port>65535)throw new b(`Invalid port: ${t.port}`);if(!t.prefix||!t.prefix.startsWith("/"))throw new b("Service prefix must start with /")}cleanServiceForStorage(t){let{process:r,...s}=t;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(t,r){let s;typeof t=="string"?s={...this.getServiceDefinition(t),...r}:s=t,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 qe(`Port ${i.port} already in use`);if(n.includes(i.name))throw new K(`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(t){let r=this.services.get(t);if(!r)return!1;if(r.process&&r.active)return!0;if(await this.isPortInUse(r.port))return console.error(`[ManagementService] Cannot start ${t}: 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=xo("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(`[${t}] ${u}`)}),a.stderr.on("data",l=>{let u=l.toString();console.error(`[${t}] 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 ${t} 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(t,!0),r.healthCheck&&this.startHealthCheck(r),!0):(console.error(`[ManagementService] Service ${t} exited immediately after spawn`),!1)}catch(i){return console.error(`[ManagementService] Failed to start ${t}:`,i),!1}}startHealthCheck(t){let r=t.healthCheck;if(!r)return;let s=async()=>{if(t.healthCheck)try{let i=new AbortController,o=setTimeout(()=>i.abort(),t.healthCheck.timeoutMs),n=await fetch(`http://localhost:${t.port}${t.healthCheck.path}`,{signal:i.signal});clearTimeout(o),n.ok&&t.healthCheck?(t.healthCheck.consecutiveSuccesses=(t.healthCheck.consecutiveSuccesses||0)+1,t.healthCheck.consecutiveFailures=0,t.healthCheck.consecutiveSuccesses>=t.healthCheck.successThreshold&&(t.healthCheck.healthy=!0)):this.handleHealthCheckFailure(t)}catch{this.handleHealthCheckFailure(t)}};r.timer=setInterval(s,r.intervalMs)}handleHealthCheckFailure(t){t.healthCheck&&(t.healthCheck.consecutiveFailures=(t.healthCheck.consecutiveFailures||0)+1,t.healthCheck.consecutiveSuccesses=0,t.healthCheck.consecutiveFailures>=t.healthCheck.failureThreshold&&(t.healthCheck.healthy=!1,t.healthCheck.restartOnFailure&&this.restartService(t.name).catch(()=>{})))}async handleServiceExit(t,r){if(await this.updateServiceStatus(t.name,!1),!t.restartPolicy||t.restartPolicy.type==="never"||t.restartPolicy.type==="on-failure"&&r===0||t.restartPolicy.maxAttempts>0&&(t.restartPolicy.attempts||0)>=t.restartPolicy.maxAttempts)return;t.restartPolicy.attempts=(t.restartPolicy.attempts||0)+1;let s=t.restartPolicy.backoffMs;setTimeout(()=>{this.startService(t.name).catch(()=>{})},s)}async stopService(t){let r=this.services.get(t);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(t,!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(t,!1),!0}catch{return r.active&&(r.active=!1,r.process=void 0,await this.updateServiceStatus(t,!1)),!1}}async restartService(t){return await this.stopService(t),await new Promise(r=>setTimeout(r,500)),this.startService(t)}async updateServiceStatus(t,r){let s=await this.db.get(this.tableName,"services")||[],i=s.findIndex(o=>o.name===t);if(i>=0){let o=this.services.get(t);o?(o.active=r,s[i]=this.cleanServiceForStorage(o)):s[i].active=r,await this.db.write(this.tableName,"services",s)}}async getService(t){return(await this.getServices()).find(s=>s.name===t)}async getServices(){return(await this.db.get(this.tableName,"services")||[]).map(({process:r,...s})=>s)}async getServiceStats(t){let r=this.services.get(t);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(t,r){let s=this.services.get(t);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===t);return n>=0?(o[n]=this.cleanServiceForStorage(s),await this.db.write(this.tableName,"services",o),i!==s.active&&(s.active?await this.startService(t):await this.stopService(t)),!0):!1}async removeService(t){let r=this.services.get(t);r?.healthCheck?.timer&&(clearInterval(r.healthCheck.timer),r.healthCheck.timer=void 0),await this.stopService(t),this.services.delete(t);let i=(await this.db.get(this.tableName,"services")||[]).filter(o=>o.name!==t);return await this.db.write(this.tableName,"services",i),!0}};var W=class{id;name;description;redirectUris;metadata;owners;constructor(t){let r=this.createApplication(t);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(t){let r=t?.id||this.createId(),s=t?.name||"",i=t?.description,o=t?.redirectUris||[],n=t?.owners||[],a=new Date().toISOString(),c={...t?.metadata||{},createdAt:t?.metadata?.createdAt||a,updatedAt:a,createdBy:t?.metadata?.createdBy||n[0]||""};return t&&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(t){t.name!==void 0&&(this.name=t.name),t.description!==void 0&&(this.description=t.description),t.redirectUris!==void 0&&(this.validateRedirectUris(t.redirectUris),this.redirectUris=t.redirectUris),t.owners!==void 0&&(this.owners=t.owners),t.metadata!==void 0?this.metadata={...this.metadata,...t.metadata,updatedAt:new Date().toISOString()}:this.metadata.updatedAt=new Date().toISOString(),this.validate(this.toDTO())}isValidRedirectUri(t){return this.redirectUris.includes(t)}isOwner(t){return this.owners.includes(t)}createId(){return new _().create()}validate(t){let{id:r,name:s,redirectUris:i,metadata:o,owners:n}=t;if(!r)throw new b("Missing ID");if(!s||s.trim().length===0)throw new b("Missing or invalid name");if(!o)throw new b("Missing metadata");if(!n||n.length===0)throw new b("Application must have at least one owner");this.validateRedirectUris(i)}validateRedirectUris(t){if(!t||t.length===0)throw new b("At least one redirect URI is required");for(let r of t)try{let s=new URL(r);if(s.protocol!=="https:"&&s.protocol!=="http:"&&s.protocol!=="custom:")throw new b(`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 b(`Invalid redirect URI format: ${r}`)}}fromDTO(t){return this.validate(t),this.id=t.id,this.name=t.name,this.description=t.description,this.redirectUris=t.redirectUris,this.metadata=t.metadata,this.owners=t.owners,this}toDTO(){return{id:this.id,name:this.name,description:this.description,redirectUris:this.redirectUris,metadata:this.metadata,owners:this.owners}}};var Ze=class{db;tableName="molnosapplications";key="applications";applications;constructor(t){this.db=new Ce({databaseDirectory:t.dbPath}),this.applications=[]}async start(){await this.db.start(),await this.loadState()}async loadState(){let t=await this.db.get(this.tableName,this.key)||[];this.applications=t,console.log(`[ApplicationService] Loaded ${this.applications.length} applications`)}async saveState(){await this.db.write(this.tableName,this.key,this.applications)}async createApplication(t,r){let s=t.owners.includes(r)?t.owners:[...t.owners,r],o=new W({...t,owners:s,metadata:{...t.metadata,createdBy:r}}).toDTO();if(this.applications.find(a=>a.name===o.name))throw new K(`Application with name '${o.name}' already exists`);return this.applications.push(o),await this.saveState(),o}async getApplication(t,r){let s=this.applications.find(o=>o.id===t);if(!s)throw new G(`Application with ID '${t}' not found`);let i=new W().fromDTO(s);if(r&&!i.isOwner(r))throw new le("Only application owners can view application details");return i.toDTO()}async getApplicationById(t){return this.applications.find(s=>s.id===t)||null}async listApplications(t){return this.applications.filter(r=>r.owners.includes(t)).map(r=>new W().fromDTO(r).toDTO())}async updateApplication(t,r,s){let i=this.applications.findIndex(a=>a.id===t);if(i===-1)throw new G(`Application with ID '${t}' not found`);let o=this.applications[i],n=new W().fromDTO(o);if(!n.isOwner(s))throw new le("Only application owners can update the application");if(r.owners&&r.owners.length===0)throw new b("Application must have at least one owner");if(r.owners&&!r.owners.includes(s)&&o.owners.length===1&&o.owners[0]===s)throw new b("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(t,r){let s=this.applications.findIndex(n=>n.id===t);if(s===-1)throw new G(`Application with ID '${t}' not found`);let i=this.applications[s];if(!new W().fromDTO(i).isOwner(r))throw new le("Only application owners can delete the application");this.applications.splice(s,1),await this.saveState()}async validateRedirectUri(t,r){let s=await this.getApplicationById(t);return s?new W().fromDTO(s).isValidRedirectUri(r):!1}getAllApplicationsInternal(){return this.applications}};async function A(e){try{return await e.req.json()}catch{return{}}}function m(e,t="An error occurred"){let r=e?.message||e||t,s=e?.cause?.statusCode||e?.statusCode||400;return{message:r,status:s}}async function Gr(e,t,r,s){try{let i=await A(e),{email:o,redirectUrl:n,applicationId:a}=i;if(!o)return e.json({error:"Email is required"},400);let c=o.trim().toLowerCase(),l;if(n){if(!a)return e.json({error:"applicationId is required when redirectUrl is provided"},400);if(!await s.validateRedirectUri(a,n))return e.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 t.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}}),e.json({success:!0,message:"If a matching account was found, a magic link has been sent."})}catch(i){let{message:o,status:n}=m(i,"Error during login");return e.text(o,n)}}async function Kr(e,t,r){try{let s=e.req.query("token"),i=e.req.query("email");if(!s)return e.json({error:"Token is required as query parameter"},400);if(!i)return e.json({error:"Email is required as query parameter"},400);try{let o=await t.verifyToken({token:s,email:i});if(!o)return e.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()),e.redirect(c.toString(),302)}else return console.warn(`Redirect URL validation failed for applicationId: ${n.applicationId}`),e.json({...o,warning:"Redirect URL validation failed. Tokens provided but redirect was not performed."},200);return e.json(o,200)}catch{return e.json({error:"Invalid or expired token"},401)}}catch(s){let{message:i,status:o}=m(s,"Error verifying token");return e.text(i,o)}}async function Jr(e,t){try{let s=(await A(e)).refreshToken;if(!s)return e.json({error:"Value for refreshToken is required"},400);try{let i=await t.refreshAccessToken(s);return e.json(i,200)}catch{return e.json({error:"Invalid or expired token"},401)}}catch(r){let{message:s,status:i}=m(r,"Error refreshing token");return e.text(s,i)}}async function Xr(e){try{let t=e.get("user");return e.json(t)}catch(t){let{message:r,status:s}=m(t,"Error getting user info");return e.text(r,s)}}function p(e,t,r={}){let s=Array.isArray(t)?t:[t];if(!e||!e.roles||!Array.isArray(e.roles)){let n=new Error("Unauthorized: User or roles missing");throw n.cause={statusCode:403},n}let i=e.roles.flatMap(n=>n?.policies?.flatMap(a=>(a?.permissions||[]).flatMap(l=>typeof l=="string"?l:l&&typeof l=="object"&&l.actions?l.actions:[]))||[]);if(!s.every(n=>i.includes(n)||i.includes("*")?!0:i.some(a=>{if(a.endsWith(".*")){let c=a.slice(0,-2);return n.startsWith(`${c}.`)}return!1}))){let n=new Error("Unauthorized");throw n.cause={statusCode:403},n}return!0}async function Yr(e,t){try{let r=e.get("user");p(r,"identity.identities.get",{});let s=await t.getIdentities();return e.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting identities");return e.text(s,i)}}var O=class{isSilent;propertyPath="";constructor(e=!1){this.isSilent=e}test(e,t){if(!t)throw new Error("Missing input!");this.updatePropertyPath();let{results:r,errors:s}=this.validate(e.properties,t),i=this.compileErrors(r,s),o=this.isSuccessful(r,i);return{errors:i,success:o}}compileErrors(e,t){let r=e.filter(s=>s.success===!1);return[...t,...r].flatMap(s=>s)}isSuccessful(e,t){return e.every(r=>r.success===!0)&&t.length===0}validate(e,t,r=[],s=[]){let i=e?.additionalProperties??!0,o=e?.required||[];s=this.checkForRequiredKeysErrors(o,t,s),s=this.checkForDisallowedProperties(Object.keys(t),Object.keys(e),s,i);for(let n in e){let a=o.includes(n)&&n!=="required",c=e[n],l=t[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(e,t=""){if(!e){this.propertyPath="";return}t&&(this.propertyPath=t),this.propertyPath=`${this.propertyPath}.${e}`,this.propertyPath.startsWith(".")&&(this.propertyPath=this.propertyPath.substring(1,this.propertyPath.length))}isDefined(e){return!!(typeof e=="number"&&e===0||e||e===""||typeof e=="boolean")}checkForRequiredKeysErrors(e,t,r){if(!this.areRequiredKeysPresent(e,t)){let s=t?Object.keys(t):[],i=this.findNonOverlappingElements(e,s),o=i.length>0?`Missing the required key: '${i.join(", ")}'!`:`Missing values for required keys: '${s.filter(n=>!t[n]).join(", ")}'!`;r.push({key:"",value:t,success:!1,error:o})}return r}checkForDisallowedProperties(e,t,r,s){if(!s){let i=this.findNonOverlappingElements(e,t);i.length>0&&r.push({key:`${t}`,value:e,success:!1,error:`Has additional (disallowed) properties: '${i.join(", ")}'!`})}return r}handleValidation(e,t,r,s){this.updatePropertyPath(e);let i=this.validateProperty(this.propertyPath,r,t);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 f=this.validateProperty(this.propertyPath,r[u],a[u]);s.push(...f)}})};this.isArray(t)&&r.items!=null?o(t,r):this.isObject(t)?n(t):this.updatePropertyPath()}handleNestedObject(e,t,r,s){if(this.isObject(e)){let i=this.getNestedObjects(e);for(let o of i){let n=t[o],a=e[o];n&&typeof a=="object"&&this.validate(n,a,r,s)}}}getNestedObjects(e){return Object.keys(e).filter(t=>{if(this.isObject(e))return t})}findNonOverlappingElements(e,t){return e.filter(r=>!t.includes(r))}areRequiredKeysPresent(e,t=[]){return e.every(r=>Object.keys(t).includes(r)?this.isDefined(t[r]):!1)}validateProperty(e,t,r){return this.validateInput(t,r).map(i=>{let{success:o,error:n}=i;return{key:e,value:r,success:o,error:n??""}})}validateInput(e,t){if(e){let r=[{condition:()=>e.type,validator:()=>this.isCorrectType(e.type,t),error:"Invalid type"},{condition:()=>e.format,validator:()=>this.isCorrectFormat(e.format,t),error:"Invalid format"},{condition:()=>e.minLength,validator:()=>this.isMinimumLength(e.minLength,t),error:"Length too short"},{condition:()=>e.maxLength,validator:()=>this.isMaximumLength(e.maxLength,t),error:"Length too long"},{condition:()=>e.minValue,validator:()=>this.isMinimumValue(e.minValue,t),error:"Value too small"},{condition:()=>e.maxValue,validator:()=>this.isMaximumValue(e.maxValue,t),error:"Value too large"},{condition:()=>e.matchesPattern,validator:()=>this.matchesPattern(e.matchesPattern,t),error:"Pattern does not match"}],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 '${e}' for match '${t}'. Skipping...`);return[{success:!0}]}isCorrectType(e,t){return Array.isArray(e)||(e=[e]),e.some(r=>{switch(r){case"string":return typeof t=="string";case"number":return typeof t=="number"&&!isNaN(t);case"boolean":return typeof t=="boolean";case"object":return this.isObject(t);case"array":return this.isArray(t)}})}isObject(e){return e!==null&&!this.isArray(e)&&typeof e=="object"&&e instanceof Object&&Object.prototype.toString.call(e)==="[object Object]"}isArray(e){return Array.isArray(e)}isCorrectFormat(e,t){switch(e){case"alphanumeric":return new RegExp(/^[a-zA-Z0-9]+$/).test(t);case"numeric":return new RegExp(/^-?\d+(\.\d+)?$/).test(t);case"email":return new RegExp(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/).test(t);case"date":return new RegExp(/^\d{4}-\d{2}-\d{2}$/).test(t);case"url":return new RegExp(/^(https?):\/\/[^\s$.?#].[^\s]*$/).test(t);case"hexColor":return new RegExp(/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i).test(t)}}isMinimumLength(e,t){return Array.isArray(t)?t.length>=e:t?.toString().length>=e}isMaximumLength(e,t){return Array.isArray(t)?t.length<=e:t.toString().length<=e}isMinimumValue(e,t){return t>=e}isMaximumValue(e,t){return t<=e}matchesPattern(e,t){return new RegExp(e).test(t)}schemaFrom(e){let t={properties:{additionalProperties:!1,required:[]}};for(let r in e){let s=e[r];t.properties.required.push(r),Array.isArray(s)?t.properties[r]=this.generateArraySchema(s):typeof s=="object"&&s!==null?t.properties[r]=this.generateNestedObjectSchema(s):t.properties[r]=this.generatePropertySchema(s)}return t}generateArraySchema(e){let t={type:"array"},r=e.filter(s=>s);if(r.length>0){let s=r[0];r.every(o=>typeof o==typeof s)?typeof s=="object"&&!Array.isArray(s)?t.items=this.generateNestedObjectSchema(s):t.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 t}generateNestedObjectSchema(e){let t={type:"object",additionalProperties:!1,required:[]};for(let r in e){let s=e[r];t.required.push(r),typeof s=="object"&&!Array.isArray(s)&&s!==null?t[r]=this.generateNestedObjectSchema(s):t[r]=this.generatePropertySchema(s)}return t}generatePropertySchema(e){let t=typeof e,r={type:t};return t==="string"&&(r.minLength=1),r}};var Zr={properties:{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 ko=new O;async function Qr(e,t){try{let r=e.get("user"),s=await A(e),i=ko.test(Zr,s);if(!i.success)return e.json({error:"Invalid input",details:i.errors},400);p(r,"identity.user.create",{});let{email:o,name:n,roles:a,verified:c}=s,l=await t.addUser(o,n,a,c);return e.json(l,201)}catch(r){let{message:s,status:i}=m(r,"Error creating user");return e.text(s,i)}}async function es(e,t){try{let r=e.get("user");p(r,"identity.user.get",{});let s=await t.getUsers();return e.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting users");return e.text(s,i)}}function S(e){return e.req.param()}async function ts(e,t){try{let r=e.get("user"),s=S(e),{userId:i}=s;p(r,"identity.user.get",{userId:i});let o=await t.getUserById(i);return o?e.json(o):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting user");return e.text(s,i)}}var rs={properties:{name:{type:"string",minLength:1},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var Ro=new O;async function ss(e,t){try{let r=e.get("user"),s=S(e),{userId:i}=s,o=await A(e),n=Ro.test(rs,o);if(!n.success)return e.json({error:"Invalid input",details:n.errors},400);p(r,"identity.user.update",{userId:i});let{name:a,roles:c}=o,l=await t.updateUser(i,{name:a,roles:c});return l?e.json(l):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error updating user");return e.text(s,i)}}async function is(e,t){try{let r=e.get("user"),s=S(e),{userId:i}=s;return p(r,"identity.user.delete",{userId:i}),await t.deleteUser(i)?e.body(null,204):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting user");return e.text(s,i)}}async function os(e,t){try{let r=e.get("user"),s=await A(e);if(!s.name||!s.description||!s.roles||!Array.isArray(s.roles))return e.json({error:"Invalid input: name, description, and roles are required"},400);if(!["user","administrator"].every(c=>s.roles.includes(c)||!s.roles.includes(c)))return e.json({error:"Invalid input: roles must be user or administrator"},400);p(r,"identity.service-account.create",{});let{name:i,description:o,roles:n}=s,a=await t.addServiceAccount(i,o,n);return e.json(a,201)}catch(r){let{message:s,status:i}=m(r,"Error creating service account");return e.text(s,i)}}async function ns(e,t){try{let r=e.get("user");p(r,"identity.service-account.get",{});let s=await t.getServiceAccounts();return e.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting service accounts");return e.text(s,i)}}async function as(e,t){try{let r=e.get("user"),s=S(e),{serviceAccountId:i}=s;p(r,"identity.service-account.get",{serviceAccountId:i});let o=await t.getServiceAccountById(i);return o?e.json(o):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting service account");return e.text(s,i)}}var cs={properties:{name:{type:"string",minLength:1,maxLength:100},description:{type:"string",minLength:1,maxLength:500},roles:{type:"array",items:{type:"string"}}},additionalProperties:!1};var jo=new O;async function ls(e,t){try{let r=e.get("user"),s=S(e),{serviceAccountId:i}=s,o=await A(e),n=jo.test(cs,o);if(!n.success)return e.json({error:"Invalid input",details:n.errors},400);p(r,"identity.service-account.update",{serviceAccountId:i});let{name:a,description:c,roles:l}=o,u=await t.updateServiceAccount(i,{name:a,description:c,roles:l});return u?e.json(u):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error updating service account");return e.text(s,i)}}async function us(e,t){try{let r=e.get("user"),s=S(e),{serviceAccountId:i}=s;return p(r,"identity.service-account.delete",{serviceAccountId:i}),await t.deleteServiceAccount(i)?e.body(null,204):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting service account");return e.text(s,i)}}async function ds(e,t){try{let r=e.get("user"),s=S(e),{serviceAccountId:i}=s;p(r,"identity.service-account.update",{serviceAccountId:i});let o=await t.rotateServiceAccountKey(i);return o?e.json({apiKey:o}):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error rotating service account key");return e.text(s,i)}}async function hs(e,t){try{let r=e.get("user");p(r,"identity.role.get",{});let s=await t.getRoles();return e.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting roles");return e.text(s,i)}}async function fs(e,t){try{let r=e.get("user");p(r,"identity.role.get",{});let s=e.req.param("roleId");if(!s)return e.text("Missing role ID",400);let i=await t.getRole(s);return i?e.json(i):e.text("Role not found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting role");return e.text(s,i)}}async function ps(e,t){try{let r=e.get("user");p(r,"identity.role.create",{});let s=await e.req.json(),{roleId:i,name:o,description:n,permissions:a,constraints:c}=s;if(!i||!o||!n)return e.text("Missing required fields: roleId, name, description",400);if(!a||!Array.isArray(a))return e.text("Permissions must be a non-empty array",400);await t.createCustomRole(i,o,n,a,c);let l=await t.getRole(i);return e.json(l,201)}catch(r){let{message:s,status:i}=m(r,"Error creating role");return e.text(s,i)}}async function ms(e,t){try{let r=e.get("user");p(r,"identity.role.update",{});let s=e.req.param("roleId");if(!s)return e.text("Missing role ID",400);let i=await e.req.json(),{name:o,description:n,permissions:a,constraints:c}=i;await t.updateRole(s,{name:o,description:n,permissions:a,constraints:c});let l=await t.getRole(s);return e.json(l)}catch(r){let{message:s,status:i}=m(r,"Error updating role");return e.text(s,i)}}async function gs(e,t){try{let r=e.get("user");p(r,"identity.role.delete",{});let s=e.req.param("roleId");return s?s==="administrator"||s==="user"?e.text("Cannot delete base roles",403):(await t.deleteRole(s),e.json({message:"Role deleted successfully"})):e.text("Missing role ID",400)}catch(r){let{message:s,status:i}=m(r,"Error deleting role");return e.text(s,i)}}async function ys(e,t){try{let r=e.get("user");p(r,"management.services.get",{});let s=await t.getServices();return e.json(s)}catch(r){let{message:s,status:i}=m(r,"Error getting services");return e.text(s,i)}}async function vs(e,t){try{let r=e.get("user"),s=S(e),{serviceName:i}=s;p(r,"management.service.get",{serviceName:i});let o=await t.getService(i);return o?e.json(o):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error getting service");return e.text(s,i)}}var ws={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 $o=new O;async function Ss(e,t){try{let r=e.get("user"),s=await A(e),i=$o.test(ws,s);if(!i.success)return e.json({error:"Invalid input",details:i.errors},400);if(p(r,"management.service.create",{}),["storage","functions","sites","databases","observability"].includes(s.name.toLowerCase())){let{name:a,...c}=s;await t.registerService(a,c)}else{if(!s.path||!s.port||!s.prefix)return e.json({error:"Custom services require: name, path, port, and prefix"},400);await t.registerService(s)}return e.text("",201)}catch(r){let{message:s,status:i}=m(r,"Error creating service");return e.text(s,i)}}var bs={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 Oo=new O;async function Es(e,t){try{let r=e.get("user"),s=S(e),i=await A(e),o=i.name,n=Oo.test(bs,i);return n.success?(p(r,"management.service.update",{serviceName:o}),o!==s.serviceName?e.json({error:"Service name in body must match path parameter"},400):(await t.updateService(o,i),e.body(null,204))):e.json({error:"Invalid input",details:n.errors},400)}catch(r){let{message:s,status:i}=m(r,"Error updating service");return e.text(s,i)}}async function Cs(e,t){try{let r=e.get("user"),s=S(e),{serviceName:i}=s;return p(r,"management.service.delete",{serviceName:i}),await t.getService(i)?(await t.removeService(i),e.body(null,204)):e.text("Not Found",404)}catch(r){let{message:s,status:i}=m(r,"Error deleting service");return e.text(s,i)}}async function xs(e,t){try{let r=e.get("user"),s=S(e),{serviceName:i}=s;if(p(r,"management.service.start",{serviceName:i}),!await t.getService(i))return e.text("Not Found",404);let n=await t.startService(i);return e.json({serviceName:i,isStarted:n})}catch(r){let{message:s,status:i}=m(r,"Error starting service");return e.text(s,i)}}async function Is(e,t){try{let r=e.get("user"),s=S(e),{serviceName:i}=s;if(p(r,"management.service.stop",{serviceName:i}),!await t.getService(i))return e.text("Not Found",404);let n=await t.stopService(i);return e.json({serviceName:i,isStopped:n})}catch(r){let{message:s,status:i}=m(r,"Error stopping service");return e.text(s,i)}}async function As(e,t){try{let r=e.get("user"),s=S(e),{serviceName:i}=s;if(p(r,"management.service.get",{serviceName:i}),!await t.getService(i))return e.text("Not Found",404);let n=new URL("http://localhost:3005/events");n.searchParams.set("service",i);let a=e.req.query();a.startTime&&n.searchParams.set("startTime",a.startTime),a.endTime&&n.searchParams.set("endTime",a.endTime),a.level&&n.searchParams.set("level",a.level),a.limit&&n.searchParams.set("limit",a.limit),a.offset&&n.searchParams.set("offset",a.offset);let c=await fetch(n.toString());if(!c.ok)throw new Ge(`Observability service error: ${c.statusText}`);let l=await c.json();return e.json({serviceName:i,logs:l.events,count:l.count})}catch(r){let{message:s,status:i}=m(r,"Error getting service logs");return e.text(s,i)}}async function ks(e,t){try{let r=e.get("user"),s=S(e),{serviceName:i}=s;if(p(r,"management.service.start",{serviceName:i}),!await t.getService(i))return e.text("Not Found",404);let n=await t.restartService(i);return e.json({serviceName:i,restarted:n})}catch(r){let{message:s,status:i}=m(r,"Error restarting service");return e.text(s,i)}}function Ts(e,t,r,s,i){let o=e.find(c=>c.service===t);if(!o){let c=new Error(`Function bindings do not include access to service: ${t}`);throw c.cause={statusCode:403},c}if(!o.permissions||o.permissions.length===0)return;for(let c of o.permissions)if(!(c.resource&&c.resource!==r)){if(!c.resource||!c.actions||c.actions.length===0)return;if(c.actions.includes(s)){if(c.targets&&c.targets.length>0){if(!i)return;if(!c.targets.includes(i))continue}return}}let n=i?`:${i}`:"",a=new Error(`Function bindings do not allow: ${t}.${r}.${s}${n}`);throw a.cause={statusCode:403},a}async function B(e,t,r,s,i,o,n){if(!t)return null;let a=e.get("user");if(!a){let l=e.req.header("authorization");if(!l){let f=new Error("Unauthorized: No authentication provided");throw f.cause={statusCode:401},f}let u=l.replace(/^Bearer\s+/i,"");if(a=await t.getUserFromToken(u),!a){let f=new Error("Unauthorized: Invalid token");throw f.cause={statusCode:401},f}}p(a,r,{});let c=e.req.header("x-function-bindings");if(c)try{let l=JSON.parse(c);Ts(l,s,i,o,n)}catch(l){if(l.cause?.statusCode===403)throw l;let u=new Error("Invalid function bindings header");throw u.cause={statusCode:400},u}return a}async function Rs(e,t,r){try{let s=await A(e),i=e.get("requestingIdentity");if(!i)return e.json({error:"Authentication required"},401);let{name:o,description:n,redirectUris:a,metadata:c}=s;if(!o||!a)return e.json({error:"Missing required fields: name and redirectUris are required"},400);await B(e,r,"applications.application.create","applications","application","create",o);let l={name:o,description:n,redirectUris:Array.isArray(a)?a:[a],metadata:c,owners:[i.id]},u=await t.createApplication(l,i.id);return e.json(u,201)}catch(s){let{message:i,status:o}=m(s,"Error creating application");return e.text(i,o)}}async function Ps(e,t,r){try{let s=e.req.param("id"),i=e.get("requestingIdentity");if(!s)return e.json({error:"Application ID is required"},400);await B(e,r,"applications.application.read","applications","application","read",s);let o=await t.getApplication(s,i?.id);return e.json(o,200)}catch(s){let{message:i,status:o}=m(s,"Error retrieving application");return e.text(i,o)}}async function js(e,t,r){try{let s=e.get("requestingIdentity");if(!s)return e.json({error:"Authentication required"},401);await B(e,r,"applications.application.list","applications","application","list");let i=await t.listApplications(s.id);return e.json({applications:i,total:i.length},200)}catch(s){let{message:i,status:o}=m(s,"Error listing applications");return e.text(i,o)}}async function Ls(e,t,r){try{let s=e.req.param("id"),i=await A(e),o=e.get("requestingIdentity");if(!o)return e.json({error:"Authentication required"},401);if(!s)return e.json({error:"Application ID is required"},400);await B(e,r,"applications.application.update","applications","application","update",s);let n=await t.updateApplication(s,i,o.id);return e.json(n,200)}catch(s){let{message:i,status:o}=m(s,"Error updating application");return e.text(i,o)}}async function $s(e,t,r){try{let s=e.req.param("id"),i=e.get("requestingIdentity");return i?s?(await B(e,r,"applications.application.delete","applications","application","delete",s),await t.deleteApplication(s,i.id),e.json({success:!0,message:"Application deleted"},200)):e.json({error:"Application ID is required"},400):e.json({error:"Authentication required"},401)}catch(s){let{message:i,status:o}=m(s,"Error deleting application");return e.text(i,o)}}function Ms(e,t,r){if(r.startsWith("/databases/")){r.includes("/table")||r.includes("/get")?p(e,"databases.table.get",{}):r.includes("/write")||r.includes("/update")||t==="PUT"||t==="PATCH"?p(e,"databases.table.update",{}):r.includes("/delete")||t==="DELETE"?p(e,"databases.table.delete",{}):t==="POST"&&p(e,"databases.table.create",{});return}if(r.startsWith("/functions/")){r.includes("/deploy")||t==="POST"?p(e,"functions.function.create",{}):r.includes("/run/")?p(e,"functions.function.execute",{}):t==="PUT"||t==="PATCH"?p(e,"functions.function.update",{}):t==="DELETE"?p(e,"functions.function.delete",{}):t==="GET"&&p(e,"functions.function.get",{});return}if(r.startsWith("/storage/")){let s=r.match(/^\/storage\/buckets\/[^/]+$/),i=r.includes("/objects");s?t==="POST"?p(e,"storage.bucket.create",{}):t==="PATCH"||t==="PUT"?p(e,"storage.bucket.update",{}):t==="DELETE"?p(e,"storage.bucket.delete",{}):t==="GET"&&p(e,"storage.bucket.get",{}):i||r.includes("/upload")||r.includes("/download")||r.includes("/get")?r.includes("/upload")||t==="POST"?p(e,"storage.object.create",{}):r.includes("/download")||r.includes("/get")?p(e,"storage.object.get",{}):t==="PUT"||t==="PATCH"?p(e,"storage.object.update",{}):t==="DELETE"?p(e,"storage.object.delete",{}):t==="GET"&&p(e,"storage.object.get",{}):t==="GET"&&p(e,"storage.bucket.get",{});return}if(r.startsWith("/sites/")){if(r.match(/^\/sites\/projects\/[^/]+/)&&t==="GET")return;r.includes("/deploy")||t==="POST"?p(e,"sites.site.create",{}):t==="PUT"||t==="PATCH"?p(e,"sites.site.update",{}):t==="DELETE"?p(e,"sites.site.delete",{}):t==="GET"&&p(e,"sites.site.get",{});return}if(r.startsWith("/observability/")){t==="POST"?p(e,"observability.metrics.create",{}):t==="GET"&&p(e,"observability.metrics.get",{});return}}async function Os(e){let{auth:t,db:r,config:s,molnos:i}=e,o=new Ke(t,r,i.initialUser);await o.start();let n=Rt(i.dataPath,"applications"),a=new Ze({dbPath:n});await a.start();let c=Rt(i.dataPath,"management"),l=new Ye({dbPath:c});await l.start();let u=!1,f=Rt(i.dataPath,".runtime-config.json");l.setEnvironmentVariables({IDENTITY_API_URL:`http://${s.host||"localhost"}:${s.port||3e3}`,MOLNOS_RUNTIME_CONFIG:f});let h=new Et;h.use("/*",async(d,E)=>u?d.text("Service Unavailable - Server is shutting down",503):E()),h.use("/*",Rr({origin:d=>d,allowMethods:["GET","POST","PUT","PATCH","DELETE","OPTIONS"],allowHeaders:["Content-Type","Authorization"],exposeHeaders:["Content-Length"],credentials:!0})),h.get("/health",async d=>d.text("OK")),h.post("/auth/login",d=>Gr(d,o,t,a)),h.get("/auth/verify",d=>Kr(d,t,a)),h.post("/auth/refresh",d=>Jr(d,t)),h.post("/management/service",g,d=>Ss(d,l)),h.get("/management/services",g,d=>ys(d,l)),h.get("/management/service/:serviceName",g,d=>vs(d,l)),h.put("/management/service/:serviceName",g,d=>Es(d,l)),h.delete("/management/service/:serviceName",g,d=>Cs(d,l)),h.get("/management/service/:serviceName/start",g,d=>xs(d,l)),h.get("/management/service/:serviceName/stop",g,d=>Is(d,l)),h.get("/management/service/:serviceName/logs",g,d=>As(d,l)),h.get("/management/service/:serviceName/restart",g,d=>ks(d,l)),h.get("/identity/whoami",g,d=>Xr(d)),h.get("/identity/identities",g,d=>Yr(d,o)),h.post("/identity/users",g,d=>Qr(d,o)),h.get("/identity/users",g,d=>es(d,o)),h.get("/identity/users/:userId",g,d=>ts(d,o)),h.patch("/identity/users/:userId",g,d=>ss(d,o)),h.delete("/identity/users/:userId",g,d=>is(d,o)),h.post("/identity/service-accounts",g,d=>os(d,o)),h.get("/identity/service-accounts",g,d=>ns(d,o)),h.get("/identity/service-accounts/:serviceAccountId",g,d=>as(d,o)),h.patch("/identity/service-accounts/:serviceAccountId",g,d=>ls(d,o)),h.delete("/identity/service-accounts/:serviceAccountId",g,d=>us(d,o)),h.post("/identity/service-accounts/:serviceAccountId/rotate-key",g,d=>ds(d,o)),h.post("/identity/roles",g,d=>ps(d,o)),h.get("/identity/roles",g,d=>hs(d,o)),h.get("/identity/roles/:roleId",g,d=>fs(d,o)),h.patch("/identity/roles/:roleId",g,d=>ms(d,o)),h.delete("/identity/roles/:roleId",g,d=>gs(d,o)),h.post("/applications",g,d=>Rs(d,a,o)),h.get("/applications",g,d=>js(d,a,o)),h.get("/applications/:id",g,d=>Ps(d,a,o)),h.patch("/applications/:id",g,d=>Ls(d,a,o)),h.delete("/applications/:id",g,d=>$s(d,a,o)),h.all("/databases/*",g,C,async d=>d.text("Not Found",404)),h.all("/functions/*",C,async d=>d.text("Not Found",404)),h.get("/sites/projects/:projectId/*",C,async d=>d.text("Not Found",404)),h.all("/sites/*",g,C,async d=>d.text("Not Found",404));async function y(d,E){let k=d.req.method,D=new URL(d.req.url).pathname.match(/^\/storage\/buckets\/([^/]+)/);if(D&&(k==="GET"||k==="HEAD")){let P=D[1],j=(await l.getServices()).find(q=>q.name==="storage");if(j?.active)try{let q=await fetch(`http://localhost:${j.port}/buckets/${P}`);if(q.ok&&(await q.json()).public===!0)return E()}catch{}}return g(d,E)}h.all("/storage/*",y,C,async d=>d.text("Not Found",404)),h.all("/observability/*",g,C,async d=>d.text("Not Found",404));async function C(d,E){try{let k=new URL(d.req.url),R=k.pathname,D=k.search,P=d.req.method,$,j=0,q=await l.getServices();for(let F of q)F.active&&R.startsWith(F.prefix)&&F.prefix.length>j&&($=F,j=F.prefix.length);if(!$)return E();let xe=d.get("user");if(!(R.match(/^\/sites\/projects\/[^/]+/)&&P==="GET")&&xe&&Ms(xe,P,R),$.healthCheck&&$.healthCheck.healthy===!1)return d.json({error:"Service unavailable (unhealthy)"},503);let Pt=(R.substring($.prefix.length)||"/")+D;console.log(`Proxying to http://localhost:${$.port}${Pt}`);let U=null;if(["POST","PUT","PATCH","DELETE"].includes(d.req.method))if((d.req.header("content-type")||"").includes("application/json"))try{let z=await d.req.json();U=JSON.stringify(z)}catch{U=null}else try{let z=await d.req.arrayBuffer();U=Buffer.from(z)}catch{U=null}return new Promise(F=>{let z={host:`localhost:${$.port}`};d.req.raw.headers.forEach((V,de)=>{de.toLowerCase()!=="host"&&(z[de]=V)}),U&&(typeof U=="string"?z["content-length"]=Buffer.byteLength(U).toString():z["content-length"]=U.length.toString());let Vs={method:d.req.method,hostname:"localhost",port:$.port,path:Pt,headers:z},Qe=Do.request(Vs,V=>{let de=[];V.on("data",et=>{de.push(et)}),V.on("end",()=>{let et=Buffer.concat(de),jt={};Object.entries(V.headers).forEach(([Ns,Ie])=>{Ie!==void 0&&(jt[Ns]=Array.isArray(Ie)?Ie.join(", "):Ie)}),F(d.body(et,V.statusCode||200,jt))})});Qe.on("error",V=>{console.log("Proxy error:",V.message),F(d.json({error:"Proxy Error",message:V.message},502))}),U&&Qe.write(U),Qe.end()})}catch(k){return I(d,k)}}async function g(d,E){try{let k=d.req.header("authorization");if(!k)return d.text("Unauthorized",401);let R=await o.getUserFromToken(k);return R?(d.set("user",R),d.set("requestingIdentity",R),E()):d.text("Unauthorized",401)}catch(k){return I(d,k)}}function I(d,E){let k=E.message||E,R=E?.cause?.statusCode||400;return d.json({error:k},R)}let T=Hr({fetch:h.fetch,port:s.port||3e3,hostname:s.host||"localhost"});console.log(`Server started on ${s.host||"localhost"}:${s.port||3e3}`);async function H(){if(u){console.log("[Server] Shutdown already in progress...");return}u=!0,console.log("[Server] Initiating graceful shutdown...");try{console.log("[Server] Stopping HTTP server..."),await new Promise((d,E)=>{T.close(k=>{k?E(k):d()})}),console.log("[Server] Stopping managed services..."),await l.shutdown(),console.log("[Server] Closing database connections..."),await r.close(),console.log("[Server] Graceful shutdown complete")}catch(d){throw console.error("[Server] Error during shutdown:",d),d}}return{server:T,shutdown:H,processManager:l,identity:o}}var Uo="molnosid",Bo={name:Uo,length:12,urlSafe:!0},Ds=()=>{let e=Ho(process.env.DEBUG)||!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://127.0.0.1:8000",debug:e},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:e},storage:{databaseDirectory:"molnosdb",encryptionKey:process.env.STORAGE_KEY||"",debug:e},server:{port:Number(process.env.PORT)||3e3,host:process.env.HOST||"localhost",useHttps:!1,useHttp2:!1,sslCert:"",sslKey:"",sslCa:"",allowedDomains:["http://127.0.0.1:8080"],debug:e},molnos:{dataPath:process.env.DATA_PATH||"data",initialUser:{id:process.env.INITIAL_USER_ID||new _().add(Bo),userName:process.env.INITIAL_USER_NAME||"",email:process.env.INITIAL_USER_EMAIL||""}}}};function Ho(e){return e==="true"||e===!0}var v=Ds(),Us={configFilePath:"molnos.config.json",args:process.argv,options:[{flag:"--jwtSecret",path:"auth.jwtSecret",defaultValue:v.auth.jwtSecret},{flag:"--magicLinkExpirySeconds",path:"auth.magicLinkExpirySeconds",defaultValue:v.auth.magicLinkExpirySeconds},{flag:"--jwtExpirySeconds",path:"auth.jwtExpirySeconds",defaultValue:v.auth.jwtExpirySeconds},{flag:"--refreshTokenExpirySeconds",path:"auth.refreshTokenExpirySeconds",defaultValue:v.auth.refreshTokenExpirySeconds},{flag:"--maxActiveSessions",path:"auth.maxActiveSessions",defaultValue:v.auth.maxActiveSessions},{flag:"--consoleUrl",path:"auth.consoleUrl",defaultValue:v.auth.consoleUrl},{flag:"--debug",path:"auth.debug",isFlag:!0,defaultValue:v.auth.debug},{flag:"--emailSubject",path:"email.emailSubject",defaultValue:"Your Secure Login Link"},{flag:"--emailHost",path:"email.host",defaultValue:v.email.host},{flag:"--emailUser",path:"email.user",defaultValue:v.email.user},{flag:"--emailPassword",path:"email.password",defaultValue:v.email.password},{flag:"--emailPort",path:"email.port",defaultValue:v.email.port},{flag:"--emailSecure",path:"email.secure",isFlag:!0,defaultValue:v.email.secure},{flag:"--emailMaxRetries",path:"email.maxRetries",defaultValue:v.email.maxRetries},{flag:"--debug",path:"email.debug",isFlag:!0,defaultValue:v.email.debug},{flag:"--db",path:"storage.databaseDirectory",defaultValue:v.storage.databaseDirectory},{flag:"--encryptionKey",path:"storage.encryptionKey",defaultValue:v.storage.encryptionKey},{flag:"--debug",path:"storage.debug",defaultValue:v.storage.debug},{flag:"--port",path:"server.port",defaultValue:v.server.port},{flag:"--host",path:"server.host",defaultValue:v.server.host},{flag:"--https",path:"server.useHttps",isFlag:!0,defaultValue:v.server.useHttps},{flag:"--http2",path:"server.useHttp2",isFlag:!0,defaultValue:v.server.useHttp2},{flag:"--cert",path:"server.sslCert",defaultValue:v.server.sslCert},{flag:"--key",path:"server.sslKey",defaultValue:v.server.sslKey},{flag:"--ca",path:"server.sslCa",defaultValue:v.server.sslCa},{flag:"--allowed",path:"server.allowedDomains",defaultValue:v.server.allowedDomains,parser:J.array},{flag:"--debug",path:"server.debug",isFlag:!0,defaultValue:v.server.debug},{flag:"--data-path",path:"dataPath",defaultValue:v.molnos.dataPath},{flag:"--initialUserId",path:"molnos.initialUser.id",defaultValue:v.molnos.initialUser.id},{flag:"--initialUserName",path:"molnos.initialUser.userName",defaultValue:v.molnos.initialUser.userName},{flag:"--initialUserEmail",path:"molnos.initialUser.email",defaultValue:v.molnos.initialUser.email}]};function Bs(e){return{...e,auth:{...e.auth,templates:{textVersion:(t,r,s)=>{let i=new URL(t),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`
|
|
116
|
+
${l}
|
|
117
|
+
|
|
118
|
+
${u}
|
|
119
|
+
|
|
120
|
+
${t}
|
|
121
|
+
|
|
122
|
+
${c?"":`For CLI/Terminal users:
|
|
123
|
+
Run: molnos auth verify ${o} ${n}
|
|
124
|
+
`}
|
|
125
|
+
This link expires in ${r} minutes and can only be used once.
|
|
126
|
+
If you didn't request this, please ignore this email.
|
|
127
|
+
`},htmlVersion:(t,r,s)=>{let i=new URL(t),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.",f=c?"":`
|
|
128
|
+
<div style="margin-top: 2rem; padding: 1rem; background-color: #f8f8f8; border-radius: 6px; border-left: 3px solid #3e63dd;">
|
|
129
|
+
<p style="font-size: 0.85rem; font-weight: 600; margin: 0 0 0.5rem 0; color: #202020;">CLI/Terminal Users</p>
|
|
130
|
+
<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>
|
|
131
|
+
<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>
|
|
132
|
+
</div>
|
|
133
|
+
`;return`
|
|
134
|
+
<!DOCTYPE html>
|
|
135
|
+
<html>
|
|
136
|
+
<head>
|
|
137
|
+
<meta charset="utf-8">
|
|
138
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
139
|
+
<title>${l}</title>
|
|
140
|
+
</head>
|
|
141
|
+
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
|
|
142
|
+
<div style="max-width: 600px; margin: 0 auto; padding: 2rem;">
|
|
143
|
+
<h1 style="font-size: 1.5rem; font-weight: 600; margin: 0 0 1rem 0; color: #202020;">${l}</h1>
|
|
144
|
+
<p style="font-size: 0.9rem; line-height: 1.5; margin: 0 0 1.5rem 0; color: #646464;">${u}</p>
|
|
145
|
+
<a href="${t}" 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>
|
|
146
|
+
${f}
|
|
147
|
+
<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>
|
|
148
|
+
</div>
|
|
149
|
+
</body>
|
|
150
|
+
</html>
|
|
151
|
+
`}}}}}function Hs(e){let t=[],r=c=>t.push(c);return e?.email?.host||r("Missing email.host value"),e?.email?.user||r("Missing email.user value"),e?.email?.password||r("Missing email.password value"),e?.molnos?.initialUser?.email||r("Missing molnos.initialUser.email value"),e?.molnos?.dataPath||r("Missing molnos.dataPath value"),{success:t.length===0,errors:t}}import{writeFileSync as Fo,mkdirSync as Vo,existsSync as No}from"node:fs";import{join as _o}from"node:path";function Fs(e){let t=e.molnos.dataPath||"data";No(t)||Vo(t,{recursive:!0});let r=_o(t,".runtime-config.json"),s={molnos:{dataPath:e.molnos.dataPath},server:{host:e.server.host,port:e.server.port},storage:e.storage};return Fo(r,JSON.stringify(s,null,2),"utf-8"),r}async function qo(){let e=zo(),t=Bs(e),r=Hs(t);if(!r.success)throw console.error(`Found configuration validation errors: ${JSON.stringify(r.errors)}`),new _e("Invalid configuration provided. Please see the validation errors and fix these and then retry again.");let s=Fs(t);console.log(`[MolnOS] Runtime configuration written to: ${s}`);let i=t.molnos.dataPath||"data",o=Wo(i,"auth"),n=new me({...t.storage,databaseDirectory:t.storage.databaseDirectory||o});await n.start();let a=new Ht(n),c=new Ft(t.email),l={...t,auth:{...t.auth,appUrl:t.auth.consoleUrl}},u=new Bt(l,c,a),f=await Os({config:t.server,molnos:t.molnos,auth:u,db:n}),h=async y=>{console.log(`
|
|
152
|
+
[MolnOS] Received ${y}, initiating graceful shutdown...`);try{await f.shutdown(),console.log("[MolnOS] Shutdown complete"),process.exit(0)}catch(C){console.error("[MolnOS] Error during shutdown:",C),process.exit(1)}};process.on("SIGINT",()=>h("SIGINT")),process.on("SIGTERM",()=>h("SIGTERM")),process.on("SIGHUP",()=>h("SIGHUP")),process.on("uncaughtException",async y=>{console.error("[MolnOS] Uncaught exception:",y);try{await f.shutdown()}catch{}process.exit(1)}),process.on("unhandledRejection",async(y,C)=>{console.error("[MolnOS] Unhandled rejection at:",C,"reason:",y);try{await f.shutdown()}catch{}process.exit(1)})}function zo(){return new N(Us).get()}qo();export{qo as start};
|