@minejs/server 0.0.2 → 0.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/README.md CHANGED
@@ -8,10 +8,10 @@
8
8
  </div>
9
9
 
10
10
  <div align="center">
11
- <img src="https://img.shields.io/badge/v-0.0.2-black"/>
11
+ <img src="https://img.shields.io/badge/v-0.0.3-black"/>
12
12
  <img src="https://img.shields.io/badge/🔥-@minejs-black"/>
13
13
  <br>
14
- <img src="https://img.shields.io/badge/coverage-94.71%25-brightgreen" alt="Test Coverage" />
14
+ <img src="https://img.shields.io/badge/coverage-98.88%25-brightgreen" alt="Test Coverage" />
15
15
  <img src="https://img.shields.io/github/issues/minejs-org/server?style=flat" alt="Github Repo Issues" />
16
16
  <img src="https://img.shields.io/github/stars/minejs-org/server?style=social" alt="GitHub Repo stars" />
17
17
  </div>
@@ -367,24 +367,37 @@
367
367
  - ### 11. Internationalization (i18n)
368
368
 
369
369
  ```typescript
370
- import { server, type AppContext } from '@minejs/server'
370
+ import { server, type AppContext, setupAuto, setLanguage } from '@minejs/server'
371
371
 
372
372
  const app = server({
373
373
  port: 3000,
374
374
  i18n: {
375
375
  defaultLanguage: 'en',
376
- supportedLanguages: ['en', 'ar', 'fr'],
377
- staticPath: './src/i18n'
376
+ supportedLanguages: ['en', 'ar', 'fr']
377
+ },
378
+
379
+ onStartup: async () => {
380
+ // Auto-setup: Automatically detects server environment and loads from files
381
+ // On server: Reads from ./translations/en.json
382
+ // On browser: Fetches from http://localhost:3000/translations/en.json
383
+ await setupAuto({
384
+ defaultLanguage: 'en',
385
+ supportedLanguages: ['en', 'ar', 'fr'],
386
+ basePath: './translations/',
387
+ fileExtension: 'json'
388
+ })
378
389
  },
390
+
379
391
  routes: [
380
392
  {
381
393
  method: 'GET',
382
394
  path: '/greeting',
383
395
  handler: (c: AppContext) => {
384
396
  const language = c.lang // Detected from query, cookie, or header
397
+ // Use c.i18n?.t() to translate with context
385
398
  return c.json({
386
399
  language,
387
- greeting: 'Hello'
400
+ greeting: c.i18n?.t('greeting') || 'Hello'
388
401
  })
389
402
  }
390
403
  }
@@ -395,6 +408,27 @@
395
408
  // Language detection priority: ?lang query param > lang cookie > Accept-Language header > default
396
409
  ```
397
410
 
411
+ **Translation file structure:**
412
+ ```
413
+ your-app/
414
+ ├── src/
415
+ │ └── main.ts
416
+ ├── translations/
417
+ │ ├── en.json
418
+ │ ├── ar.json
419
+ │ └── fr.json
420
+ └── package.json
421
+ ```
422
+
423
+ **translations/en.json:**
424
+ ```json
425
+ {
426
+ "greeting": "Hello",
427
+ "farewell": "Goodbye",
428
+ "welcome": "Welcome, {name}!"
429
+ }
430
+ ```
431
+
398
432
  - ### 12. Logging
399
433
 
