@minejs/server 0.0.5 → 0.0.6

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/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  </div>
9
9
 
10
10
  <div align="center">
11
- <img src="https://img.shields.io/badge/v-0.0.5-black"/>
11
+ <img src="https://img.shields.io/badge/v-0.0.6-black"/>
12
12
  <img src="https://img.shields.io/badge/🔥-@minejs-black"/>
13
13
  <br>
14
14
  <img src="https://img.shields.io/badge/coverage-98.88%25-brightgreen" alt="Test Coverage" />
@@ -48,7 +48,7 @@
48
48
  ```typescript
49
49
  import { server } from '@minejs/server'
50
50
 
51
- const app = server({
51
+ const app = await server({
52
52
  port: 3000,
53
53
  logging: true,
54
54
  routes: [
@@ -68,7 +68,7 @@
68
68
  ```typescript
69
69
  import { server, type AppContext } from '@minejs/server'
70
70
 
71
- const app = server({
71
+ const app = await server({
72
72
  port: 3000,
73
73
  routes: [
74
74
  {
@@ -98,7 +98,7 @@
98
98
  ```typescript
99
99
  import { server, type AppContext } from '@minejs/server'
100
100
 
101
- const app = server({
101
+ const app = await server({
102
102
  port: 3000,
103
103
  routes: [
104
104
  {
@@ -142,7 +142,7 @@
142
142
  await next()
143
143
  }
144
144
 
145
- const app = server({
145
+ const app = await server({
146
146
  port: 3000,
147
147
  routes: [
148
148
  {
@@ -164,7 +164,7 @@
164
164
  ```typescript
165
165
  import { server } from '@minejs/server'
166
166
 
167
- const app = server({
167
+ const app = await server({
168
168
  port: 3000,
169
169
  logging: true,
170
170
  security: {
@@ -196,7 +196,7 @@
196
196
  ```typescript
197
197
  import { server, type AppContext } from '@minejs/server'
198
198
 
199
- const app = server({
199
+ const app = await server({
200
200
  port: 3000,
201
201
  routes: [
202
202
  {
@@ -243,7 +243,7 @@
243
243
  ```typescript
244
244
  import { server } from '@minejs/server'
245
245
 
246
- const app = server({
246
+ const app = await server({
247
247
  port: 3000,
248
248
  static: {
249
249
  path: '/public', // URL prefix
@@ -263,7 +263,7 @@
263
263
  ```typescript
264
264
  import { server, type AppContext } from '@minejs/server'
265
265
 
266
- const app = server({
266
+ const app = await server({
267
267
  port: 3000,
268
268
  database: {
269
269
  connection: './data.db', // SQLite file path
@@ -292,7 +292,7 @@
292
292
  ```typescript
293
293
  import { server, type AppContext } from '@minejs/server'
294
294
 
295
- const app = server({
295
+ const app = await server({
296
296
  port: 3000,
297
297
  routes: [
298
298
  {
@@ -331,7 +331,7 @@
331
331
  ```typescript
332
332
  import { server, type ServerInstance } from '@minejs/server'
333
333
 
334
- const app = server({
334
+ const app = await server({
335
335
  port: 3000,
336
336
  logging: true,
337
337
 
@@ -369,7 +369,7 @@
369
369
  ```typescript
370
370
  import { server, type AppContext, setupAuto, setLanguage } from '@minejs/server'
371
371
 
372
- const app = server({
372
+ const app = await server({
373
373
  port: 3000,
374
374
  i18n: {
375
375
  defaultLanguage: 'en',
@@ -434,7 +434,7 @@
434
434
  ```typescript
435
435
  import { server } from '@minejs/server'
436
436
 
437
- const app = server({
437
+ const app = await server({
438
438
  port: 3000,
439
439
  logging: {
440
440
  level: 'info', // 'debug' | 'info' | 'warn' | 'error'
@@ -453,7 +453,7 @@
453
453
  > Create and configure an HTTP server instance.
454
454
 
455
455
  ```typescript
456
- const app = server({
456
+ const app = await server({
457
457
  port: 3000,
458
458
  hostname: 'localhost',
459
459
  logging: true,
@@ -716,7 +716,7 @@
716
716
  ```typescript
717
717
  import { server, AppError, ValidationError } from '@minejs/server'
718
718
 
719
- const app = server({
719
+ const app = await server({
720
720
  port: 3000,
721
721
  routes: [
722
722
  {
@@ -772,7 +772,7 @@
772
772
  - ### Multiple Databases
773
773
 
774
774
  ```typescript
775
- const app = server({
775
+ const app = await server({
776
776
  port: 3000,
777
777
  database: [
778
778
  { name: 'primary', connection: './primary.db' },
@@ -798,7 +798,7 @@
798
798
  - ### Dynamic Routes
799
799
 
800
800
  ```typescript
801
- const app = server({
801
+ const app = await server({
802
802
  port: 3000,
803
803
  logging: false,
804
804
  routes: [
@@ -821,7 +821,7 @@
821
821
  - ### Error Handling
822
822
 
823
823
  ```typescript
824
- const app = server({
824
+ const app = await server({
825
825
  port: 3000,
826
826
  errorHandler: async (error, context) => {
827
827
  // Custom error handling
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var le=require('@minejs/db'),ge=require('crypto'),path=require('path'),fs=require('fs'),i18n=require('@minejs/i18n');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var le__namespace=/*#__PURE__*/_interopNamespace(le);var ge__default=/*#__PURE__*/_interopDefault(ge);var B=class{constructor(){this.routes=new Map;this.regexRoutes=[];}match(e,t){let n=`${e}:${t}`;if(this.routes.has(n)){let r=this.routes.get(n);return {handler:r.handler,params:{},metadata:r.metadata}}for(let r of this.regexRoutes)if(r.method===e){let i=t.match(r.pattern);if(i){let a=i.groups||{};return {handler:r.handler,params:a,metadata:r.metadata}}}return null}getAll(){let e=Array.from(this.routes.entries()).map(([n,r])=>{let i=n.indexOf(":"),a=n.substring(0,i),l=n.substring(i+1);return {method:a,path:l,handler:r.handler}}),t=this.regexRoutes.map(n=>{let r=n.key.indexOf(":");return {method:n.method,path:n.key.substring(r+1),handler:n.handler}});return [...e,...t]}clear(){this.routes.clear(),this.regexRoutes=[];}remove(e,t){let n=`${e}:${t}`;if(this.routes.has(n))return this.routes.delete(n),true;let r=this.regexRoutes.findIndex(i=>i.key===n);return r>=0?(this.regexRoutes.splice(r,1),true):false}register(e,t,n,r={}){let i=`${e}:${t}`;if(t.includes(":")||t.includes("*")){let a=this.pathToRegex(t),l=this.regexRoutes.findIndex(b=>b.key===i),m={pattern:a,method:e,handler:n,key:i,metadata:r};l>=0?this.regexRoutes[l]=m:this.regexRoutes.push(m);}else this.routes.set(i,{handler:n,metadata:r});}pathToRegex(e){let t=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return t=t.replace(/:(\w+)/g,"(?<$1>[^/]+)"),t=t.replace(/\*/g,".*"),new RegExp(`^${t}$`)}};var V=class{constructor(){this.rateLimitStore=new Map;this.csrfTokens=new Map;this.requestLog=new Map;this.MAX_REQUEST_LOG_SIZE=1e3;}checkRateLimit(e,t,n){let r=Date.now(),i=this.rateLimitStore.get(e);return i?r<i.reset?i.count>=t?false:(i.count++,true):(this.rateLimitStore.set(e,{count:1,reset:r+n}),true):(this.rateLimitStore.set(e,{count:1,reset:r+n}),true)}cleanupRateLimit(){let e=Date.now();for(let[t,n]of this.rateLimitStore.entries())e>n.reset&&this.rateLimitStore.delete(t);}generateCsrfToken(e,t=36e5){let n=ge__default.default.randomBytes(32).toString("hex");return this.csrfTokens.set(n,{sessionId:e,expires:Date.now()+t}),n}validateCsrfToken(e,t){let n=this.csrfTokens.get(e);return n?Date.now()>n.expires?(this.csrfTokens.delete(e),false):n.sessionId===t?(this.csrfTokens.delete(e),true):false:false}cleanupCsrfTokens(){let e=Date.now();for(let[t,n]of this.csrfTokens.entries())e>n.expires&&this.csrfTokens.delete(t);}sanitizeHtml(e){return e?e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;"):""}sanitizeSql(e){return e?e.replace(/\\/g,"\\\\").replace(/;/g,"").replace(/'/g,"''").replace(/"/g,'\\"').replace(/\u0000/g,""):""}logRequest(e,t,n,r,i,a){if(this.requestLog.set(e,{timestamp:new Date().toISOString(),method:t,path:n,ip:r,status:i,duration:a}),this.requestLog.size>this.MAX_REQUEST_LOG_SIZE){let{value:l}=this.requestLog.keys().next()||{value:null};l&&this.requestLog.delete(l);}}getRequestLog(e){return this.requestLog.get(e)}getAllRequestLogs(){return Array.from(this.requestLog.values())}clearAll(){this.rateLimitStore.clear(),this.csrfTokens.clear(),this.requestLog.clear();}getStats(){return {rateLimitEntries:this.rateLimitStore.size,csrfTokens:this.csrfTokens.size,requestLogs:this.requestLog.size}}};var J=class o{constructor(e="info",t=false,n=""){this.level=1;this.pretty=false;this.prefix="";this.levels={debug:0,info:1,warn:2,error:3,fatal:4};this.colors={reset:"\x1B[0m",gray:"\x1B[90m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",magenta:"\x1B[35m",bold:"\x1B[1m"};this.level=this.levels[e]??1,this.pretty=t,this.prefix=n;}debug(e,t){this.log("debug",this.levels.debug,e,t);}info(e,t){this.log("info",this.levels.info,e,t);}warn(e,t){this.log("warn",this.levels.warn,e,t);}error(e,t){this.log("error",this.levels.error,e,t);}fatal(e,t){this.log("fatal",this.levels.fatal,e,t),process.env.NODE_ENV;}child(e){let t=this.prefix?`${this.prefix}:${e}`:e,n=Object.keys(this.levels).find(r=>this.levels[r]===this.level)||"info";return new o(n,this.pretty,t)}log(e,t,n,r){if(t<this.level)return;let i,a;if(typeof n=="string"?(a=n,i={}):(i=n??{},a=r),this.prefix&&a?a=`[${this.prefix}] ${a}`:this.prefix&&(a=`[${this.prefix}]`),this.pretty)this.prettyLog(e,i,a);else {let m={timestamp:new Date().toISOString(),level:e.toUpperCase(),message:a||"No message",...i},b=JSON.stringify(m);e==="error"||e==="fatal"?console.error(b):e==="warn"?console.warn(b):console.log(b);}}prettyLog(e,t,n){let r=this.colors,i=new Date().toLocaleTimeString("en-US",{hour12:false}),a="method"in t&&"path"in t,l=a&&"status"in t&&"duration"in t,m="name"in t,b="url"in t;if(l){let R=this.colorizeMethod(t.method),u=this.colorizeStatus(t.status),g=t.duration?`${t.duration}ms`:"",y=t.path;console.log(`${r.gray}${i}${r.reset} ${R} ${r.bold}${y}${r.reset} ${u} ${r.gray}${g}${r.reset}`);return}if(n==="Route added"&&a){let R=Array.isArray(t.method)?t.method.join("|"):t.method;console.log(`${r.gray}${i}${r.reset} ${r.cyan}\u2192${r.reset} ${r.bold}${R.padEnd(6)}${r.reset} ${t.path}`);return}if(n==="\u2714 Database connected"&&m){console.log(`${r.gray}${i}${r.reset} ${r.green}\u2713${r.reset} Database connected ${r.gray}(${t.name})${r.reset}`);return}if(n==="Server started"&&b){console.log(`${r.gray}${i}${r.reset} ${r.green}\u2713${r.reset} Server started at ${r.cyan}${t.url}${r.reset}`);return}let v=this.getLevelIcon(e),f=this.getLevelColor(e),D=`${r.gray}${i}${r.reset} ${f}${v}${r.reset} `;n&&(D+=`${n} `);let q=Object.keys(t).filter(R=>!["timestamp","level","message"].includes(R));if(q.length>0){let R=q.map(u=>{let g=t[u];return typeof g=="string"||typeof g=="number"?`${r.gray}${u}:${r.reset}${g}`:null}).filter(Boolean);R.length>0&&(D+=r.gray+R.join(" ")+r.reset);}console.log(D);}colorizeMethod(e){let t=this.colors,n=e.toUpperCase();switch(n){case "GET":return `${t.green}${n}${t.reset}`;case "POST":return `${t.cyan}${n}${t.reset}`;case "PUT":return `${t.yellow}${n}${t.reset}`;case "DELETE":return `${t.red}${n}${t.reset}`;case "PATCH":return `${t.magenta}${n}${t.reset}`;default:return `${t.gray}${n}${t.reset}`}}colorizeStatus(e){if(!e)return "";let t=this.colors,n=e.toString();return e>=200&&e<300?`${t.green}${n}${t.reset}`:e>=300&&e<400?`${t.cyan}${n}${t.reset}`:e>=400&&e<500?`${t.yellow}${n}${t.reset}`:e>=500?`${t.red}${n}${t.reset}`:`${t.gray}${n}${t.reset}`}getLevelIcon(e){switch(e){case "debug":return "\u25CF";case "info":return "\u25CF";case "warn":return "\u26A0";case "error":return "\u2716";case "fatal":return "\u2716";default:return "\u25CF"}}getLevelColor(e){let t=this.colors;switch(e){case "debug":return t.gray;case "info":return t.cyan;case "warn":return t.yellow;case "error":return t.red;case "fatal":return t.red+t.bold;default:return t.reset}}};var P=class extends Error{constructor(t,n=500,r){super(t);this.message=t;this.statusCode=n;this.code=r;this.name="AppError";}},I=class extends P{constructor(t,n){super(t,400,"VALIDATION_ERROR");this.issues=n;this.name="ValidationError";}},se=class extends P{constructor(e){super(e,500,"DATABASE_ERROR"),this.name="DatabaseError";}},X=class extends P{constructor(e="Request timeout"){super(e,408,"TIMEOUT_ERROR"),this.name="TimeoutError";}},oe=class extends P{constructor(e="Too many requests"){super(e,429,"RATE_LIMIT_ERROR"),this.name="RateLimitError";}};var O=class{constructor(e){this.fileCache=new Map;this.CACHE_MAX_SIZE=1e3;if(!fs.existsSync(e.directory))throw new Error(`Static directory does not exist: ${e.directory}`);if(!fs.statSync(e.directory).isDirectory())throw new Error(`Static path is not a directory: ${e.directory}`);this.resolvedDir=path.resolve(e.directory),this.config={path:e.path,directory:e.directory,maxAge:e.maxAge??3600,index:e.index??["index.html"],dotfiles:e.dotfiles??"deny",etag:e.etag??true,lastModified:e.lastModified??true,immutable:e.immutable??false,extensions:e.extensions??[],fallthrough:e.fallthrough??false,setHeaders:e.setHeaders};}handler(){return async e=>{let t=e.request.url,r=new URL(t).pathname;r.startsWith(this.config.path)&&(r=r.slice(this.config.path.length));try{r=decodeURIComponent(r);}catch{return e.json({error:"Invalid URL encoding"},400)}if(r.includes("..")||r.includes("\\"))return e.json({error:"Forbidden"},403);if(this.config.dotfiles!=="allow"&&r.split("/").some(l=>l.startsWith(".")))return this.config.dotfiles==="deny"?e.json({error:"Forbidden"},403):this.handleNotFound(e);let i=this.resolveFilePath(r);if(!i)return this.handleNotFound(e);if(!this.isPathSafe(i))return e.json({error:"Forbidden"},403);if(!fs.existsSync(i))return this.handleNotFound(e);let a=fs.statSync(i);return a.isDirectory()?this.serveDirectory(e,i,r):this.serveFile(e,i,a)}}getPathPattern(){return `${this.config.path}/*`}resolveFilePath(e){e.startsWith("/")&&(e=e.slice(1));let t=path.join(this.resolvedDir,e);if(!fs.existsSync(t)&&this.config.extensions.length>0)for(let n of this.config.extensions){let r=`${t}.${n}`;if(fs.existsSync(r))return r}return t}isPathSafe(e){return !path.relative(this.resolvedDir,path.resolve(e)).startsWith("..")&&!path.resolve(e).startsWith("..")}async serveDirectory(e,t,n){for(let r of this.config.index){let i=path.join(t,r);if(fs.existsSync(i)){let a=fs.statSync(i);if(a.isFile())return this.serveFile(e,i,a)}}return this.handleNotFound(e)}async serveFile(e,t,n){let r=e.request.method.toUpperCase();if(r!=="GET"&&r!=="HEAD")return e.json({error:"Method not allowed"},405);let i=t,a=this.fileCache.get(i);if(a&&a.mtime!==n.mtimeMs&&(a=void 0),!a){if(a={etag:this.generateEtag(n),lastModified:new Date(n.mtime),size:n.size,mtime:n.mtimeMs},this.fileCache.size>=this.CACHE_MAX_SIZE){let f=this.fileCache.keys().next().value;f&&this.fileCache.delete(f);}this.fileCache.set(i,a);}let l=e.request.headers.get("if-none-match"),m=e.request.headers.get("if-modified-since");if(this.config.etag&&l===a.etag)return new Response(null,{status:304,headers:this.buildHeaders(t,a)});if(this.config.lastModified&&m){let f=new Date(m);if(a.lastModified<=f)return new Response(null,{status:304,headers:this.buildHeaders(t,a)})}let b=Bun.file(t),v=this.buildHeaders(t,a);return this.config.setHeaders&&this.config.setHeaders(e,t),r==="HEAD"?new Response(null,{status:200,headers:v}):new Response(b,{status:200,headers:v})}buildHeaders(e,t){let n=new Headers,r=this.getMimeType(e);if(n.set("Content-Type",r),n.set("Content-Length",t.size.toString()),this.config.etag&&n.set("ETag",t.etag),this.config.lastModified&&n.set("Last-Modified",t.lastModified.toUTCString()),this.config.maxAge>0){let i=`public, max-age=${this.config.maxAge}`;this.config.immutable&&(i+=", immutable"),n.set("Cache-Control",i);}else n.set("Cache-Control","no-cache");return n.set("Accept-Ranges","bytes"),n}generateEtag(e){return `"${e.size.toString(16)}-${e.mtimeMs.toString(16)}"`}getMimeType(e){let t=path.extname(e).toLowerCase();return be[t]||"application/octet-stream"}handleNotFound(e){return this.config.fallthrough?e.json({error:"Not Found"},404):e.json({error:"Not Found"},404)}clearCache(){this.fileCache.clear();}getCacheStats(){return {entries:this.fileCache.size,maxSize:this.CACHE_MAX_SIZE}}};function ye(o){return new O(o)}var be={".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".txt":"text/plain; charset=utf-8",".xml":"text/xml; charset=utf-8",".csv":"text/csv; charset=utf-8",".md":"text/markdown; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".jsonld":"application/ld+json",".map":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".ico":"image/x-icon",".webp":"image/webp",".avif":"image/avif",".bmp":"image/bmp",".tiff":"image/tiff",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".mp3":"audio/mpeg",".wav":"audio/wav",".ogg":"audio/ogg",".m4a":"audio/mp4",".aac":"audio/aac",".flac":"audio/flac",".mp4":"video/mp4",".webm":"video/webm",".ogv":"video/ogg",".mov":"video/quicktime",".avi":"video/x-msvideo",".mkv":"video/x-matroska",".pdf":"application/pdf",".doc":"application/msword",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xls":"application/vnd.ms-excel",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".ppt":"application/vnd.ms-powerpoint",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",".zip":"application/zip",".rar":"application/x-rar-compressed",".7z":"application/x-7z-compressed",".tar":"application/x-tar",".gz":"application/gzip",".wasm":"application/wasm",".manifest":"text/cache-manifest",".webmanifest":"application/manifest+json"};var W=new V,k=new B;function xe(o={}){let e=Number(o.port)||3e3,t=o.hostname||"localhost",n=o.maxRequestSize||10*1024*1024,r=o.requestTimeout||3e4,i=o.gracefulShutdownTimeout||1e4,a=typeof o.logging=="object"?o.logging:{},l=o.logging?new J(a.level||"info",a.pretty):null,m=null;o.i18n&&(m=i18n.getI18n());let b=new Map,v=[],f=new Set,D=[],q=setInterval(()=>{W.cleanupRateLimit(),W.cleanupCsrfTokens();},120*1e3);async function R(s,c){let p=Date.now(),d=crypto.randomUUID(),x=new URL(s.url).pathname,E=s.method.toUpperCase(),$=Ce(s,c);f.add(d);try{let C=s.headers.get("content-length");if(C&&parseInt(C)>n)return l?.warn({requestId:d,size:C,ip:$},"Request too large"),new Response(JSON.stringify({error:"Payload too large"}),{status:413,headers:{"Content-Type":"application/json"}});let j=ve(s,o);if(E==="OPTIONS")return new Response(null,{status:204,headers:j});if(o.security&&typeof o.security=="object"&&o.security.rateLimit){let L=typeof o.security.rateLimit=="object"?o.security.rateLimit:{},H=L.max||100,Z=L.windowMs||6e4,ne=L.keyGenerator?L.keyGenerator({request:s,ip:$}):$;if(!W.checkRateLimit(ne,H,Z))return l?.warn({requestId:d,ip:$,key:ne},"Rate limit exceeded"),new Response(JSON.stringify({error:L.message||"Too many requests"}),{status:429,headers:{"Content-Type":"application/json"}})}let w=null;["POST","PUT","PATCH"].includes(E)&&(w=await Re(s,l,n));let T=b.get("default"),A=Object.fromEntries(new URL(s.url).searchParams),ue=s.headers.get("cookie")||"",de=ce(ue).get("lang"),z=A.lang||de||s.headers.get("Accept-Language")?.split(",")[0]?.split("-")[0]||"en";m&&!m.getSupportedLanguages().includes(z)&&(z=m.getLanguage()),m&&m.setLanguage(z);let N=k.match(E,x);if(!N){let L=ae($,s,{},T,l,d,m,z);if(l?.warn({requestId:d,method:E,path:x,ip:$},"Route not found"),o.onError)try{return await o.onError(404,x,E)}catch(H){l?.error({error:String(H),requestId:d},"Error in onError handler");}return L.json({error:"Not Found",path:x},404)}let G=ae($,s,N.params||{},T,l,d,m,z);G.body=w,G.request=s;let ee=new AbortController,pe=new Promise((L,H)=>{let Z=setTimeout(()=>{ee.abort(),H(new X("Request timeout"));},r);ee.signal.addEventListener("abort",()=>clearTimeout(Z));}),te=N.metadata?.middlewares||[],K;te.length>0?K=u(G,te,N.handler):K=Promise.resolve(N.handler(G));let F=await Promise.race([K,pe]),M=new Headers(F.headers);j.forEach((L,H)=>{M.has(H)||M.set(H,L);}),M.set("X-Request-ID",d),M.set("X-Content-Type-Options","nosniff"),M.set("X-Frame-Options","DENY"),M.set("X-XSS-Protection","1; mode=block"),M.set("Referrer-Policy","strict-origin-when-cross-origin");let re=Date.now()-p;return W.logRequest(d,E,x,$,F.status,re),l?.info({requestId:d,method:E,path:x,status:F.status,duration:re,ip:$},"Request completed"),new Response(F.body,{status:F.status,headers:M})}catch(C){if(C instanceof P){if(l?.warn({error:C.message,requestId:d,ip:$},`App error: ${C.message}`),o.onError)try{return await o.onError(C.statusCode,x,E)}catch(w){l?.error({error:String(w),requestId:d},"Error in onError handler");}return new Response(JSON.stringify({error:C.message,code:C.code,requestId:d}),{status:C.statusCode,headers:{"Content-Type":"application/json"}})}l?.error({error:String(C),requestId:d,ip:$},"Unhandled error");let j=process.env.NODE_ENV==="production"?"Internal Server Error":C.message;if(o.onError)try{return await o.onError(500,x,E)}catch(w){l?.error({error:String(w),requestId:d},"Error in onError handler");}return new Response(JSON.stringify({error:j,requestId:d}),{status:500,headers:{"Content-Type":"application/json"}})}finally{f.delete(d);}}async function u(s,c,p){let d=0,h=null,x=s.json.bind(s),E=s.text.bind(s),$=s.html.bind(s),C=s.redirect.bind(s);s.json=function(w,T){let A=x(w,T);return h=A,A},s.text=function(w,T){let A=E(w,T);return h=A,A},s.html=function(w,T){let A=$(w,T);return h=A,A},s.redirect=function(w,T){let A=C(w,T);return h=A,A};async function j(){if(!h&&d<c.length){let w=c[d];d++,await w(s,j);}}return await j(),s.json=x,s.text=E,s.html=$,s.redirect=C,h||p(s)}let g={method:"GET",path:"/health",handler:s=>s.json({status:"healthy",timestamp:new Date().toISOString(),uptime:process.uptime(),activeRequests:f.size})},y={method:"GET",path:"/readiness",handler:s=>{let c=b.size>0,p=c||b.size===0;return s.json({ready:p,checks:{database:c?"connected":"not configured",activeRequests:f.size},timestamp:new Date().toISOString()},p?200:503)}};if(o.routes&&o.routes.forEach(s=>{v.push(s),(Array.isArray(s.method)?s.method:[s.method]).forEach(p=>{k.register(p,s.path,s.handler,s);});}),o.static){let s=Array.isArray(o.static)?o.static:[o.static];for(let c of s)try{let d=new O(c).handler(),h={method:"GET",path:c.path==="/"?"/*":`${c.path}/*`,handler:d};v.push(h);let x=c.path==="/"?"/":c.path;D.push({prefix:x,handler:d}),c.path==="/"?(k.register("GET","/",d,h),k.register("HEAD","/",d,h),k.register("GET","/*",d,h),k.register("HEAD","/*",d,h)):(k.register("GET",`${c.path}/*`,d,h),k.register("HEAD",`${c.path}/*`,d,h));}catch(p){throw l?.error({error:String(p),path:c.path},"Failed to initialize static file server"),p}}v.push(g,y),k.register("GET","/health",g.handler,g),k.register("GET","/readiness",y.handler,y);let S=null,U={app:null,logger:l,db:b,bunServer:null,async start(){if(m&&await m.init(),o.database){let c=Array.isArray(o.database)?o.database:[o.database];for(let p of c){let d=p.name||"default";try{if(typeof p.connection=="string"){let h=new le__namespace.DB(p.connection);if(p.schema&&typeof p.schema=="object")for(let[,x]of Object.entries(p.schema))x&&typeof x=="object"&&h.defineSchema(x);b.set(d,h),l?.info({name:d,connection:p.connection},"\u2714 Database connected");}else throw new Error(`Database connection must be a string path (got ${typeof p.connection})`)}catch(h){throw l?.error({error:String(h),name:d},"Failed to connect to database"),h}}}S=Bun.serve({port:e,hostname:t,fetch:(c,p)=>R(c,p)}),U.bunServer=S;let s=`http://${t}:${e}`;if(l?.info({url:s},"\u2714 Server started"),o.onStartup)try{await o.onStartup(U);}catch(c){l?.error({error:String(c)},"Error in startup handler");}if(o.onReady)try{await o.onReady(U,b);}catch(c){l?.error({error:String(c)},"Error in ready handler");}},async stop(){if(l?.info("Stopping server..."),f.size>0){l?.info({count:f.size},"Waiting for active requests...");let s=Date.now()+i;for(;f.size>0&&Date.now()<s;)await new Promise(c=>setTimeout(c,100));f.size>0&&l?.warn({count:f.size},"Force closing with active requests");}if(clearInterval(q),o.onShutdown)try{await o.onShutdown();}catch(s){l?.error({error:String(s)},"Error in shutdown handler");}for(let[s,c]of b.entries())try{c&&typeof c.close=="function"&&c.close(),l?.info({name:s},"Database closed");}catch(p){l?.error({error:String(p),name:s},"Error closing database");}S&&typeof S.stop=="function"&&(S.stop(),l?.info("Bun server stopped")),l?.info("Server stopped successfully");},addRoute(s){v.push(s),(Array.isArray(s.method)?s.method:[s.method]).forEach(p=>{k.register(p,s.path,s.handler,s);}),l?.info({method:s.method,path:s.path},"Route added");},addRoutes(s){s.forEach(c=>this.addRoute(c));},getRoutes(){return v}};return U}async function Re(o,e,t){let n=o.headers.get("content-type")||"";try{if(n.includes("application/json")){let r=await o.text();if(r.length>t)throw new I("Payload too large");if(!r.trim())return {};try{return JSON.parse(r)}catch(i){throw e?.warn({error:String(i),bodyPreview:r.substring(0,100)},"Invalid JSON in request body"),new I("Invalid JSON in request body")}}if(n.includes("application/x-www-form-urlencoded")){let r=await o.text();if(r.length>t)throw new I("Payload too large");return Object.fromEntries(new URLSearchParams(r))}if(n.includes("multipart/form-data"))return await o.formData()}catch(r){throw r instanceof I?r:(e?.error({error:String(r)},"Error parsing request body"),new I("Failed to parse request body"))}return {}}function ce(o){let e=new Map;if(!o)return e;let t=o.split(";");for(let n of t){let[r,...i]=n.trim().split("=");if(r){let a=i.join("=");e.set(r,a?decodeURIComponent(a):"");}}return e}function ae(o,e,t,n,r,i,a=null,l="en"){let m=new URL(e.url),b=Object.fromEntries(m.searchParams),v=e.headers,f=200,D=new Map,q=ce(v.get("cookie")||""),R={ip:o,request:e,params:t,query:b,headers:v,db:n,logger:r,i18n:a,lang:l,requestId:i,get statusCode(){return f},set statusCode(u){f=u;},body:null,state:{},json(u,g){return new Response(JSON.stringify(u),{status:g??f,headers:{"Content-Type":"application/json",...this._setCookieHeaders()}})},text(u,g){return new Response(u,{status:g??f,headers:{"Content-Type":"text/plain",...this._setCookieHeaders()}})},html(u,g){return new Response(u,{status:g??f,headers:{"Content-Type":"text/html; charset=utf-8",...this._setCookieHeaders()}})},redirect(u,g=302){return new Response(null,{status:g,headers:{Location:u,...this._setCookieHeaders()}})},file(u,g="application/octet-stream"){let y=Bun.file(u);return new Response(y,{headers:{"Content-Type":g,...this._setCookieHeaders()}})},setCookie(u,g,y={}){let S=`${u}=${encodeURIComponent(g)}`;return y.maxAge!==void 0&&(S+=`; Max-Age=${y.maxAge}`),y.expires&&(S+=`; Expires=${y.expires.toUTCString()}`),y.path&&(S+=`; Path=${y.path}`),y.domain&&(S+=`; Domain=${y.domain}`),y.secure&&(S+="; Secure"),y.httpOnly&&(S+="; HttpOnly"),y.sameSite&&(S+=`; SameSite=${y.sameSite}`),D.set(u,S),R},getCookie(u){return q.get(u)},deleteCookie(u,g={}){return R.setCookie(u,"",{...g,maxAge:0,path:g.path||"/"})},setHeader(u,g){return v.set(u,g),R},getHeader(u){return v.get(u)||void 0},status(u){return f=u,R},_setCookieHeaders(){let u={};return D.size>0&&(u["Set-Cookie"]=Array.from(D.values())),u}};return R}function Ce(o,e){let t=o.headers.get("x-forwarded-for");if(t)return t.split(",").map(i=>i.trim())[0]||"unknown";let n=o.headers.get("x-real-ip");if(n)return n;if(e)try{let i=e.requestIP?.(o);if(i?.address)return i.address}catch{}return "unknown"}function ve(o,e){let t=new Headers;if(!e.security||typeof e.security!="object"||!e.security.cors)return t;let n=typeof e.security.cors=="object"?e.security.cors:{},r=o.headers.get("Origin");if(r){typeof n.origin=="function"?n.origin(r)&&t.set("Access-Control-Allow-Origin",r):Array.isArray(n.origin)?n.origin.includes(r)&&t.set("Access-Control-Allow-Origin",r):typeof n.origin=="string"?t.set("Access-Control-Allow-Origin",n.origin):t.set("Access-Control-Allow-Origin",r);let i=n.methods||["GET","POST","PUT","DELETE","PATCH","OPTIONS"];t.set("Access-Control-Allow-Methods",i.join(", "));let a=n.allowedHeaders||["Content-Type","Authorization","X-Requested-With"];t.set("Access-Control-Allow-Headers",a.join(", ")),n.credentials&&t.set("Access-Control-Allow-Credentials","true"),n.maxAge&&t.set("Access-Control-Max-Age",n.maxAge.toString());}return t}var ze=xe;
2
- Object.defineProperty(exports,"DB",{enumerable:true,get:function(){return le.DB}});Object.defineProperty(exports,"blob",{enumerable:true,get:function(){return le.blob}});Object.defineProperty(exports,"column",{enumerable:true,get:function(){return le.column}});Object.defineProperty(exports,"defaultValue",{enumerable:true,get:function(){return le.defaultValue}});Object.defineProperty(exports,"index",{enumerable:true,get:function(){return le.index}});Object.defineProperty(exports,"integer",{enumerable:true,get:function(){return le.integer}});Object.defineProperty(exports,"notNull",{enumerable:true,get:function(){return le.notNull}});Object.defineProperty(exports,"numeric",{enumerable:true,get:function(){return le.numeric}});Object.defineProperty(exports,"primaryKey",{enumerable:true,get:function(){return le.primaryKey}});Object.defineProperty(exports,"real",{enumerable:true,get:function(){return le.real}});Object.defineProperty(exports,"references",{enumerable:true,get:function(){return le.references}});Object.defineProperty(exports,"table",{enumerable:true,get:function(){return le.table}});Object.defineProperty(exports,"text",{enumerable:true,get:function(){return le.text}});Object.defineProperty(exports,"unique",{enumerable:true,get:function(){return le.unique}});Object.defineProperty(exports,"I18nManager",{enumerable:true,get:function(){return i18n.I18nManager}});Object.defineProperty(exports,"LazyLoader",{enumerable:true,get:function(){return i18n.LazyLoader}});Object.defineProperty(exports,"fetchTranslations",{enumerable:true,get:function(){return i18n.fetchTranslations}});Object.defineProperty(exports,"getI18n",{enumerable:true,get:function(){return i18n.getI18n}});Object.defineProperty(exports,"getLanguage",{enumerable:true,get:function(){return i18n.getLanguage}});Object.defineProperty(exports,"getSupportedLanguages",{enumerable:true,get:function(){return i18n.getSupportedLanguages}});Object.defineProperty(exports,"loadLanguage",{enumerable:true,get:function(){return i18n.loadLanguage}});Object.defineProperty(exports,"loadTranslations",{enumerable:true,get:function(){return i18n.loadTranslations}});Object.defineProperty(exports,"setLanguage",{enumerable:true,get:function(){return i18n.setLanguage}});Object.defineProperty(exports,"setupAuto",{enumerable:true,get:function(){return i18n.setupAuto}});Object.defineProperty(exports,"setupI18n",{enumerable:true,get:function(){return i18n.setupI18n}});Object.defineProperty(exports,"setupLazy",{enumerable:true,get:function(){return i18n.setupLazy}});Object.defineProperty(exports,"t",{enumerable:true,get:function(){return i18n.t}});Object.defineProperty(exports,"tLang",{enumerable:true,get:function(){return i18n.tLang}});Object.defineProperty(exports,"tParse",{enumerable:true,get:function(){return i18n.tParse}});exports.AppError=P;exports.DatabaseError=se;exports.Logger=J;exports.RateLimitError=oe;exports.Router=B;exports.SecurityManager=V;exports.StaticFileServer=O;exports.TimeoutError=X;exports.ValidationError=I;exports.createStatic=ye;exports.default=ze;exports.server=xe;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var le=require('@minejs/db'),ge=require('crypto'),path=require('path'),fs=require('fs'),i18n=require('@minejs/i18n');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var le__namespace=/*#__PURE__*/_interopNamespace(le);var ge__default=/*#__PURE__*/_interopDefault(ge);var B=class{constructor(){this.routes=new Map;this.regexRoutes=[];}match(e,t){let n=`${e}:${t}`;if(this.routes.has(n)){let r=this.routes.get(n);return {handler:r.handler,params:{},metadata:r.metadata}}for(let r of this.regexRoutes)if(r.method===e){let i=t.match(r.pattern);if(i){let a=i.groups||{};return {handler:r.handler,params:a,metadata:r.metadata}}}return null}getAll(){let e=Array.from(this.routes.entries()).map(([n,r])=>{let i=n.indexOf(":"),a=n.substring(0,i),l=n.substring(i+1);return {method:a,path:l,handler:r.handler}}),t=this.regexRoutes.map(n=>{let r=n.key.indexOf(":");return {method:n.method,path:n.key.substring(r+1),handler:n.handler}});return [...e,...t]}clear(){this.routes.clear(),this.regexRoutes=[];}remove(e,t){let n=`${e}:${t}`;if(this.routes.has(n))return this.routes.delete(n),true;let r=this.regexRoutes.findIndex(i=>i.key===n);return r>=0?(this.regexRoutes.splice(r,1),true):false}register(e,t,n,r={}){let i=`${e}:${t}`;if(t.includes(":")||t.includes("*")){let a=this.pathToRegex(t),l=this.regexRoutes.findIndex(b=>b.key===i),h={pattern:a,method:e,handler:n,key:i,metadata:r};l>=0?this.regexRoutes[l]=h:this.regexRoutes.push(h);}else this.routes.set(i,{handler:n,metadata:r});}pathToRegex(e){let t=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return t=t.replace(/:(\w+)/g,"(?<$1>[^/]+)"),t=t.replace(/\*/g,".*"),new RegExp(`^${t}$`)}};var V=class{constructor(){this.rateLimitStore=new Map;this.csrfTokens=new Map;this.requestLog=new Map;this.MAX_REQUEST_LOG_SIZE=1e3;}checkRateLimit(e,t,n){let r=Date.now(),i=this.rateLimitStore.get(e);return i?r<i.reset?i.count>=t?false:(i.count++,true):(this.rateLimitStore.set(e,{count:1,reset:r+n}),true):(this.rateLimitStore.set(e,{count:1,reset:r+n}),true)}cleanupRateLimit(){let e=Date.now();for(let[t,n]of this.rateLimitStore.entries())e>n.reset&&this.rateLimitStore.delete(t);}generateCsrfToken(e,t=36e5){let n=ge__default.default.randomBytes(32).toString("hex");return this.csrfTokens.set(n,{sessionId:e,expires:Date.now()+t}),n}validateCsrfToken(e,t){let n=this.csrfTokens.get(e);return n?Date.now()>n.expires?(this.csrfTokens.delete(e),false):n.sessionId===t?(this.csrfTokens.delete(e),true):false:false}cleanupCsrfTokens(){let e=Date.now();for(let[t,n]of this.csrfTokens.entries())e>n.expires&&this.csrfTokens.delete(t);}sanitizeHtml(e){return e?e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;"):""}sanitizeSql(e){return e?e.replace(/\\/g,"\\\\").replace(/;/g,"").replace(/'/g,"''").replace(/"/g,'\\"').replace(/\u0000/g,""):""}logRequest(e,t,n,r,i,a){if(this.requestLog.set(e,{timestamp:new Date().toISOString(),method:t,path:n,ip:r,status:i,duration:a}),this.requestLog.size>this.MAX_REQUEST_LOG_SIZE){let{value:l}=this.requestLog.keys().next()||{value:null};l&&this.requestLog.delete(l);}}getRequestLog(e){return this.requestLog.get(e)}getAllRequestLogs(){return Array.from(this.requestLog.values())}clearAll(){this.rateLimitStore.clear(),this.csrfTokens.clear(),this.requestLog.clear();}getStats(){return {rateLimitEntries:this.rateLimitStore.size,csrfTokens:this.csrfTokens.size,requestLogs:this.requestLog.size}}};var J=class s{constructor(e="info",t=false,n=""){this.level=1;this.pretty=false;this.prefix="";this.levels={debug:0,info:1,warn:2,error:3,fatal:4};this.colors={reset:"\x1B[0m",gray:"\x1B[90m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",magenta:"\x1B[35m",bold:"\x1B[1m"};this.level=this.levels[e]??1,this.pretty=t,this.prefix=n;}debug(e,t){this.log("debug",this.levels.debug,e,t);}info(e,t){this.log("info",this.levels.info,e,t);}warn(e,t){this.log("warn",this.levels.warn,e,t);}error(e,t){this.log("error",this.levels.error,e,t);}fatal(e,t){this.log("fatal",this.levels.fatal,e,t),process.env.NODE_ENV;}child(e){let t=this.prefix?`${this.prefix}:${e}`:e,n=Object.keys(this.levels).find(r=>this.levels[r]===this.level)||"info";return new s(n,this.pretty,t)}log(e,t,n,r){if(t<this.level)return;let i,a;if(typeof n=="string"?(a=n,i={}):(i=n??{},a=r),this.prefix&&a?a=`[${this.prefix}] ${a}`:this.prefix&&(a=`[${this.prefix}]`),this.pretty)this.prettyLog(e,i,a);else {let h={timestamp:new Date().toISOString(),level:e.toUpperCase(),message:a||"No message",...i},b=JSON.stringify(h);e==="error"||e==="fatal"?console.error(b):e==="warn"?console.warn(b):console.log(b);}}prettyLog(e,t,n){let r=this.colors,i=new Date().toLocaleTimeString("en-US",{hour12:false}),a="method"in t&&"path"in t,l=a&&"status"in t&&"duration"in t,h="name"in t,b="url"in t;if(l){let R=this.colorizeMethod(t.method),u=this.colorizeStatus(t.status),g=t.duration?`${t.duration}ms`:"",y=t.path;console.log(`${r.gray}${i}${r.reset} ${R} ${r.bold}${y}${r.reset} ${u} ${r.gray}${g}${r.reset}`);return}if(n==="Route added"&&a){let R=Array.isArray(t.method)?t.method.join("|"):t.method;console.log(`${r.gray}${i}${r.reset} ${r.cyan}\u2192${r.reset} ${r.bold}${R.padEnd(6)}${r.reset} ${t.path}`);return}if(n==="\u2714 Database connected"&&h){console.log(`${r.gray}${i}${r.reset} ${r.green}\u2713${r.reset} Database connected ${r.gray}(${t.name})${r.reset}`);return}if(n==="Server started"&&b){console.log(`${r.gray}${i}${r.reset} ${r.green}\u2713${r.reset} Server started at ${r.cyan}${t.url}${r.reset}`);return}let v=this.getLevelIcon(e),f=this.getLevelColor(e),D=`${r.gray}${i}${r.reset} ${f}${v}${r.reset} `;n&&(D+=`${n} `);let q=Object.keys(t).filter(R=>!["timestamp","level","message"].includes(R));if(q.length>0){let R=q.map(u=>{let g=t[u];return typeof g=="string"||typeof g=="number"?`${r.gray}${u}:${r.reset}${g}`:null}).filter(Boolean);R.length>0&&(D+=r.gray+R.join(" ")+r.reset);}console.log(D);}colorizeMethod(e){let t=this.colors,n=e.toUpperCase();switch(n){case "GET":return `${t.green}${n}${t.reset}`;case "POST":return `${t.cyan}${n}${t.reset}`;case "PUT":return `${t.yellow}${n}${t.reset}`;case "DELETE":return `${t.red}${n}${t.reset}`;case "PATCH":return `${t.magenta}${n}${t.reset}`;default:return `${t.gray}${n}${t.reset}`}}colorizeStatus(e){if(!e)return "";let t=this.colors,n=e.toString();return e>=200&&e<300?`${t.green}${n}${t.reset}`:e>=300&&e<400?`${t.cyan}${n}${t.reset}`:e>=400&&e<500?`${t.yellow}${n}${t.reset}`:e>=500?`${t.red}${n}${t.reset}`:`${t.gray}${n}${t.reset}`}getLevelIcon(e){switch(e){case "debug":return "\u25CF";case "info":return "\u25CF";case "warn":return "\u26A0";case "error":return "\u2716";case "fatal":return "\u2716";default:return "\u25CF"}}getLevelColor(e){let t=this.colors;switch(e){case "debug":return t.gray;case "info":return t.cyan;case "warn":return t.yellow;case "error":return t.red;case "fatal":return t.red+t.bold;default:return t.reset}}};var M=class extends Error{constructor(t,n=500,r){super(t);this.message=t;this.statusCode=n;this.code=r;this.name="AppError";}},I=class extends M{constructor(t,n){super(t,400,"VALIDATION_ERROR");this.issues=n;this.name="ValidationError";}},se=class extends M{constructor(e){super(e,500,"DATABASE_ERROR"),this.name="DatabaseError";}},X=class extends M{constructor(e="Request timeout"){super(e,408,"TIMEOUT_ERROR"),this.name="TimeoutError";}},oe=class extends M{constructor(e="Too many requests"){super(e,429,"RATE_LIMIT_ERROR"),this.name="RateLimitError";}};var O=class{constructor(e){this.fileCache=new Map;this.CACHE_MAX_SIZE=1e3;if(!fs.existsSync(e.directory))throw new Error(`Static directory does not exist: ${e.directory}`);if(!fs.statSync(e.directory).isDirectory())throw new Error(`Static path is not a directory: ${e.directory}`);this.resolvedDir=path.resolve(e.directory),this.config={path:e.path,directory:e.directory,maxAge:e.maxAge??3600,index:e.index??["index.html"],dotfiles:e.dotfiles??"deny",etag:e.etag??true,lastModified:e.lastModified??true,immutable:e.immutable??false,extensions:e.extensions??[],fallthrough:e.fallthrough??false,setHeaders:e.setHeaders};}handler(){return async e=>{let t=e.request.url,r=new URL(t).pathname;r.startsWith(this.config.path)&&(r=r.slice(this.config.path.length));try{r=decodeURIComponent(r);}catch{return e.json({error:"Invalid URL encoding"},400)}if(r.includes("..")||r.includes("\\"))return e.json({error:"Forbidden"},403);if(this.config.dotfiles!=="allow"&&r.split("/").some(l=>l.startsWith(".")))return this.config.dotfiles==="deny"?e.json({error:"Forbidden"},403):this.handleNotFound(e);let i=this.resolveFilePath(r);if(!i)return this.handleNotFound(e);if(!this.isPathSafe(i))return e.json({error:"Forbidden"},403);if(!fs.existsSync(i))return this.handleNotFound(e);let a=fs.statSync(i);return a.isDirectory()?this.serveDirectory(e,i,r):this.serveFile(e,i,a)}}getPathPattern(){return `${this.config.path}/*`}resolveFilePath(e){e.startsWith("/")&&(e=e.slice(1));let t=path.join(this.resolvedDir,e);if(!fs.existsSync(t)&&this.config.extensions.length>0)for(let n of this.config.extensions){let r=`${t}.${n}`;if(fs.existsSync(r))return r}return t}isPathSafe(e){return !path.relative(this.resolvedDir,path.resolve(e)).startsWith("..")&&!path.resolve(e).startsWith("..")}async serveDirectory(e,t,n){for(let r of this.config.index){let i=path.join(t,r);if(fs.existsSync(i)){let a=fs.statSync(i);if(a.isFile())return this.serveFile(e,i,a)}}return this.handleNotFound(e)}async serveFile(e,t,n){let r=e.request.method.toUpperCase();if(r!=="GET"&&r!=="HEAD")return e.json({error:"Method not allowed"},405);let i=t,a=this.fileCache.get(i);if(a&&a.mtime!==n.mtimeMs&&(a=void 0),!a){if(a={etag:this.generateEtag(n),lastModified:new Date(n.mtime),size:n.size,mtime:n.mtimeMs},this.fileCache.size>=this.CACHE_MAX_SIZE){let f=this.fileCache.keys().next().value;f&&this.fileCache.delete(f);}this.fileCache.set(i,a);}let l=e.request.headers.get("if-none-match"),h=e.request.headers.get("if-modified-since");if(this.config.etag&&l===a.etag)return new Response(null,{status:304,headers:this.buildHeaders(t,a)});if(this.config.lastModified&&h){let f=new Date(h);if(a.lastModified<=f)return new Response(null,{status:304,headers:this.buildHeaders(t,a)})}let b=Bun.file(t),v=this.buildHeaders(t,a);return this.config.setHeaders&&this.config.setHeaders(e,t),r==="HEAD"?new Response(null,{status:200,headers:v}):new Response(b,{status:200,headers:v})}buildHeaders(e,t){let n=new Headers,r=this.getMimeType(e);if(n.set("Content-Type",r),n.set("Content-Length",t.size.toString()),this.config.etag&&n.set("ETag",t.etag),this.config.lastModified&&n.set("Last-Modified",t.lastModified.toUTCString()),this.config.maxAge>0){let i=`public, max-age=${this.config.maxAge}`;this.config.immutable&&(i+=", immutable"),n.set("Cache-Control",i);}else n.set("Cache-Control","no-cache");return n.set("Accept-Ranges","bytes"),n}generateEtag(e){return `"${e.size.toString(16)}-${e.mtimeMs.toString(16)}"`}getMimeType(e){let t=path.extname(e).toLowerCase();return be[t]||"application/octet-stream"}handleNotFound(e){return this.config.fallthrough?e.json({error:"Not Found"},404):e.json({error:"Not Found"},404)}clearCache(){this.fileCache.clear();}getCacheStats(){return {entries:this.fileCache.size,maxSize:this.CACHE_MAX_SIZE}}};function ye(s){return new O(s)}var be={".html":"text/html; charset=utf-8",".htm":"text/html; charset=utf-8",".css":"text/css; charset=utf-8",".txt":"text/plain; charset=utf-8",".xml":"text/xml; charset=utf-8",".csv":"text/csv; charset=utf-8",".md":"text/markdown; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".jsonld":"application/ld+json",".map":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".ico":"image/x-icon",".webp":"image/webp",".avif":"image/avif",".bmp":"image/bmp",".tiff":"image/tiff",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".mp3":"audio/mpeg",".wav":"audio/wav",".ogg":"audio/ogg",".m4a":"audio/mp4",".aac":"audio/aac",".flac":"audio/flac",".mp4":"video/mp4",".webm":"video/webm",".ogv":"video/ogg",".mov":"video/quicktime",".avi":"video/x-msvideo",".mkv":"video/x-matroska",".pdf":"application/pdf",".doc":"application/msword",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xls":"application/vnd.ms-excel",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",".ppt":"application/vnd.ms-powerpoint",".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",".zip":"application/zip",".rar":"application/x-rar-compressed",".7z":"application/x-7z-compressed",".tar":"application/x-tar",".gz":"application/gzip",".wasm":"application/wasm",".manifest":"text/cache-manifest",".webmanifest":"application/manifest+json"};var W=new V,k=new B;async function Re(s={}){let e=Number(s.port)||3e3,t=s.hostname||"localhost",n=s.maxRequestSize||10*1024*1024,r=s.requestTimeout||3e4,i=s.gracefulShutdownTimeout||1e4,a=typeof s.logging=="object"?s.logging:{},l=s.logging?new J(a.level||"info",a.pretty):null,h=null;s.i18n&&(h=i18n.getI18n(),h&&await i18n.setupI18n(s.i18n===true?{defaultLanguage:"en",supportedLanguages:["en"]}:s.i18n));let b=new Map,v=[],f=new Set,D=[],q=setInterval(()=>{W.cleanupRateLimit(),W.cleanupCsrfTokens();},120*1e3);async function R(o,c){let p=Date.now(),d=crypto.randomUUID(),x=new URL(o.url).pathname,E=o.method.toUpperCase(),$=ve(o,c);f.add(d);try{let C=o.headers.get("content-length");if(C&&parseInt(C)>n)return l?.warn({requestId:d,size:C,ip:$},"Request too large"),new Response(JSON.stringify({error:"Payload too large"}),{status:413,headers:{"Content-Type":"application/json"}});let j=Se(o,s);if(E==="OPTIONS")return new Response(null,{status:204,headers:j});if(s.security&&typeof s.security=="object"&&s.security.rateLimit){let L=typeof s.security.rateLimit=="object"?s.security.rateLimit:{},H=L.max||100,Z=L.windowMs||6e4,ne=L.keyGenerator?L.keyGenerator({request:o,ip:$}):$;if(!W.checkRateLimit(ne,H,Z))return l?.warn({requestId:d,ip:$,key:ne},"Rate limit exceeded"),new Response(JSON.stringify({error:L.message||"Too many requests"}),{status:429,headers:{"Content-Type":"application/json"}})}let w=null;["POST","PUT","PATCH"].includes(E)&&(w=await Ce(o,l,n));let T=b.get("default"),A=Object.fromEntries(new URL(o.url).searchParams),ue=o.headers.get("cookie")||"",de=ce(ue).get("lang"),z=A.lang||de||o.headers.get("Accept-Language")?.split(",")[0]?.split("-")[0]||"en";h&&!h.getSupportedLanguages().includes(z)&&(z=h.getLanguage()),h&&h.setLanguage(z);let N=k.match(E,x);if(!N){let L=ae($,o,{},T,l,d,h,z);if(l?.warn({requestId:d,method:E,path:x,ip:$},"Route not found"),s.onError)try{return await s.onError(404,x,E)}catch(H){l?.error({error:String(H),requestId:d},"Error in onError handler");}return L.json({error:"Not Found",path:x},404)}let G=ae($,o,N.params||{},T,l,d,h,z);G.body=w,G.request=o;let ee=new AbortController,pe=new Promise((L,H)=>{let Z=setTimeout(()=>{ee.abort(),H(new X("Request timeout"));},r);ee.signal.addEventListener("abort",()=>clearTimeout(Z));}),te=N.metadata?.middlewares||[],K;te.length>0?K=u(G,te,N.handler):K=Promise.resolve(N.handler(G));let F=await Promise.race([K,pe]),P=new Headers(F.headers);j.forEach((L,H)=>{P.has(H)||P.set(H,L);}),P.set("X-Request-ID",d),P.set("X-Content-Type-Options","nosniff"),P.set("X-Frame-Options","DENY"),P.set("X-XSS-Protection","1; mode=block"),P.set("Referrer-Policy","strict-origin-when-cross-origin");let re=Date.now()-p;return W.logRequest(d,E,x,$,F.status,re),l?.info({requestId:d,method:E,path:x,status:F.status,duration:re,ip:$},"Request completed"),new Response(F.body,{status:F.status,headers:P})}catch(C){if(C instanceof M){if(l?.warn({error:C.message,requestId:d,ip:$},`App error: ${C.message}`),s.onError)try{return await s.onError(C.statusCode,x,E)}catch(w){l?.error({error:String(w),requestId:d},"Error in onError handler");}return new Response(JSON.stringify({error:C.message,code:C.code,requestId:d}),{status:C.statusCode,headers:{"Content-Type":"application/json"}})}l?.error({error:String(C),requestId:d,ip:$},"Unhandled error");let j=process.env.NODE_ENV==="production"?"Internal Server Error":C.message;if(s.onError)try{return await s.onError(500,x,E)}catch(w){l?.error({error:String(w),requestId:d},"Error in onError handler");}return new Response(JSON.stringify({error:j,requestId:d}),{status:500,headers:{"Content-Type":"application/json"}})}finally{f.delete(d);}}async function u(o,c,p){let d=0,m=null,x=o.json.bind(o),E=o.text.bind(o),$=o.html.bind(o),C=o.redirect.bind(o);o.json=function(w,T){let A=x(w,T);return m=A,A},o.text=function(w,T){let A=E(w,T);return m=A,A},o.html=function(w,T){let A=$(w,T);return m=A,A},o.redirect=function(w,T){let A=C(w,T);return m=A,A};async function j(){if(!m&&d<c.length){let w=c[d];d++,await w(o,j);}}return await j(),o.json=x,o.text=E,o.html=$,o.redirect=C,m||p(o)}let g={method:"GET",path:"/health",handler:o=>o.json({status:"healthy",timestamp:new Date().toISOString(),uptime:process.uptime(),activeRequests:f.size})},y={method:"GET",path:"/readiness",handler:o=>{let c=b.size>0,p=c||b.size===0;return o.json({ready:p,checks:{database:c?"connected":"not configured",activeRequests:f.size},timestamp:new Date().toISOString()},p?200:503)}};if(s.routes&&s.routes.forEach(o=>{v.push(o),(Array.isArray(o.method)?o.method:[o.method]).forEach(p=>{k.register(p,o.path,o.handler,o);});}),s.static){let o=Array.isArray(s.static)?s.static:[s.static];for(let c of o)try{let d=new O(c).handler(),m={method:"GET",path:c.path==="/"?"/*":`${c.path}/*`,handler:d};v.push(m);let x=c.path==="/"?"/":c.path;D.push({prefix:x,handler:d}),c.path==="/"?(k.register("GET","/",d,m),k.register("HEAD","/",d,m),k.register("GET","/*",d,m),k.register("HEAD","/*",d,m)):(k.register("GET",`${c.path}/*`,d,m),k.register("HEAD",`${c.path}/*`,d,m));}catch(p){throw l?.error({error:String(p),path:c.path},"Failed to initialize static file server"),p}}v.push(g,y),k.register("GET","/health",g.handler,g),k.register("GET","/readiness",y.handler,y);let S=null,U={app:null,logger:l,db:b,bunServer:null,async start(){if(s.database){let c=Array.isArray(s.database)?s.database:[s.database];for(let p of c){let d=p.name||"default";try{if(typeof p.connection=="string"){let m=new le__namespace.DB(p.connection);if(p.schema&&typeof p.schema=="object")for(let[,x]of Object.entries(p.schema))x&&typeof x=="object"&&m.defineSchema(x);b.set(d,m),l?.info({name:d,connection:p.connection},"\u2714 Database connected");}else throw new Error(`Database connection must be a string path (got ${typeof p.connection})`)}catch(m){throw l?.error({error:String(m),name:d},"Failed to connect to database"),m}}}S=Bun.serve({port:e,hostname:t,fetch:(c,p)=>R(c,p)}),U.bunServer=S;let o=`http://${t}:${e}`;if(l?.info({url:o},"\u2714 Server started"),s.onStartup)try{await s.onStartup(U);}catch(c){l?.error({error:String(c)},"Error in startup handler");}if(s.onReady)try{await s.onReady(U,b);}catch(c){l?.error({error:String(c)},"Error in ready handler");}},async stop(){if(l?.info("Stopping server..."),f.size>0){l?.info({count:f.size},"Waiting for active requests...");let o=Date.now()+i;for(;f.size>0&&Date.now()<o;)await new Promise(c=>setTimeout(c,100));f.size>0&&l?.warn({count:f.size},"Force closing with active requests");}if(clearInterval(q),s.onShutdown)try{await s.onShutdown();}catch(o){l?.error({error:String(o)},"Error in shutdown handler");}for(let[o,c]of b.entries())try{c&&typeof c.close=="function"&&c.close(),l?.info({name:o},"Database closed");}catch(p){l?.error({error:String(p),name:o},"Error closing database");}S&&typeof S.stop=="function"&&(S.stop(),l?.info("Bun server stopped")),l?.info("Server stopped successfully");},addRoute(o){v.push(o),(Array.isArray(o.method)?o.method:[o.method]).forEach(p=>{k.register(p,o.path,o.handler,o);}),l?.info({method:o.method,path:o.path},"Route added");},addRoutes(o){o.forEach(c=>this.addRoute(c));},getRoutes(){return v}};return U}async function Ce(s,e,t){let n=s.headers.get("content-type")||"";try{if(n.includes("application/json")){let r=await s.text();if(r.length>t)throw new I("Payload too large");if(!r.trim())return {};try{return JSON.parse(r)}catch(i){throw e?.warn({error:String(i),bodyPreview:r.substring(0,100)},"Invalid JSON in request body"),new I("Invalid JSON in request body")}}if(n.includes("application/x-www-form-urlencoded")){let r=await s.text();if(r.length>t)throw new I("Payload too large");return Object.fromEntries(new URLSearchParams(r))}if(n.includes("multipart/form-data"))return await s.formData()}catch(r){throw r instanceof I?r:(e?.error({error:String(r)},"Error parsing request body"),new I("Failed to parse request body"))}return {}}function ce(s){let e=new Map;if(!s)return e;let t=s.split(";");for(let n of t){let[r,...i]=n.trim().split("=");if(r){let a=i.join("=");e.set(r,a?decodeURIComponent(a):"");}}return e}function ae(s,e,t,n,r,i,a=null,l="en"){let h=new URL(e.url),b=Object.fromEntries(h.searchParams),v=e.headers,f=200,D=new Map,q=ce(v.get("cookie")||""),R={ip:s,request:e,params:t,query:b,headers:v,db:n,logger:r,i18n:a,lang:l,requestId:i,get statusCode(){return f},set statusCode(u){f=u;},body:null,state:{},json(u,g){return new Response(JSON.stringify(u),{status:g??f,headers:{"Content-Type":"application/json",...this._setCookieHeaders()}})},text(u,g){return new Response(u,{status:g??f,headers:{"Content-Type":"text/plain",...this._setCookieHeaders()}})},html(u,g){return new Response(u,{status:g??f,headers:{"Content-Type":"text/html; charset=utf-8",...this._setCookieHeaders()}})},redirect(u,g=302){return new Response(null,{status:g,headers:{Location:u,...this._setCookieHeaders()}})},file(u,g="application/octet-stream"){let y=Bun.file(u);return new Response(y,{headers:{"Content-Type":g,...this._setCookieHeaders()}})},setCookie(u,g,y={}){let S=`${u}=${encodeURIComponent(g)}`;return y.maxAge!==void 0&&(S+=`; Max-Age=${y.maxAge}`),y.expires&&(S+=`; Expires=${y.expires.toUTCString()}`),y.path&&(S+=`; Path=${y.path}`),y.domain&&(S+=`; Domain=${y.domain}`),y.secure&&(S+="; Secure"),y.httpOnly&&(S+="; HttpOnly"),y.sameSite&&(S+=`; SameSite=${y.sameSite}`),D.set(u,S),R},getCookie(u){return q.get(u)},deleteCookie(u,g={}){return R.setCookie(u,"",{...g,maxAge:0,path:g.path||"/"})},setHeader(u,g){return v.set(u,g),R},getHeader(u){return v.get(u)||void 0},status(u){return f=u,R},_setCookieHeaders(){let u={};return D.size>0&&(u["Set-Cookie"]=Array.from(D.values())),u}};return R}function ve(s,e){let t=s.headers.get("x-forwarded-for");if(t)return t.split(",").map(i=>i.trim())[0]||"unknown";let n=s.headers.get("x-real-ip");if(n)return n;if(e)try{let i=e.requestIP?.(s);if(i?.address)return i.address}catch{}return "unknown"}function Se(s,e){let t=new Headers;if(!e.security||typeof e.security!="object"||!e.security.cors)return t;let n=typeof e.security.cors=="object"?e.security.cors:{},r=s.headers.get("Origin");if(r){typeof n.origin=="function"?n.origin(r)&&t.set("Access-Control-Allow-Origin",r):Array.isArray(n.origin)?n.origin.includes(r)&&t.set("Access-Control-Allow-Origin",r):typeof n.origin=="string"?t.set("Access-Control-Allow-Origin",n.origin):t.set("Access-Control-Allow-Origin",r);let i=n.methods||["GET","POST","PUT","DELETE","PATCH","OPTIONS"];t.set("Access-Control-Allow-Methods",i.join(", "));let a=n.allowedHeaders||["Content-Type","Authorization","X-Requested-With"];t.set("Access-Control-Allow-Headers",a.join(", ")),n.credentials&&t.set("Access-Control-Allow-Credentials","true"),n.maxAge&&t.set("Access-Control-Max-Age",n.maxAge.toString());}return t}var Ne=Re;
2
+ Object.defineProperty(exports,"DB",{enumerable:true,get:function(){return le.DB}});Object.defineProperty(exports,"blob",{enumerable:true,get:function(){return le.blob}});Object.defineProperty(exports,"column",{enumerable:true,get:function(){return le.column}});Object.defineProperty(exports,"defaultValue",{enumerable:true,get:function(){return le.defaultValue}});Object.defineProperty(exports,"index",{enumerable:true,get:function(){return le.index}});Object.defineProperty(exports,"integer",{enumerable:true,get:function(){return le.integer}});Object.defineProperty(exports,"notNull",{enumerable:true,get:function(){return le.notNull}});Object.defineProperty(exports,"numeric",{enumerable:true,get:function(){return le.numeric}});Object.defineProperty(exports,"primaryKey",{enumerable:true,get:function(){return le.primaryKey}});Object.defineProperty(exports,"real",{enumerable:true,get:function(){return le.real}});Object.defineProperty(exports,"references",{enumerable:true,get:function(){return le.references}});Object.defineProperty(exports,"table",{enumerable:true,get:function(){return le.table}});Object.defineProperty(exports,"text",{enumerable:true,get:function(){return le.text}});Object.defineProperty(exports,"unique",{enumerable:true,get:function(){return le.unique}});Object.defineProperty(exports,"genPageTitle",{enumerable:true,get:function(){return i18n.genPageTitle}});Object.defineProperty(exports,"getI18n",{enumerable:true,get:function(){return i18n.getI18n}});Object.defineProperty(exports,"getLanguage",{enumerable:true,get:function(){return i18n.getLanguage}});Object.defineProperty(exports,"getSupportedLanguages",{enumerable:true,get:function(){return i18n.getSupportedLanguages}});Object.defineProperty(exports,"loadLanguage",{enumerable:true,get:function(){return i18n.loadLanguage}});Object.defineProperty(exports,"loadTranslations",{enumerable:true,get:function(){return i18n.loadTranslations}});Object.defineProperty(exports,"setLanguage",{enumerable:true,get:function(){return i18n.setLanguage}});Object.defineProperty(exports,"setupI18n",{enumerable:true,get:function(){return i18n.setupI18n}});Object.defineProperty(exports,"t",{enumerable:true,get:function(){return i18n.t}});Object.defineProperty(exports,"tLang",{enumerable:true,get:function(){return i18n.tLang}});Object.defineProperty(exports,"tParse",{enumerable:true,get:function(){return i18n.tParse}});exports.AppError=M;exports.DatabaseError=se;exports.Logger=J;exports.RateLimitError=oe;exports.Router=B;exports.SecurityManager=V;exports.StaticFileServer=O;exports.TimeoutError=X;exports.ValidationError=I;exports.createStatic=ye;exports.default=Ne;exports.server=Re;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map