400
434
  ```typescript
package/dist/main.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';Object.defineProperty(exports,'__esModule',{value:true});var pe=require('@minejs/db'),ye=require('crypto'),path=require('path'),fs=require('fs');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 pe__namespace=/*#__PURE__*/_interopNamespace(pe);var ye__default=/*#__PURE__*/_interopDefault(ye);var X=class{constructor(){this.routes=new Map;this.regexRoutes=[];}match(e,t){let r=`${e}:${t}`;if(this.routes.has(r)){let n=this.routes.get(r);return {handler:n.handler,params:{},metadata:n.metadata}}for(let n of this.regexRoutes)if(n.method===e){let o=t.match(n.pattern);if(o){let a=o.groups||{};return {handler:n.handler,params:a,metadata:n.metadata}}}return null}getAll(){let e=Array.from(this.routes.entries()).map(([r,n])=>{let o=r.indexOf(":"),a=r.substring(0,o),u=r.substring(o+1);return {method:a,path:u,handler:n.handler}}),t=this.regexRoutes.map(r=>{let n=r.key.indexOf(":");return {method:r.method,path:r.key.substring(n+1),handler:r.handler}});return [...e,...t]}clear(){this.routes.clear(),this.regexRoutes=[];}remove(e,t){let r=`${e}:${t}`;if(this.routes.has(r))return this.routes.delete(r),true;let n=this.regexRoutes.findIndex(o=>o.key===r);return n>=0?(this.regexRoutes.splice(n,1),true):false}register(e,t,r,n={}){let o=`${e}:${t}`;if(t.includes(":")||t.includes("*")){let a=this.pathToRegex(t),u=this.regexRoutes.findIndex(b=>b.key===o),h={pattern:a,method:e,handler:r,key:o,metadata:n};u>=0?this.regexRoutes[u]=h:this.regexRoutes.push(h);}else this.routes.set(o,{handler:r,metadata:n});}pathToRegex(e){let t=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&");return t=t.replace(/:(\w+)/g,"(?<$1>[^/]+)"),t=t.replace(/\*/g,".*"),new RegExp(`^${t}$`)}};var W=class{constructor(){this.rateLimitStore=new Map;this.csrfTokens=new Map;this.requestLog=new Map;this.MAX_REQUEST_LOG_SIZE=1e3;}checkRateLimit(e,t,r){let n=Date.now(),o=this.rateLimitStore.get(e);return o?n<o.reset?o.count>=t?false:(o.count++,true):(this.rateLimitStore.set(e,{count:1,reset:n+r}),true):(this.rateLimitStore.set(e,{count:1,reset:n+r}),true)}cleanupRateLimit(){let e=Date.now();for(let[t,r]of this.rateLimitStore.entries())e>r.reset&&this.rateLimitStore.delete(t);}generateCsrfToken(e,t=36e5){let r=ye__default.default.randomBytes(32).toString("hex");return this.csrfTokens.set(r,{sessionId:e,expires:Date.now()+t}),r}validateCsrfToken(e,t){let r=this.csrfTokens.get(e);return r?Date.now()>r.expires?(this.csrfTokens.delete(e),false):r.sessionId===t?(this.csrfTokens.delete(e),true):false:false}cleanupCsrfTokens(){let e=Date.now();for(let[t,r]of this.csrfTokens.entries())e>r.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,r,n,o,a){if(this.requestLog.set(e,{timestamp:new Date().toISOString(),method:t,path:r,ip:n,status:o,duration:a}),this.requestLog.size>this.MAX_REQUEST_LOG_SIZE){let{value:u}=this.requestLog.keys().next()||{value:null};u&&this.requestLog.delete(u);}}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 K=class s{constructor(e="info",t=false,r=""){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=r;}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,r=Object.keys(this.levels).find(n=>this.levels[n]===this.level)||"info";return new s(r,this.pretty,t)}log(e,t,r,n){if(t<this.level)return;let o,a;if(typeof r=="string"?(a=r,o={}):(o=r??{},a=n),this.prefix&&a?a=`[${this.prefix}] ${a}`:this.prefix&&(a=`[${this.prefix}]`),this.pretty)this.prettyLog(e,o,a);else {let h={timestamp:new Date().toISOString(),level:e.toUpperCase(),message:a||"No message",...o},b=JSON.stringify(h);e==="error"||e==="fatal"?console.error(b):e==="warn"?console.warn(b):console.log(b);}}prettyLog(e,t,r){let n=this.colors,o=new Date().toLocaleTimeString("en-US",{hour12:false}),a="method"in t&&"path"in t,u=a&&"status"in t&&"duration"in t,h="name"in t,b="url"in t;if(u){let x=this.colorizeMethod(t.method),g=this.colorizeStatus(t.status),f=t.duration?`${t.duration}ms`:"",y=t.path;console.log(`${n.gray}${o}${n.reset} ${x} ${n.bold}${y}${n.reset} ${g} ${n.gray}${f}${n.reset}`);return}if(r==="Route added"&&a){let x=Array.isArray(t.method)?t.method.join("|"):t.method;console.log(`${n.gray}${o}${n.reset} ${n.cyan}\u2192${n.reset} ${n.bold}${x.padEnd(6)}${n.reset} ${t.path}`);return}if(r==="\u2714 Database connected"&&h){console.log(`${n.gray}${o}${n.reset} ${n.green}\u2713${n.reset} Database connected ${n.gray}(${t.name})${n.reset}`);return}if(r==="Server started"&&b){console.log(`${n.gray}${o}${n.reset} ${n.green}\u2713${n.reset} Server started at ${n.cyan}${t.url}${n.reset}`);return}let S=this.getLevelIcon(e),m=this.getLevelColor(e),D=`${n.gray}${o}${n.reset} ${m}${S}${n.reset} `;r&&(D+=`${r} `);let O=Object.keys(t).filter(x=>!["timestamp","level","message"].includes(x));if(O.length>0){let x=O.map(g=>{let f=t[g];return typeof f=="string"||typeof f=="number"?`${n.gray}${g}:${n.reset}${f}`:null}).filter(Boolean);x.length>0&&(D+=n.gray+x.join(" ")+n.reset);}console.log(D);}colorizeMethod(e){let t=this.colors,r=e.toUpperCase();switch(r){case "GET":return `${t.green}${r}${t.reset}`;case "POST":return `${t.cyan}${r}${t.reset}`;case "PUT":return `${t.yellow}${r}${t.reset}`;case "DELETE":return `${t.red}${r}${t.reset}`;case "PATCH":return `${t.magenta}${r}${t.reset}`;default:return `${t.gray}${r}${t.reset}`}}colorizeStatus(e){if(!e)return "";let t=this.colors,r=e.toString();return e>=200&&e<300?`${t.green}${r}${t.reset}`:e>=300&&e<400?`${t.cyan}${r}${t.reset}`:e>=400&&e<500?`${t.yellow}${r}${t.reset}`:e>=500?`${t.red}${r}${t.reset}`:`${t.gray}${r}${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 I=class extends Error{constructor(t,r=500,n){super(t);this.message=t;this.statusCode=r;this.code=n;this.name="AppError";}},M=class extends I{constructor(t,r){super(t,400,"VALIDATION_ERROR");this.issues=r;this.name="ValidationError";}},ue=class extends I{constructor(e){super(e,500,"DATABASE_ERROR"),this.name="DatabaseError";}},Z=class extends I{constructor(e="Request timeout"){super(e,408,"TIMEOUT_ERROR"),this.name="TimeoutError";}},ce=class extends I{constructor(e="Too many requests"){super(e,429,"RATE_LIMIT_ERROR"),this.name="RateLimitError";}};var q=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,n=new URL(t).pathname;n.startsWith(this.config.path)&&(n=n.slice(this.config.path.length));try{n=decodeURIComponent(n);}catch{return e.json({error:"Invalid URL encoding"},400)}if(n.includes("..")||n.includes("\\"))return e.json({error:"Forbidden"},403);if(this.config.dotfiles!=="allow"&&n.split("/").some(u=>u.startsWith(".")))return this.config.dotfiles==="deny"?e.json({error:"Forbidden"},403):this.handleNotFound(e);let o=this.resolveFilePath(n);if(!o)return this.handleNotFound(e);if(!this.isPathSafe(o))return e.json({error:"Forbidden"},403);if(!fs.existsSync(o))return this.handleNotFound(e);let a=fs.statSync(o);return a.isDirectory()?this.serveDirectory(e,o,n):this.serveFile(e,o,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 r of this.config.extensions){let n=`${t}.${r}`;if(fs.existsSync(n))return n}return t}isPathSafe(e){return !path.relative(this.resolvedDir,path.resolve(e)).startsWith("..")&&!path.resolve(e).startsWith("..")}async serveDirectory(e,t,r){for(let n of this.config.index){let o=path.join(t,n);if(fs.existsSync(o)){let a=fs.statSync(o);if(a.isFile())return this.serveFile(e,o,a)}}return this.handleNotFound(e)}async serveFile(e,t,r){let n=e.request.method.toUpperCase();if(n!=="GET"&&n!=="HEAD")return e.json({error:"Method not allowed"},405);let o=t,a=this.fileCache.get(o);if(a&&a.mtime!==r.mtimeMs&&(a=void 0),!a){if(a={etag:this.generateEtag(r),lastModified:new Date(r.mtime),size:r.size,mtime:r.mtimeMs},this.fileCache.size>=this.CACHE_MAX_SIZE){let m=this.fileCache.keys().next().value;m&&this.fileCache.delete(m);}this.fileCache.set(o,a);}let u=e.request.headers.get("if-none-match"),h=e.request.headers.get("if-modified-since");if(this.config.etag&&u===a.etag)return new Response(null,{status:304,headers:this.buildHeaders(t,a)});if(this.config.lastModified&&h){let m=new Date(h);if(a.lastModified<=m)return new Response(null,{status:304,headers:this.buildHeaders(t,a)})}let b=Bun.file(t),S=this.buildHeaders(t,a);return this.config.setHeaders&&this.config.setHeaders(e,t),n==="HEAD"?new Response(null,{status:200,headers:S}):new Response(b,{status:200,headers:S})}buildHeaders(e,t){let r=new Headers,n=this.getMimeType(e);if(r.set("Content-Type",n),r.set("Content-Length",t.size.toString()),this.config.etag&&r.set("ETag",t.etag),this.config.lastModified&&r.set("Last-Modified",t.lastModified.toUTCString()),this.config.maxAge>0){let o=`public, max-age=${this.config.maxAge}`;this.config.immutable&&(o+=", immutable"),r.set("Cache-Control",o);}else r.set("Cache-Control","no-cache");return r.set("Accept-Ranges","bytes"),r}generateEtag(e){return `"${e.size.toString(16)}-${e.mtimeMs.toString(16)}"`}getMimeType(e){let t=path.extname(e).toLowerCase();return Ce[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 xe(s){return new q(s)}var Ce={".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 B=class{constructor(e){this.translations={};this.currentLanguage="en";this.defaultLanguage="en";this.supportedLanguages=new Set(["en"]);this.cachePath="";e&&(this.defaultLanguage=e.defaultLanguage||"en",this.currentLanguage=e.defaultLanguage||"en",this.cachePath=e.staticPath||"static/i18n",e.supportedLanguages&&(this.supportedLanguages=new Set(e.supportedLanguages)));}loadLanguage(e,t){this.translations[e]||(this.translations[e]={});let r=this.flattenObject(t);this.translations[e]={...this.translations[e],...r},this.supportedLanguages.add(e);}flattenObject(e,t=""){let r={};for(let n in e)if(Object.prototype.hasOwnProperty.call(e,n)){let o=e[n],a=t?`${t}.${n}`:n;typeof o=="object"&&o!==null&&!Array.isArray(o)?Object.assign(r,this.flattenObject(o,a)):r[a]=String(o);}return r}loadTranslations(e){Object.entries(e).forEach(([t,r])=>{this.loadLanguage(t,r);});}setLanguage(e){this.supportedLanguages.has(e)?this.currentLanguage=e:this.supportedLanguages.has(this.defaultLanguage)&&(this.currentLanguage=this.defaultLanguage);}getLanguage(){return this.currentLanguage}getSupportedLanguages(){return Array.from(this.supportedLanguages)}t(e,t,r){let n=this.currentLanguage,o=this.getTranslation(e,r);return t&&Object.entries(t).forEach(([a,u])=>{let h=this.translations[n]?.[u]||this.translations[this.defaultLanguage]?.[u]||u;o=o.replace(new RegExp(`\\{${a}\\}`,"g"),h);}),o}getTranslation(e,t){let r=this.currentLanguage;return this.translations[r]?.[e]?this.translations[r]?.[e]||this.translations[this.defaultLanguage]?.[e]:(console.warn(`Translation key not found: ${e}`),t||e)}tLang(e,t,r){let n=this.currentLanguage;this.setLanguage(t);let o=this.t(e,r);return this.currentLanguage=n,o}getTranslations(){return this.translations[this.currentLanguage]||{}}hasKey(e){return !!(this.translations[this.currentLanguage]?.[e]||this.translations[this.defaultLanguage]?.[e])}},z=null;function ne(s){return z||(z=new B(s)),z}function G(){return z||(z=new B),z}function ve(s,e,t){return G().t(s,e,t)}function Se(s){G().setLanguage(s);}function Le(){return G().getLanguage()}function $e(){return G().getSupportedLanguages()}var Q=new W,E=new X;function Ae(s={}){let e=Number(s.port)||3e3,t=s.hostname||"localhost",r=s.maxRequestSize||10*1024*1024,n=s.requestTimeout||3e4,o=s.gracefulShutdownTimeout||1e4,a=typeof s.logging=="object"?s.logging:{},u=s.logging?new K(a.level||"info",a.pretty):null,h=null;if(s.i18n){let i=typeof s.i18n=="object"?s.i18n:{};h=ne({defaultLanguage:i.defaultLanguage||"en",supportedLanguages:i.supportedLanguages||["en","ar","fr"],staticPath:i.staticPath||"./src/frontend/static/i18n"});}let b=new Map,S=[],m=new Set,D=[],O=setInterval(()=>{Q.cleanupRateLimit(),Q.cleanupCsrfTokens();},120*1e3);async function x(i,c){let p=Date.now(),l=crypto.randomUUID(),w=new URL(i.url).pathname,L=i.method.toUpperCase(),C=ke(i,c);m.add(l);try{let v=i.headers.get("content-length");if(v&&parseInt(v)>r)return u?.warn({requestId:l,size:v,ip:C},"Request too large"),new Response(JSON.stringify({error:"Payload too large"}),{status:413,headers:{"Content-Type":"application/json"}});let j=Te(i,s);if(L==="OPTIONS")return new Response(null,{status:204,headers:j});if(s.security&&typeof s.security=="object"&&s.security.rateLimit){let T=typeof s.security.rateLimit=="object"?s.security.rateLimit:{},H=T.max||100,ee=T.windowMs||6e4,ae=T.keyGenerator?T.keyGenerator({request:i,ip:C}):C;if(!Q.checkRateLimit(ae,H,ee))return u?.warn({requestId:l,ip:C,key:ae},"Rate limit exceeded"),new Response(JSON.stringify({error:T.message||"Too many requests"}),{status:429,headers:{"Content-Type":"application/json"}})}let R=null;["POST","PUT","PATCH"].includes(L)&&(R=await Ee(i,u,r));let k=b.get("default"),A=Object.fromEntries(new URL(i.url).searchParams),fe=i.headers.get("cookie")||"",he=de(fe).get("lang"),N=A.lang||he||i.headers.get("Accept-Language")?.split(",")[0]?.split("-")[0]||"en";h&&!h.getSupportedLanguages().includes(N)&&(N=h.getLanguage()),h&&h.setLanguage(N);let F=E.match(L,w);if(!F){let T=ge(C,i,{},k,u,l,h,N);if(u?.warn({requestId:l,method:L,path:w,ip:C},"Route not found"),s.onError)try{return await s.onError(404,w,L)}catch(H){u?.error({error:String(H),requestId:l},"Error in onError handler");}return T.json({error:"Not Found",path:w},404)}let J=ge(C,i,F.params||{},k,u,l,h,N);J.body=R,J.request=i;let se=new AbortController,me=new Promise((T,H)=>{let ee=setTimeout(()=>{se.abort(),H(new Z("Request timeout"));},n);se.signal.addEventListener("abort",()=>clearTimeout(ee));}),oe=F.metadata?.middlewares||[],Y;oe.length>0?Y=g(J,oe,F.handler):Y=Promise.resolve(F.handler(J));let _=await Promise.race([Y,me]),P=new Headers(_.headers);j.forEach((T,H)=>{P.has(H)||P.set(H,T);}),P.set("X-Request-ID",l),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 ie=Date.now()-p;return Q.logRequest(l,L,w,C,_.status,ie),u?.info({requestId:l,method:L,path:w,status:_.status,duration:ie,ip:C},"Request completed"),new Response(_.body,{status:_.status,headers:P})}catch(v){if(v instanceof I){if(u?.warn({error:v.message,requestId:l,ip:C},`App error: ${v.message}`),s.onError)try{return await s.onError(v.statusCode,w,L)}catch(R){u?.error({error:String(R),requestId:l},"Error in onError handler");}return new Response(JSON.stringify({error:v.message,code:v.code,requestId:l}),{status:v.statusCode,headers:{"Content-Type":"application/json"}})}u?.error({error:String(v),requestId:l,ip:C},"Unhandled error");let j=process.env.NODE_ENV==="production"?"Internal Server Error":v.message;if(s.onError)try{return await s.onError(500,w,L)}catch(R){u?.error({error:String(R),requestId:l},"Error in onError handler");}return new Response(JSON.stringify({error:j,requestId:l}),{status:500,headers:{"Content-Type":"application/json"}})}finally{m.delete(l);}}async function g(i,c,p){let l=0,d=null,w=i.json.bind(i),L=i.text.bind(i),C=i.html.bind(i),v=i.redirect.bind(i);i.json=function(R,k){let A=w(R,k);return d=A,A},i.text=function(R,k){let A=L(R,k);return d=A,A},i.html=function(R,k){let A=C(R,k);return d=A,A},i.redirect=function(R,k){let A=v(R,k);return d=A,A};async function j(){if(!d&&l<c.length){let R=c[l];l++,await R(i,j);}}return await j(),i.json=w,i.text=L,i.html=C,i.redirect=v,d||p(i)}let f={method:"GET",path:"/health",handler:i=>i.json({status:"healthy",timestamp:new Date().toISOString(),uptime:process.uptime(),activeRequests:m.size})},y={method:"GET",path:"/readiness",handler:i=>{let c=b.size>0,p=c||b.size===0;return i.json({ready:p,checks:{database:c?"connected":"not configured",activeRequests:m.size},timestamp:new Date().toISOString()},p?200:503)}};if(s.routes&&s.routes.forEach(i=>{S.push(i),(Array.isArray(i.method)?i.method:[i.method]).forEach(p=>{E.register(p,i.path,i.handler,i);});}),s.static){let i=Array.isArray(s.static)?s.static:[s.static];for(let c of i)try{let l=new q(c).handler(),d={method:"GET",path:c.path==="/"?"/*":`${c.path}/*`,handler:l};S.push(d);let w=c.path==="/"?"/":c.path;D.push({prefix:w,handler:l}),c.path==="/"?(E.register("GET","/",l,d),E.register("HEAD","/",l,d),E.register("GET","/*",l,d),E.register("HEAD","/*",l,d)):(E.register("GET",`${c.path}/*`,l,d),E.register("HEAD",`${c.path}/*`,l,d));}catch(p){throw u?.error({error:String(p),path:c.path},"Failed to initialize static file server"),p}}S.push(f,y),E.register("GET","/health",f.handler,f),E.register("GET","/readiness",y.handler,y);let $=null,V={app:null,logger:u,db:b,bunServer:null,async start(){if(h&&s.i18n){let c=typeof s.i18n=="object"?s.i18n:{},p=c.staticPath||"./src/frontend/static/i18n",l=c.supportedLanguages||["en","ar","fr"];try{for(let d of l){let w=`${p}/${d}.json`,L=Bun.file(w);if(await L.exists()){let C=await L.json();h.loadLanguage(d,C);}}u?.info({languages:h.getSupportedLanguages()},"i18n translations loaded");}catch(d){u?.warn({error:String(d)},"Failed to load i18n translations");}}if(s.database){let c=Array.isArray(s.database)?s.database:[s.database];for(let p of c){let l=p.name||"default";try{if(typeof p.connection=="string"){let d=new pe__namespace.DB(p.connection);if(p.schema&&typeof p.schema=="object")for(let[,w]of Object.entries(p.schema))w&&typeof w=="object"&&d.defineSchema(w);b.set(l,d),u?.info({name:l,connection:p.connection},"\u2714 Database connected");}else throw new Error(`Database connection must be a string path (got ${typeof p.connection})`)}catch(d){throw u?.error({error:String(d),name:l},"Failed to connect to database"),d}}}$=Bun.serve({port:e,hostname:t,fetch:(c,p)=>x(c,p)}),V.bunServer=$;let i=`http://${t}:${e}`;if(u?.info({url:i},"\u2714 Server started"),s.onStartup)try{await s.onStartup(V);}catch(c){u?.error({error:String(c)},"Error in startup handler");}if(s.onReady)try{await s.onReady(V,b);}catch(c){u?.error({error:String(c)},"Error in ready handler");}},async stop(){if(u?.info("Stopping server..."),m.size>0){u?.info({count:m.size},"Waiting for active requests...");let i=Date.now()+o;for(;m.size>0&&Date.now()<i;)await new Promise(c=>setTimeout(c,100));m.size>0&&u?.warn({count:m.size},"Force closing with active requests");}if(clearInterval(O),s.onShutdown)try{await s.onShutdown();}catch(i){u?.error({error:String(i)},"Error in shutdown handler");}for(let[i,c]of b.entries())try{c&&typeof c.close=="function"&&c.close(),u?.info({name:i},"Database closed");}catch(p){u?.error({error:String(p),name:i},"Error closing database");}$&&typeof $.stop=="function"&&($.stop(),u?.info("Bun server stopped")),u?.info("Server stopped successfully");},addRoute(i){S.push(i),(Array.isArray(i.method)?i.method:[i.method]).forEach(p=>{E.register(p,i.path,i.handler,i);}),u?.info({method:i.method,path:i.path},"Route added");},addRoutes(i){i.forEach(c=>this.addRoute(c));},getRoutes(){return S}};return V}async function Ee(s,e,t){let r=s.headers.get("content-type")||"";try{if(r.includes("application/json")){let n=await s.text();if(n.length>t)throw new M("Payload too large");if(!n.trim())return {};try{return JSON.parse(n)}catch(o){throw e?.warn({error:String(o),bodyPreview:n.substring(0,100)},"Invalid JSON in request body"),new M("Invalid JSON in request body")}}if(r.includes("application/x-www-form-urlencoded")){let n=await s.text();if(n.length>t)throw new M("Payload too large");return Object.fromEntries(new URLSearchParams(n))}if(r.includes("multipart/form-data"))return await s.formData()}catch(n){throw n instanceof M?n:(e?.error({error:String(n)},"Error parsing request body"),new M("Failed to parse request body"))}return {}}function de(s){let e=new Map;if(!s)return e;let t=s.split(";");for(let r of t){let[n,...o]=r.trim().split("=");if(n){let a=o.join("=");e.set(n,a?decodeURIComponent(a):"");}}return e}function ge(s,e,t,r,n,o,a=null,u="en"){let h=new URL(e.url),b=Object.fromEntries(h.searchParams),S=e.headers,m=200,D=new Map,O=de(S.get("cookie")||""),x={ip:s,request:e,params:t,query:b,headers:S,db:r,logger:n,i18n:a,lang:u,requestId:o,get statusCode(){return m},set statusCode(g){m=g;},body:null,state:{},json(g,f){return new Response(JSON.stringify(g),{status:f??m,headers:{"Content-Type":"application/json",...this._setCookieHeaders()}})},text(g,f){return new Response(g,{status:f??m,headers:{"Content-Type":"text/plain",...this._setCookieHeaders()}})},html(g,f){return new Response(g,{status:f??m,headers:{"Content-Type":"text/html; charset=utf-8",...this._setCookieHeaders()}})},redirect(g,f=302){return new Response(null,{status:f,headers:{Location:g,...this._setCookieHeaders()}})},file(g,f="application/octet-stream"){let y=Bun.file(g);return new Response(y,{headers:{"Content-Type":f,...this._setCookieHeaders()}})},setCookie(g,f,y={}){let $=`${g}=${encodeURIComponent(f)}`;return y.maxAge!==void 0&&($+=`; Max-Age=${y.maxAge}`),y.expires&&($+=`; Expires=${y.expires.toUTCString()}`),y.path&&($+=`; Path=${y.path}`),y.domain&&($+=`; Domain=${y.domain}`),y.secure&&($+="; Secure"),y.httpOnly&&($+="; HttpOnly"),y.sameSite&&($+=`; SameSite=${y.sameSite}`),D.set(g,$),x},getCookie(g){return O.get(g)},deleteCookie(g,f={}){return x.setCookie(g,"",{...f,maxAge:0,path:f.path||"/"})},setHeader(g,f){return S.set(g,f),x},getHeader(g){return S.get(g)||void 0},status(g){return m=g,x},_setCookieHeaders(){let g={};return D.size>0&&(g["Set-Cookie"]=Array.from(D.values())),g}};return x}function ke(s,e){let t=s.headers.get("x-forwarded-for");if(t)return t.split(",").map(o=>o.trim())[0]||"unknown";let r=s.headers.get("x-real-ip");if(r)return r;if(e)try{let o=e.requestIP?.(s);if(o?.address)return o.address}catch{}return "unknown"}function Te(s,e){let t=new Headers;if(!e.security||typeof e.security!="object"||!e.security.cors)return t;let r=typeof e.security.cors=="object"?e.security.cors:{},n=s.headers.get("Origin");if(n){typeof r.origin=="function"?r.origin(n)&&t.set("Access-Control-Allow-Origin",n):Array.isArray(r.origin)?r.origin.includes(n)&&t.set("Access-Control-Allow-Origin",n):typeof r.origin=="string"?t.set("Access-Control-Allow-Origin",r.origin):t.set("Access-Control-Allow-Origin",n);let o=r.methods||["GET","POST","PUT","DELETE","PATCH","OPTIONS"];t.set("Access-Control-Allow-Methods",o.join(", "));let a=r.allowedHeaders||["Content-Type","Authorization","X-Requested-With"];t.set("Access-Control-Allow-Headers",a.join(", ")),r.credentials&&t.set("Access-Control-Allow-Credentials","true"),r.maxAge&&t.set("Access-Control-Max-Age",r.maxAge.toString());}return t}var Je=Ae;
2
- Object.defineProperty(exports,"DB",{enumerable:true,get:function(){return pe.DB}});Object.defineProperty(exports,"blob",{enumerable:true,get:function(){return pe.blob}});Object.defineProperty(exports,"column",{enumerable:true,get:function(){return pe.column}});Object.defineProperty(exports,"defaultValue",{enumerable:true,get:function(){return pe.defaultValue}});Object.defineProperty(exports,"index",{enumerable:true,get:function(){return pe.index}});Object.defineProperty(exports,"integer",{enumerable:true,get:function(){return pe.integer}});Object.defineProperty(exports,"notNull",{enumerable:true,get:function(){return pe.notNull}});Object.defineProperty(exports,"numeric",{enumerable:true,get:function(){return pe.numeric}});Object.defineProperty(exports,"primaryKey",{enumerable:true,get:function(){return pe.primaryKey}});Object.defineProperty(exports,"real",{enumerable:true,get:function(){return pe.real}});Object.defineProperty(exports,"references",{enumerable:true,get:function(){return pe.references}});Object.defineProperty(exports,"table",{enumerable:true,get:function(){return pe.table}});Object.defineProperty(exports,"text",{enumerable:true,get:function(){return pe.text}});Object.defineProperty(exports,"unique",{enumerable:true,get:function(){return pe.unique}});exports.AppError=I;exports.DatabaseError=ue;exports.I18nManager=B;exports.Logger=K;exports.RateLimitError=ce;exports.Router=X;exports.SecurityManager=W;exports.StaticFileServer=q;exports.TimeoutError=Z;exports.ValidationError=M;exports.createStatic=xe;exports.default=Je;exports.getCurrentLanguage=Le;exports.getI18n=G;exports.getSupportedLanguages=$e;exports.initI18n=ne;exports.server=Ae;exports.setLanguage=Se;exports.t=ve;//# sourceMappingURL=main.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),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=main.cjs.map
3
3
  //# sourceMappingURL=main.cjs.map