@stacksjs/bun-router 0.1.17 → 0.1.20
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 +17 -0
- package/dist/chunk-mpyfk9k4.js +357 -0
- package/dist/chunk-q4ktdehf.js +82 -0
- package/dist/chunk-sr7yt36v.js +102 -0
- package/dist/cli.js +8 -8
- package/dist/container/index.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -103
- package/dist/response/markers.d.ts +2 -0
- package/dist/response/response-factory.d.ts +0 -3
- package/dist/router/index.d.ts +1 -105
- package/dist/router/middleware-chain.d.ts +10 -0
- package/dist/router/router.d.ts +1 -1
- package/dist/router/runtime.d.ts +107 -0
- package/dist/runtime.d.ts +16 -0
- package/dist/runtime.js +2 -0
- package/package.json +11 -1
- package/dist/chunk-7s1kcj7w.js +0 -357
- package/dist/chunk-sccx6r6k.js +0 -82
package/README.md
CHANGED
|
@@ -49,6 +49,23 @@ route.serve({
|
|
|
49
49
|
})
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Runtime Entry
|
|
53
|
+
|
|
54
|
+
Frameworks and API servers that only need route registration and serving can
|
|
55
|
+
import `@stacksjs/bun-router/runtime`. It exposes the registered `Router`, typed
|
|
56
|
+
routing, request context, response factories, and compression helpers without
|
|
57
|
+
loading root-only auth, container, session, or testing exports.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { Router } from '@stacksjs/bun-router/runtime'
|
|
61
|
+
|
|
62
|
+
const router = new Router()
|
|
63
|
+
router.get('/health', () => ({ ok: true }))
|
|
64
|
+
await router.serve({ port: 3000 })
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The root `@stacksjs/bun-router` entry keeps its complete existing API.
|
|
68
|
+
|
|
52
69
|
## Action Classes
|
|
53
70
|
|
|
54
71
|
Action classes provide a clean way to organize your route handlers. Create a class that implements a `handle` method:
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var ge=Object.defineProperty;var ye=(t)=>t;function be(t,s){this[t]=ye.bind(null,s)}var At=(t,s)=>{for(var r in s)ge(t,r,{get:s[r],enumerable:!0,configurable:!0,set:be.bind(s,r)})};var we=import.meta.require;import ve from"process";var Ze={verbose:!1,routesPath:"routes",apiRoutesPath:"routes/api.ts",webRoutesPath:"routes/web.ts",apiPrefix:"/api",webPrefix:"",defaultMiddleware:{api:["security","helmet","cors","rate_limit","json_body","request_id"],web:["security","helmet","ddos_protection","session","csrf"]},docs:{output:"api-reference.md",groupBy:"path",includeExamples:!0,title:"API Reference",description:"API documentation for the application.",version:"1.0.0",baseUrl:"http://localhost:3000",contact:{name:"API Support",email:"support@example.com",url:"https://example.com/support"},security:{bearer:{type:"http",scheme:"bearer",bearerFormat:"JWT"}}},server:{port:3000,hostname:"localhost",development:ve.env.NODE_ENV!=="production",cors:{enabled:!0,origin:"*",methods:["GET","POST","PUT","DELETE","PATCH"],allowedHeaders:["Content-Type","Authorization"],exposedHeaders:["X-Request-Id"],credentials:!1,maxAge:86400},rateLimit:{enabled:!0,max:100,timeWindow:60000,message:"Too many requests, please try again later"},compression:{enabled:!0,level:6,threshold:1024},static:{enabled:!0,dir:"public",maxAge:86400},performance:{cache:{enabled:!1,type:"memory",ttl:3600},prefetch:{enabled:!1,paths:[],maxConcurrent:5},optimization:{minify:!1,compress:!1,treeshake:!1,lazyLoad:!1,chunkSize:50000},monitoring:{enabled:!1,metrics:{responseTime:!0,memoryUsage:!0,cpuUsage:!0,errorRate:!0,requestRate:!0,cacheStats:!0},tracing:{enabled:!1,sampleRate:0.1,exporters:["console"],propagation:["w3c"]},logging:{level:"info",format:"json",destination:"console"}}},security:{schemes:{},rateLimit:{enabled:!0,max:100,timeWindow:60000},cors:{enabled:!0,origin:"*",methods:["GET","POST","PUT","DELETE","PATCH"]},csrf:{enabled:!0,secret:"csrf-secret",cookie:{name:"csrf-token",options:{httpOnly:!0,secure:!0,sameSite:"strict"}}},helmet:{enabled:!0,contentSecurityPolicy:{directives:{"default-src":["'self'"],"script-src":["'self'","'unsafe-inline'"],"style-src":["'self'","'unsafe-inline'"],"img-src":["'self'","data:","https:"],"font-src":["'self'"],"connect-src":["'self'"],"media-src":["'self'"],"object-src":["'none'"],"child-src":["'self'"],"worker-src":["'self'"],"frame-ancestors":["'none'"],"form-action":["'self'"],"base-uri":["'self'"],"manifest-src":["'self'"]}},xssFilter:!0,noSniff:!0,frameOptions:"DENY",hidePoweredBy:!0,hsts:{maxAge:31536000,includeSubDomains:!0,preload:!0},referrerPolicy:"strict-origin-when-cross-origin"},ddos:{enabled:!0,maxRequestsPerSecond:10,maxRequestsPerMinute:100,maxRequestsPerHour:1000,burstLimit:20,windowSize:60000,blockDuration:300000,whitelistedIPs:[],blacklistedIPs:[],trustProxy:!0,store:"memory"},inputValidation:{enabled:!0,sanitizeByDefault:!0,strictMode:!1,allowUnknownFields:!0,maxDepth:10},attackPrevention:{enabled:!0,sqlInjection:!0,xss:!0,pathTraversal:!0,commandInjection:!0,ldapInjection:!0,xxe:!0,customPatterns:[]},requestFiltering:{enabled:!0,blockSuspiciousPatterns:!0,maxRequestsPerMinute:1000,blockUserAgents:["sqlmap","nikto","nessus","openvas","nmap","masscan","zap","w3af"],allowedMethods:["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"],requireUserAgent:!1,maxBodySize:10485760,maxUrlLength:2048,maxHeaderSize:8192,allowedContentTypes:["application/json","application/x-www-form-urlencoded","multipart/form-data","text/plain","text/html","application/xml","text/xml"]},ipFiltering:{enabled:!1,whitelist:[],blacklist:[],blockPrivateIPs:!1,blockCloudProviders:!1,geoBlocking:{enabled:!1,allowedCountries:[],blockedCountries:[]}},responseSecurity:{enabled:!0,removeServerHeaders:!0,addSecurityHeaders:!0,sanitizeErrors:!0,preventInfoDisclosure:!0},auth:{jwt:{secret:"jwt-secret",expiresIn:"1h",algorithm:"HS256"},session:{enabled:!1,secret:"session-secret",name:"session",resave:!1,rolling:!0,saveUninitialized:!1,cookie:{maxAge:86400000,secure:!0,httpOnly:!0,sameSite:"strict"}}}},cluster:{enabled:!1,workers:"auto",sticky:!0},gracefulShutdown:{enabled:!0,timeout:30000,signals:["SIGTERM","SIGINT"],forceTimeout:1e4},middleware:{order:[],global:[]},hooks:{}}},z=null;async function xr(){if(!z){let{loadConfig:t}=await import("./chunk-9y37n6xs.js");z=await t({name:"router",defaultConfig:Ze})}return z}var e=Ze;function et(t){if(!t||!t.startsWith("Basic "))return null;try{let s=t.split(" ")[1],r=atob(s),[n,i]=r.split(":");return{username:n,password:i}}catch(s){return null}}function Se(t){if(!t||!t.startsWith("Bearer "))return null;return t.split(" ")[1]}function tt(t,s="header",r="X-API-Key"){switch(s){case"header":return t.headers.get(r)||null;case"query":return new URL(t.url).searchParams.get(r);case"cookie":if(t.cookies){if(typeof t.cookies.get==="function")return t.cookies.get(r)||null;return t.cookies[r]||null}return null;default:return null}}class x{options;constructor(t){this.options={source:"header",key:"Authorization",attachUser:!0,...t}}async handle(t,s){let r=null;if(this.options.credentialsExtractor)r=await this.options.credentialsExtractor(t);else switch(this.options.type){case"basic":{let l=t.headers.get(this.options.key||"Authorization");r=et(l||"");break}case"bearer":case"jwt":{let l=t.headers.get(this.options.key||"Authorization");r=Se(l||"");break}case"api-key":{r=tt(t,this.options.source,this.options.key);break}case"oauth2":{let l=t.headers.get(this.options.key||"Authorization");r=Se(l||"");break}}if(!r){let l={};if(this.options.type==="basic"){let d=this.options.realm||"Secure Area";l["WWW-Authenticate"]=`Basic realm="${d}"`}return new Response("Unauthorized",{status:401,headers:l})}if(!await this.options.validator(r,t))return new Response("Unauthorized",{status:401});if(this.options.userExtractor&&this.options.attachUser){let l=await this.options.userExtractor(r,t);t.user=l}return await s()||new Response("Not Found",{status:404})}}function Ot(t,s={}){return new x({type:"basic",validator:t,...s})}function It(t,s={}){return new x({type:"bearer",validator:t,...s})}function Ft(t,s={}){return new x({type:"jwt",validator:t,...s})}function Nt(t,s={}){return new x({type:"api-key",validator:t,...s})}function Dt(t,s={}){return new x({type:"oauth2",validator:t,...s})}var _={"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, POST, PUT, DELETE, PATCH, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization, X-Requested-With, Accept, Origin","Access-Control-Max-Age":"86400"};class E{resolveAllowOrigin(t,s,r){if(Array.isArray(t)){if(r&&t.includes(r))return{value:r,vary:!0};return{value:null,vary:!0}}let n=t||"*";if(n==="*"){if(s){if(r)return{value:r,vary:!0};return{value:null,vary:!0}}return{value:"*",vary:!1}}return{value:n,vary:!1}}getCorsHeaders(t){let s=e.server?.cors,r=t.headers.get("origin");if(s&&s.enabled){let n=Boolean(s.credentials),{value:i,vary:l}=this.resolveAllowOrigin(s.origin,n,r),d={"Access-Control-Allow-Methods":Array.isArray(s.methods)?s.methods.join(", "):_["Access-Control-Allow-Methods"],"Access-Control-Allow-Headers":Array.isArray(s.allowedHeaders)?s.allowedHeaders.join(", "):_["Access-Control-Allow-Headers"],"Access-Control-Max-Age":String(s.maxAge||86400)};if(i!==null)d["Access-Control-Allow-Origin"]=i;if(n&&i!==null&&i!=="*")d["Access-Control-Allow-Credentials"]="true";if(l)d.Vary="Origin";return d}return{..._}}async handle(t,s){let r=this.getCorsHeaders(t);if(t.method==="OPTIONS")return new Response(null,{status:204,headers:r});let n=(i)=>{let l=new Headers(i.headers);return Object.entries(r).forEach(([d,u])=>{l.set(d,u)}),new Response(i.body,{status:i.status,statusText:i.statusText,headers:l})};try{let i=await s();if(!i)return new Response(JSON.stringify({error:"Not Found"}),{status:404,headers:{...r,"Content-Type":"application/json"}});return n(i)}catch(i){return console.error("[CORS] Error in middleware chain:",i),new Response(JSON.stringify({error:"Internal Server Error",message:i instanceof Error?i.message:String(i)}),{status:500,headers:{...r,"Content-Type":"application/json"}})}}}var xe;function c(){return xe??=we("crypto")}var Re=1e4,Te=7200000;class o{static tokens=new Map;async handle(t,s){let r=e.server?.security?.csrf??{},n=t.method.toUpperCase();if(["GET","HEAD","OPTIONS",...r?.ignoreMethods||[]].includes(n)){let g=this.generateToken(r?.secret||"csrf-secret"),y=await s();if(!y)return new Response("Not Found",{status:404});let b=r?.cookie?.name||"csrf-token",v=[];if(v.push(`${b}=${g}`),v.push("Path=/"),r?.cookie?.options?.httpOnly)v.push("HttpOnly");if(r?.cookie?.options?.secure)v.push("Secure");if(r?.cookie?.options?.sameSite)v.push(`SameSite=${r.cookie.options.sameSite}`);let S=new Headers(y.headers);return S.append("Set-Cookie",v.join("; ")),o.storeToken(g),new Response(y.body,{status:y.status,statusText:y.statusText,headers:S})}let l=t.headers.get("authorization")??t.headers.get("Authorization");if(l&&/^Bearer\s+\S/i.test(l))return await s()||new Response("Not Found",{status:404});let d=t.headers.get("X-CSRF-TOKEN")||t.jsonBody?.csrf_token||t.jsonBody?._token||null,u=typeof d==="string"?d:null,m=this.parseCookies(t)[r?.cookie?.name||"csrf-token"];if(!u||!m||!o.safeCompare(u,m)||!o.isTokenValid(u))return new Response(JSON.stringify({error:"CSRF token validation failed"}),{status:403,headers:{"Content-Type":"application/json"}});return await s()||new Response("Not Found",{status:404})}static safeCompare(t,s){let r=Buffer.from(t),n=Buffer.from(s);if(r.length!==n.length)return!1;return c().timingSafeEqual(r,n)}static storeToken(t){if(o.tokens.size>=Re){let s=o.tokens.keys().next().value;if(s!==void 0)o.tokens.delete(s)}o.tokens.set(t,Date.now())}static isTokenValid(t){let s=o.tokens.get(t);if(s===void 0)return!1;if(Date.now()-s>Te)return o.tokens.delete(t),!1;return!0}generateToken(t){let{createHash:s,randomBytes:r}=c(),n=r(16).toString("hex");return s("sha256").update(`${n}${t}`).digest("hex")}parseCookies(t){let s=t.headers.get("cookie");if(!s)return{};let r={};for(let n of s.split(";")){let i=n.indexOf("=");if(i===-1)continue;let l=n.slice(0,i).trim();if(!l)continue;r[l]=n.slice(i+1).trim()}return r}}class P{async handle(t,s){let r=t.headers.get("content-type");if(r&&r.includes("application/json"))try{let l=await t.clone().json();Object.defineProperty(t,"jsonBody",{value:l,writable:!0,enumerable:!0,configurable:!0})}catch{return new Response(JSON.stringify({error:"Invalid JSON payload"}),{status:400,headers:{"Content-Type":"application/json"}})}return await s()||new Response("Not Found",{status:404})}}function ke(t={}){let s=new ie(t);return async(n,i)=>s.handle(n,i)}class ie{limiterPromise;options;constructor(t={}){let s=e.server?.rateLimit||{},r=e.server?.security?.rateLimit||{};if(this.options={windowMs:t.windowMs||s.timeWindow||r.timeWindow||60000,maxRequests:t.maxRequests||s.max||r.max||100,standardHeaders:t.standardHeaders??!0,legacyHeaders:t.legacyHeaders??!1,skipFailedRequests:t.skipFailedRequests??s.advanced?.skipFailedRequests??r.advanced?.skipFailedRequests??!1,draftMode:t.draftMode??!1,keyGenerator:t.keyGenerator,handler:t.handler||(s.message?(n,i)=>new Response(s.message,{status:429}):void 0),skip:t.skip,algorithm:t.algorithm||"fixed-window",storage:t.storage},!this.options.storage&&s.stores?.type==="redis"&&s.stores.redis){if(this.options.storage="redis",s.stores.redis)this.options.redis={url:s.stores.redis.url,prefix:s.stores.redis.prefix||"ratelimit:"}}if(s.advanced){if(s.advanced.tokensPerInterval&&this.options.algorithm==="token-bucket")this.options.tokenBucket={tokensPerInterval:s.advanced.tokensPerInterval,interval:s.advanced.interval||this.options.windowMs,burst:s.advanced.burst}}}getLimiter(){return this.limiterPromise??=this.initLimiter(),this.limiterPromise}async initLimiter(){let t={...this.options};t.windowMs=this.options.windowMs,t.maxRequests=this.options.maxRequests,t.standardHeaders=this.options.standardHeaders,t.legacyHeaders=this.options.legacyHeaders,t.skipFailedRequests=this.options.skipFailedRequests,t.keyGenerator=this.options.keyGenerator,t.skip=this.options.skip,t.algorithm=this.options.algorithm,t.draftMode=this.options.draftMode,t.handler=this.options.handler?async(n,i)=>this.options.handler?.(n,{remaining:i.remaining,limit:i.limit,resetTime:i.resetTime})||this.defaultHandler(n,i):void 0;let{log:s,warn:r}=console;console.log=()=>{},console.warn=()=>{};try{let{createRateLimiter:n}=await import("ts-rate-limiter");return await n(t)}finally{console.log=s,console.warn=r}}defaultHandler(t,s){let r={};if(this.options.standardHeaders)r["RateLimit-Limit"]=String(s.limit),r["RateLimit-Remaining"]=String(Math.max(0,s.limit-s.current)),r["RateLimit-Reset"]=String(Math.ceil(s.resetTime/1000));if(this.options.legacyHeaders)r["X-RateLimit-Limit"]=String(s.limit),r["X-RateLimit-Remaining"]=String(Math.max(0,s.limit-s.current)),r["X-RateLimit-Reset"]=String(Math.ceil(s.resetTime/1000)),r["Retry-After"]=String(Math.ceil(s.remaining/1000));let n=e.server?.rateLimit?.message||"Too Many Requests";return new Response(n,{status:429,headers:r})}async handle(t,s){if(e.server?.rateLimit?.enabled===!1)return await s()||new Response("Not Found",{status:404});try{let n=await(await this.getLimiter()).check(t);if(!n.allowed)return this.options.handler?await this.options.handler(t,{remaining:n.remaining,limit:n.limit,resetTime:n.resetTime}):this.defaultHandler(t,n);let i=await s();if(!i)return new Response("Not Found",{status:404});let l=new Headers(i.headers);if(this.options.standardHeaders)l.set("RateLimit-Limit",String(n.limit)),l.set("RateLimit-Remaining",String(Math.max(0,n.limit-n.current))),l.set("RateLimit-Reset",String(Math.ceil(n.resetTime/1000)));if(this.options.legacyHeaders)l.set("X-RateLimit-Limit",String(n.limit)),l.set("X-RateLimit-Remaining",String(Math.max(0,n.limit-n.current))),l.set("X-RateLimit-Reset",String(Math.ceil(n.resetTime/1000)));return new Response(i.body,{status:i.status,statusText:i.statusText,headers:l})}catch(r){return console.error("[RateLimit] Error during rate limiting:",r),await s()||new Response("Not Found",{status:404})}}}function Ee(t={}){return ke(t)}class M{async handle(t,s){let r=t.headers.get("X-Request-ID")||c().randomUUID();Object.defineProperty(t,"requestId",{value:r,writable:!1,enumerable:!0,configurable:!1});let n=await s();if(!n)return new Response("Not Found",{status:404});let i=new Headers(n.headers);if(!i.has("X-Request-ID"))i.set("X-Request-ID",r);return new Response(n.body,{status:n.status,statusText:n.statusText,headers:i})}}class a extends Error{code;statusCode;constructor(t,s){super(s);this.name="SignatureError",this.code=t,this.statusCode=401}}class rt{nonces=new Map;cleanupInterval=null;constructor(t=60000){this.cleanupInterval=setInterval(()=>this.cleanup(),t),this.cleanupInterval.unref?.()}has(t){let s=this.nonces.get(t);if(s===void 0)return!1;if(Date.now()>s)return this.nonces.delete(t),!1;return!0}set(t,s=300){this.nonces.set(t,Date.now()+s*1000)}cleanup(){let t=Date.now();for(let[s,r]of this.nonces.entries())if(t>r)this.nonces.delete(s)}destroy(){if(this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null;this.nonces.clear()}}class k{options;constructor(t){this.options={secret:t.secret,algorithm:t.algorithm??"sha256",signatureHeader:t.signatureHeader??"X-Signature",timestampHeader:t.timestampHeader??"X-Timestamp",keyIdHeader:t.keyIdHeader??"X-Key-Id",nonceHeader:t.nonceHeader??"X-Nonce",maxAge:t.maxAge??300,requireTimestamp:t.requireTimestamp??!0,requireNonce:t.requireNonce??!1,signedParts:t.signedParts??["method","path","timestamp","body"],signedHeaders:t.signedHeaders??[],encoding:t.encoding??"hex",onError:t.onError,exclude:t.exclude,nonceStore:t.nonceStore,stringToSign:t.stringToSign}}async handle(t,s){if(this.shouldSkip(t))return s();try{return await this.verifySignature(t),s()}catch(r){if(r instanceof a){if(this.options.onError)return this.options.onError(r,t);return this.defaultErrorResponse(r)}throw r}}shouldSkip(t){if(!this.options.exclude)return!1;if(typeof this.options.exclude==="function")return this.options.exclude(t);let s=new URL(t.url);return this.options.exclude.some((r)=>s.pathname===r||s.pathname.startsWith(`${r}/`))}async verifySignature(t){let s=t.headers.get(this.options.signatureHeader);if(!s)throw new a("MISSING_SIGNATURE",`Missing ${this.options.signatureHeader} header`);let r=t.headers.get(this.options.timestampHeader);if(this.options.requireTimestamp){if(!r)throw new a("MISSING_TIMESTAMP",`Missing ${this.options.timestampHeader} header`);this.validateTimestamp(r)}let n=t.headers.get(this.options.nonceHeader);if(this.options.requireNonce){if(!n)throw new a("MISSING_NONCE",`Missing ${this.options.nonceHeader} header`);await this.validateNonce(n)}let i=await this.getSecret(t);if(!i)throw new a("INVALID_KEY","Invalid or missing API key");let l=await this.buildStringToSign(t,r||"",n||void 0),d=await this.calculateSignature(l,i);if(!this.timingSafeEqual(s,d))throw new a("SIGNATURE_MISMATCH","Invalid signature");if(this.options.requireNonce&&n&&this.options.nonceStore)await this.options.nonceStore.set(n,this.options.maxAge)}async getSecret(t){if(typeof this.options.secret==="string")return this.options.secret;let s=t.headers.get(this.options.keyIdHeader);if(!s)throw new a("MISSING_KEY_ID",`Missing ${this.options.keyIdHeader} header`);return this.options.secret(s)}validateTimestamp(t){let s=Number.parseInt(t,10);if(Number.isNaN(s))throw new a("EXPIRED_TIMESTAMP","Invalid timestamp format");let n=Math.floor(Date.now()/1000)-s;if(n>this.options.maxAge)throw new a("EXPIRED_TIMESTAMP",`Request timestamp expired (${n}s old, max ${this.options.maxAge}s)`);if(n<-30)throw new a("FUTURE_TIMESTAMP","Request timestamp is in the future")}async validateNonce(t){if(!this.options.nonceStore)return;if(await this.options.nonceStore.has(t))throw new a("NONCE_REUSED","Nonce has already been used (possible replay attack)")}async buildStringToSign(t,s,r){if(this.options.stringToSign)return this.options.stringToSign(t,s,r);let n=new URL(t.url),i=[];for(let l of this.options.signedParts)switch(l){case"method":i.push(t.method.toUpperCase());break;case"path":i.push(n.pathname);break;case"query":i.push(n.search);break;case"timestamp":i.push(s);break;case"nonce":if(r)i.push(r);break;case"body":if(t.body){let d=await t.clone().text();i.push(d)}break;case"headers":for(let d of this.options.signedHeaders){let u=t.headers.get(d);if(u)i.push(`${d.toLowerCase()}:${u}`)}break}return i.join(`
|
|
3
|
+
`)}async calculateSignature(t,s){let r=new TextEncoder,n=r.encode(s),i=r.encode(t),l={sha256:"SHA-256",sha384:"SHA-384",sha512:"SHA-512"}[this.options.algorithm],d=await crypto.subtle.importKey("raw",n,{name:"HMAC",hash:l},!1,["sign"]),u=await crypto.subtle.sign("HMAC",d,i);if(this.options.encoding==="base64")return btoa(String.fromCharCode(...new Uint8Array(u)));return Array.from(new Uint8Array(u)).map((p)=>p.toString(16).padStart(2,"0")).join("")}timingSafeEqual(t,s){if(t.length!==s.length)return!1;let r=0;for(let n=0;n<t.length;n++)r|=t.charCodeAt(n)^s.charCodeAt(n);return r===0}defaultErrorResponse(t){return new Response(JSON.stringify({error:{code:t.code,message:t.message}}),{status:t.statusCode,headers:{"Content-Type":"application/json","WWW-Authenticate":"HMAC-SHA256"}})}}function qt(t){return new k(t)}async function Ht(t,s,r={}){let{algorithm:n="sha256",signedParts:i=["method","path","timestamp","body"],signedHeaders:l=[],signatureHeader:d="X-Signature",timestampHeader:u="X-Timestamp",nonceHeader:p="X-Nonce",keyId:m,keyIdHeader:h="X-Key-Id",encoding:g="hex"}=r,y=Math.floor(Date.now()/1000).toString(),b=crypto.randomUUID(),v=new URL(t.url),S=[];for(let B of i)switch(B){case"method":S.push(t.method.toUpperCase());break;case"path":S.push(v.pathname);break;case"query":S.push(v.search);break;case"timestamp":S.push(y);break;case"nonce":S.push(b);break;case"body":if(t.body){let U=await t.clone().text();S.push(U)}break;case"headers":for(let U of l){let Y=t.headers.get(U);if(Y)S.push(`${U.toLowerCase()}:${Y}`)}break}let te=S.join(`
|
|
4
|
+
`),K=new TextEncoder,se=K.encode(s),re=K.encode(te),ne={sha256:"SHA-256",sha384:"SHA-384",sha512:"SHA-512"}[n],fe=await crypto.subtle.importKey("raw",se,{name:"HMAC",hash:ne},!1,["sign"]),Q=await crypto.subtle.sign("HMAC",fe,re),L;if(g==="base64")L=btoa(String.fromCharCode(...new Uint8Array(Q)));else L=Array.from(new Uint8Array(Q)).map((B)=>B.toString(16).padStart(2,"0")).join("");let C=new Headers(t.headers);if(C.set(d,L),C.set(u,y),C.set(p,b),m)C.set(h,m);return new Request(t.url,{method:t.method,headers:C,body:t.body,redirect:t.redirect,integrity:t.integrity,signal:t.signal})}async function Bt(t,s,r,n="sha256",i="hex"){let l=new TextEncoder,d=l.encode(r),u=l.encode(t),p={sha256:"SHA-256",sha384:"SHA-384",sha512:"SHA-512"}[n],m=await crypto.subtle.importKey("raw",d,{name:"HMAC",hash:p},!1,["sign"]),h=await crypto.subtle.sign("HMAC",m,u),g;if(i==="base64")g=btoa(String.fromCharCode(...new Uint8Array(h)));else g=Array.from(new Uint8Array(h)).map((b)=>b.toString(16).padStart(2,"0")).join("");if(s.length!==g.length)return!1;let y=0;for(let b=0;b<s.length;b++)y|=s.charCodeAt(b)^g.charCodeAt(b);return y===0}class w{defaultTtl;sessions=new Map;cleanupInterval=null;constructor(t=86400){this.defaultTtl=t;this.cleanupInterval=setInterval(()=>this.cleanup(),300000)}async get(t){let s=this.sessions.get(t);if(!s)return null;if(Date.now()>s.expiresAt)return this.sessions.delete(t),null;return s.data}async set(t,s,r){let n=Date.now()+(r??this.defaultTtl)*1000;this.sessions.set(t,{data:s,expiresAt:n})}async destroy(t){this.sessions.delete(t)}async touch(t,s,r){let n=this.sessions.get(t);if(n)n.expiresAt=Date.now()+(r??this.defaultTtl)*1000,n.data=s}async all(){let t={},s=Date.now();for(let[r,n]of this.sessions)if(s<=n.expiresAt)t[r]=n.data;return t}async length(){return this.sessions.size}async clear(){this.sessions.clear()}cleanup(){let t=Date.now();for(let[s,r]of this.sessions)if(t>r.expiresAt)this.sessions.delete(s)}dispose(){if(this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null;this.sessions.clear()}}import{existsSync as D,mkdirSync as Ie,readdirSync as H,unlinkSync as j,writeFileSync as Z,readFileSync as J}from"fs";import{join as q}from"path";import{tmpdir as Ae}from"os";class oe{defaultTtl;dir;cleanupInterval=null;constructor(t=86400,s){this.defaultTtl=t;if(this.dir=s||q(Ae(),"bun-router-sessions"),!D(this.dir))Ie(this.dir,{recursive:!0});this.cleanupInterval=setInterval(()=>this.cleanup(),600000)}filePath(t){let s=t.replace(/[^a-zA-Z0-9_-]/g,"");return q(this.dir,`${s}.json`)}async get(t){let s=this.filePath(t);if(!D(s))return null;try{let r=J(s,"utf-8"),n=JSON.parse(r);if(Date.now()>n.expiresAt)return j(s),null;return n.data}catch{return null}}async set(t,s,r){let n={data:s,expiresAt:Date.now()+(r??this.defaultTtl)*1000};Z(this.filePath(t),JSON.stringify(n),"utf-8")}async destroy(t){let s=this.filePath(t);if(D(s))j(s)}async touch(t,s,r){let n=this.filePath(t);if(!D(n))return;let i={data:s,expiresAt:Date.now()+(r??this.defaultTtl)*1000};Z(n,JSON.stringify(i),"utf-8")}async all(){let t={},s=Date.now();try{let r=H(this.dir).filter((n)=>n.endsWith(".json"));for(let n of r){let i=J(q(this.dir,n),"utf-8"),l=JSON.parse(i);if(s<=l.expiresAt){let d=n.replace(".json","");t[d]=l.data}}}catch{}return t}async length(){try{return H(this.dir).filter((t)=>t.endsWith(".json")).length}catch{return 0}}async clear(){try{let t=H(this.dir).filter((s)=>s.endsWith(".json"));for(let s of t)j(q(this.dir,s))}catch{}}cleanup(){let t=Date.now();try{let s=H(this.dir).filter((r)=>r.endsWith(".json"));for(let r of s){let n=q(this.dir,r),i=J(n,"utf-8"),l=JSON.parse(i);if(t>l.expiresAt)j(n)}}catch{}}dispose(){if(this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}}class ae{client;defaultTtl;prefix;constructor(t,s=86400,r="sess:"){this.client=t;this.defaultTtl=s;this.prefix=r}key(t){return`${this.prefix}${t}`}async get(t){let s=await this.client.get(this.key(t));if(!s)return null;try{return JSON.parse(s)}catch{return null}}async set(t,s,r){let n=this.key(t),i=r??this.defaultTtl;await this.client.set(n,JSON.stringify(s),"EX",i)}async destroy(t){await this.client.del(this.key(t))}async touch(t,s,r){let n=this.key(t),i=r??this.defaultTtl;await this.client.set(n,JSON.stringify(s),"EX",i)}async all(){let t=await this.client.keys(`${this.prefix}*`),s={};for(let r of t){let n=await this.client.get(r);if(n)try{let i=r.slice(this.prefix.length);s[i]=JSON.parse(n)}catch{}}return s}async length(){return(await this.client.keys(`${this.prefix}*`)).length}async clear(){let t=await this.client.keys(`${this.prefix}*`);if(t.length>0)await this.client.del(t)}}class ce{adapter;defaultTtl;cleanupInterval=null;constructor(t,s=86400){this.adapter=t;this.defaultTtl=s;this.cleanupInterval=setInterval(()=>{let r=Date.now()-this.defaultTtl*1000;this.adapter.deleteExpiredSessions(r)},1800000)}async get(t){let s=await this.adapter.findSession(t);if(!s)return null;let r=Date.now()-this.defaultTtl*1000;if(s.last_activity<r)return await this.adapter.deleteSession(t),null;try{return JSON.parse(s.payload)}catch{return null}}async set(t,s,r){await this.adapter.upsertSession(t,JSON.stringify(s),Date.now())}async destroy(t){await this.adapter.deleteSession(t)}async touch(t,s,r){await this.adapter.upsertSession(t,JSON.stringify(s),Date.now())}async all(){let t=await this.adapter.getAllSessions(),s={},r=Date.now()-this.defaultTtl*1000;for(let n of t)if(n.last_activity>=r)try{s[n.id]=JSON.parse(n.payload)}catch{}return s}async length(){return this.adapter.countSessions()}async clear(){await this.adapter.clearAllSessions()}dispose(){if(this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null}}function Tr(t){let s=t.ttl??86400;switch(t.driver){case"memory":return new w(s);case"file":return new oe(s,t.file?.dir);case"redis":{if(!t.redis?.client)throw Error("Redis client is required for redis session driver");return new ae(t.redis.client,s,t.redis.prefix)}case"database":{if(!t.database?.adapter)throw Error("Database adapter is required for database session driver");return new ce(t.database.adapter,s)}default:return new w(s)}}class Pe{sessionId;data;store;flashedKeys=[];previousFlash={};dirty=!1;constructor(t,s,r){this.sessionId=t,this.data=s,this.store=r,this.previousFlash={...s.flash||{}}}get id(){return this.sessionId}get(t){if(this.data.flash&&t in this.data.flash)return this.data.flash[t];if(this.data.data&&t in this.data.data)return this.data.data[t];return}set(t,s){if(!this.data.data)this.data.data={};this.data.data[t]=s,this.dirty=!0}has(t){return this.data.data&&t in this.data.data||this.data.flash&&t in this.data.flash||!1}forget(t){if(this.data.data)delete this.data.data[t],this.dirty=!0}all(){return{...this.data.data||{},...this.data.flash||{}}}flash(t,s){if(!this.data.flash)this.data.flash={};this.data.flash[t]=s,this.flashedKeys.push(t),this.dirty=!0}getFlash(t){return this.previousFlash[t]}keep(t){for(let s of t)if(s in this.previousFlash)this.flash(s,this.previousFlash[s])}reflash(){for(let[t,s]of Object.entries(this.previousFlash))this.flash(t,s)}async regenerate(){let t=this.sessionId;return this.sessionId=le(),await this.store.set(this.sessionId,this.data),await this.store.destroy(t),this.sessionId}async invalidate(){let t=this.sessionId;return this.sessionId=le(),this.data={id:this.sessionId},await this.store.destroy(t),await this.store.set(this.sessionId,this.data),this.sessionId}async save(){if(this.data.flash){let t={};for(let s of this.flashedKeys)if(this.data.flash[s]!==void 0)t[s]=this.data.flash[s];this.data.flash=Object.keys(t).length>0?t:void 0}await this.store.set(this.sessionId,this.data)}async destroy(){await this.store.destroy(this.sessionId),this.data={}}}function le(){let t=new Uint8Array(32);return crypto.getRandomValues(t),Array.from(t,(s)=>s.toString(16).padStart(2,"0")).join("")}class A{store;constructor(t){this.store=t?.store||new w}async handle(t,s){let r=e.server?.security?.auth?.session,n=r?.name||"session",i=t.cookies?.get(n)||"",l=!1;if(!i)i=le(),l=!0;let d=l?null:await this.store.get(i);if(!d)d={id:i},l=!0;let u=new Pe(i,d,this.store);t.session=u;let p=await s();await u.save();let m={maxAge:r?.cookie?.maxAge||86400000,path:r?.cookie?.path||"/"};if(r?.cookie?.httpOnly!==!1)m.httpOnly=!0;if(r?.cookie?.secure)m.secure=!0;if(r?.cookie?.sameSite)m.sameSite=r.cookie.sameSite;if(!t._cookiesToSet)t._cookiesToSet=[];return t._cookiesToSet.push({name:n,value:u.id,options:m}),p||new Response("Not Found",{status:404})}}class O{options;nonces=new Map;constructor(t={}){let s=e.server?.security?.helmet?.contentSecurityPolicy,r={"default-src":["'self'"],"script-src":["'self'"],"style-src":["'self'"],"img-src":["'self'","data:","https:"],"font-src":["'self'"],"connect-src":["'self'"],"media-src":["'self'"],"object-src":["'none'"],"child-src":["'self'"],"worker-src":["'self'"],"frame-ancestors":["'none'"],"form-action":["'self'"],"base-uri":["'self'"],"manifest-src":["'self'"]};this.options={directives:t.directives||typeof s==="object"&&s.directives||r,reportOnly:t.reportOnly??(typeof s==="object"&&s.reportOnly)??!1,reportUri:t.reportUri,reportTo:t.reportTo,useNonces:t.useNonces??!1,nonceLength:t.nonceLength??16,upgradeInsecureRequests:t.upgradeInsecureRequests??!0,blockAllMixedContent:t.blockAllMixedContent??!1}}generateNonce(){let s="";for(let r=0;r<(this.options.nonceLength||16);r++)s+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return s}buildCSPHeader(){let t=[],s=this.options.directives||{};for(let[r,n]of Object.entries(s)){if(r==="upgrade-insecure-requests"||r==="block-all-mixed-content"||r==="disown-opener"){if(n===!0)t.push(r.replace(/([A-Z])/g,"-$1").toLowerCase());continue}if(Array.isArray(n)&&n.length>0){let i=r.replace(/([A-Z])/g,"-$1").toLowerCase();t.push(`${i} ${n.join(" ")}`)}}if(this.options.upgradeInsecureRequests)t.push("upgrade-insecure-requests");if(this.options.blockAllMixedContent)t.push("block-all-mixed-content");if(this.options.reportUri)t.push(`report-uri ${this.options.reportUri}`);if(this.options.reportTo)t.push(`report-to ${this.options.reportTo}`);return t.join("; ")}async handle(t,s){if((e.server?.security?.helmet||{}).contentSecurityPolicy===!1)return await s()||new Response("Not Found",{status:404});let n;if(this.options.useNonces){if(n=this.generateNonce(),this.nonces.set(t.url,n),this.options.directives?.["script-src"])this.options.directives["script-src"]=[...this.options.directives["script-src"],`'nonce-${n}'`];if(this.options.directives?.["style-src"])this.options.directives["style-src"]=[...this.options.directives["style-src"],`'nonce-${n}'`]}if(n)t.nonce=n;let i=await s();if(!i)return new Response("Not Found",{status:404});let l=new Headers(i.headers),d=this.buildCSPHeader();if(d){let u=this.options.reportOnly?"Content-Security-Policy-Report-Only":"Content-Security-Policy";l.set(u,d)}if(this.options.reportTo)l.set("Report-To",JSON.stringify({group:this.options.reportTo,max_age:10886400,endpoints:[{url:this.options.reportUri||"/csp-report"}]}));if(n)this.nonces.delete(t.url);return new Response(i.body,{status:i.status,statusText:i.statusText,headers:l})}getNonce(t){return this.nonces.get(t)}}function jt(t={}){let s=new O(t);return async(r,n)=>s.handle(r,n)}class I{options;requestStore=new Map;cleanupInterval=null;constructor(t={}){let s=e.server?.security?.ddos||{};if(this.options={enabled:t.enabled??s.enabled??!0,maxRequestsPerSecond:t.maxRequestsPerSecond??s.maxRequestsPerSecond??10,maxRequestsPerMinute:t.maxRequestsPerMinute??s.maxRequestsPerMinute??100,maxRequestsPerHour:t.maxRequestsPerHour??s.maxRequestsPerHour??1000,burstLimit:t.burstLimit??s.burstLimit??20,windowSize:t.windowSize??s.windowSize??60000,blockDuration:t.blockDuration??s.blockDuration??300000,whitelistedIPs:t.whitelistedIPs??s.whitelistedIPs??[],blacklistedIPs:t.blacklistedIPs??s.blacklistedIPs??[],trustProxy:t.trustProxy??s.trustProxy??!0,skipSuccessfulRequests:t.skipSuccessfulRequests??s.skipSuccessfulRequests??!1,skipFailedRequests:t.skipFailedRequests??s.skipFailedRequests??!1,keyGenerator:t.keyGenerator??this.defaultKeyGenerator.bind(this),onLimitReached:t.onLimitReached,store:t.store??s.store??"memory",redis:t.redis??s.redis},this.options.store==="memory")this.startCleanupInterval()}defaultKeyGenerator(t){let s=t.headers.get("x-forwarded-for"),r=t.headers.get("x-real-ip"),n=t.headers.get("cf-connecting-ip");if(this.options.trustProxy&&s)return s.split(",")[0].trim();return r||n||"unknown"}startCleanupInterval(){this.cleanupInterval=setInterval(()=>{let t=Date.now();for(let[s,r]of this.requestStore.entries()){if(t-r.lastRequest>this.options.windowSize*2)this.requestStore.delete(s);if(r.blocked&&r.blockExpires&&t>r.blockExpires)r.blocked=!1,r.blockExpires=void 0}},this.options.windowSize/2),this.cleanupInterval.unref?.()}isWhitelisted(t){return this.options.whitelistedIPs?.includes(t)??!1}isBlacklisted(t){return this.options.blacklistedIPs?.includes(t)??!1}getRateLimitInfo(t,s){let r=this.requestStore.get(t);if(!r){if(this.requestStore.size>=1e5){let n=Math.ceil(this.requestStore.size/10);for(let i of this.requestStore.keys())if(this.requestStore.delete(i),--n<=0)break}r={count:0,firstRequest:s,lastRequest:s,blocked:!1},this.requestStore.set(t,r)}if(s-r.firstRequest>this.options.windowSize)r.count=0,r.firstRequest=s;return r}shouldBlock(t,s){if(t.blocked&&t.blockExpires&&s<t.blockExpires)return!0;let r=1000;if(t.count>this.options.burstLimit)return!0;if(t.count>this.options.maxRequestsPerMinute)return!0;return!1}blockIP(t,s){t.blocked=!0,t.blockExpires=s+this.options.blockDuration}createBlockedResponse(t,s){let r=Math.ceil((s.blockExpires-Date.now())/1000),n={"Retry-After":r.toString(),"X-RateLimit-Limit":this.options.maxRequestsPerMinute.toString(),"X-RateLimit-Remaining":"0","X-RateLimit-Reset":Math.ceil(s.blockExpires/1000).toString()};if(this.options.onLimitReached)return this.options.onLimitReached(t,{...s,retryAfter:r});return new Response(JSON.stringify({error:"Too Many Requests",message:"Rate limit exceeded. Please try again later.",retryAfter:r}),{status:429,headers:{"Content-Type":"application/json",...n}})}async handle(t,s){if(!this.options.enabled)return await s()||new Response("Not Found",{status:404});let r=Date.now(),n=this.options.keyGenerator(t);if(this.isWhitelisted(n))return await s()||new Response("Not Found",{status:404});if(this.isBlacklisted(n))return new Response("Access Denied",{status:403});let i=this.getRateLimitInfo(n,r);if(this.shouldBlock(i,r))return this.blockIP(i,r),this.createBlockedResponse(t,i);i.count++,i.lastRequest=r;let l=await s();if(!l)return new Response("Not Found",{status:404});if(this.options.skipSuccessfulRequests&&l.status<400)i.count--;if(this.options.skipFailedRequests&&l.status>=400)i.count--;let d=new Headers(l.headers);return d.set("X-RateLimit-Limit",this.options.maxRequestsPerMinute.toString()),d.set("X-RateLimit-Remaining",Math.max(0,this.options.maxRequestsPerMinute-i.count).toString()),d.set("X-RateLimit-Reset",Math.ceil((i.firstRequest+this.options.windowSize)/1000).toString()),new Response(l.body,{status:l.status,statusText:l.statusText,headers:d})}destroy(){if(this.cleanupInterval)clearInterval(this.cleanupInterval),this.cleanupInterval=null;this.requestStore.clear()}}function Ut(t={}){let s=new I(t);return async(r,n)=>s.handle(r,n)}class V{config;FILE_SIGNATURES={"image/jpeg":[new Uint8Array([255,216,255])],"image/png":[new Uint8Array([137,80,78,71,13,10,26,10])],"image/gif":[new Uint8Array([71,73,70,56,55,97]),new Uint8Array([71,73,70,56,57,97])],"application/pdf":[new Uint8Array([37,80,68,70])],"application/zip":[new Uint8Array([80,75,3,4]),new Uint8Array([80,75,5,6]),new Uint8Array([80,75,7,8])]};EXECUTABLE_EXTENSIONS=[".exe",".bat",".cmd",".com",".pif",".scr",".vbs",".js",".jar",".app",".deb",".pkg",".dmg",".sh",".ps1",".msi",".dll"];constructor(t={}){this.config={scanForMalware:t.scanForMalware??!1,checkMagicNumbers:t.checkMagicNumbers??!0,sanitizeFilenames:t.sanitizeFilenames??!0,preventExecutableUploads:t.preventExecutableUploads??!0,maxFilenameLength:t.maxFilenameLength??255}}validateFile(t){let s=[];if(t.originalName.length>this.config.maxFilenameLength)s.push(`Filename too long (max ${this.config.maxFilenameLength} characters)`);if(this.config.sanitizeFilenames){let r=this.sanitizeFilename(t.originalName);if(!r||r.length===0)s.push("Filename is invalid or empty after sanitization")}if(this.config.preventExecutableUploads){let r=this.getFileExtension(t.originalName).toLowerCase();if(this.EXECUTABLE_EXTENSIONS.includes(r))s.push("Executable files are not allowed")}if(this.config.checkMagicNumbers){if(!this.validateFileSignature(t))s.push("File signature does not match declared MIME type")}if(this.config.scanForMalware){if(this.basicMalwareScan(t))s.push("Potential malware detected")}return{isValid:s.length===0,errors:s}}validateFileSignature(t){let s=this.FILE_SIGNATURES[t.mimetype];if(!s)return!0;let r=new Uint8Array(t.buffer.slice(0,16));return s.some((n)=>{if(r.length<n.length)return!1;for(let i=0;i<n.length;i++)if(r[i]!==n[i])return!1;return!0})}sanitizeFilename(t){return t.replace(/[<>:"/\\|?*\u0000-\u001F]/u,"_").replace(/^\.+/,"").replace(/\.+$/,"").replace(/\s+/g,"_").substring(0,this.config.maxFilenameLength)}getFileExtension(t){let s=t.lastIndexOf(".");return s===-1?"":t.substring(s)}basicMalwareScan(t){let s=new Uint8Array(t.buffer),r=new TextDecoder("utf-8",{fatal:!1}).decode(s);return[/eval\s*\(/gi,/document\.write/gi,/window\.location/gi,/<script[^>]*>/gi,/javascript:/gi,/vbscript:/gi,/onload\s*=/gi,/onerror\s*=/gi].some((i)=>i.test(r))}getSafeFilename(t){return this.sanitizeFilename(t)}isAllowedFileType(t,s){if(s.length===0)return!0;return s.includes(t)}isWithinSizeLimit(t,s){return t<=s}}import{existsSync as Ce,mkdirSync as Ne,writeFileSync as qe}from"fs";import{basename as Ue,extname as ee,join as Fe}from"path";class f{config;fileSecurity;constructor(t={}){if(this.config={destination:t.destination||"./uploads",maxFileSize:t.maxFileSize||10485760,maxFiles:t.maxFiles||10,allowedMimeTypes:t.allowedMimeTypes||[],allowedExtensions:t.allowedExtensions||[],preserveOriginalName:t.preserveOriginalName??!1,generateUniqueFilename:t.generateUniqueFilename??!0,createDestination:t.createDestination??!0,scanForMalware:t.scanForMalware??!1,checkMagicNumbers:t.checkMagicNumbers??!0,sanitizeFilenames:t.sanitizeFilenames??!0,preventExecutableUploads:t.preventExecutableUploads??!0,maxFilenameLength:t.maxFilenameLength??255},this.fileSecurity=new V(t),this.config.createDestination&&!Ce(this.config.destination))Ne(this.config.destination,{recursive:!0})}async handle(t,s){let r=t.headers.get("content-type");if(!r||!r.includes("multipart/form-data"))return await s()||new Response("Not Found",{status:404});try{let n=await t.formData(),i=[],l={};for(let[u,p]of n.entries())if(p instanceof File){if(i.length>=this.config.maxFiles)return this.createErrorResponse(`Maximum ${this.config.maxFiles} files allowed`,400);if(p.size>this.config.maxFileSize)return this.createErrorResponse(`File ${p.name} exceeds maximum size of ${this.formatBytes(this.config.maxFileSize)}`,413);if(this.config.allowedMimeTypes.length>0){let S=p.type.split(";")[0];if(!this.config.allowedMimeTypes.includes(S))return this.createErrorResponse(`File type ${S} not allowed. Allowed types: ${this.config.allowedMimeTypes.join(", ")}`,415)}let m=ee(p.name).toLowerCase();if(this.config.allowedExtensions.length>0&&!this.config.allowedExtensions.includes(m))return this.createErrorResponse(`File extension ${m} not allowed. Allowed extensions: ${this.config.allowedExtensions.join(", ")}`,415);let h=this.generateFilename(p.name),g=Fe(this.config.destination,h),y=await p.arrayBuffer(),b={fieldName:u,originalName:p.name,filename:h,path:g,size:p.size,mimetype:p.type,buffer:y},v=this.fileSecurity.validateFile(b);if(!v.isValid)return this.createErrorResponse(`Security validation failed: ${v.errors.join(", ")}`,400);qe(g,new Uint8Array(y)),i.push(b)}else if(l[u])if(Array.isArray(l[u]))l[u].push(p);else l[u]=[l[u],p];else l[u]=p;return Object.defineProperty(t,"files",{value:i,writable:!0,enumerable:!0,configurable:!0}),Object.defineProperty(t,"file",{value:(u)=>i.find((p)=>p.fieldName===u)??null,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(t,"formBody",{value:l,writable:!0,enumerable:!0,configurable:!0}),await s()||new Response("Not Found",{status:404})}catch(n){return this.createErrorResponse(`File upload failed: ${n instanceof Error?n.message:"Unknown error"}`,500)}}generateFilename(t){let s=this.fileSecurity.getSafeFilename(t);if(this.config.preserveOriginalName&&!this.config.generateUniqueFilename)return s;let r=ee(s),n=Ue(s,r);if(this.config.generateUniqueFilename){let i=c().randomUUID();return this.config.preserveOriginalName?`${n}_${i}${r}`:`${i}${r}`}return s}formatBytes(t){if(t===0)return"0 Bytes";let s=1024,r=["Bytes","KB","MB","GB"],n=Math.floor(Math.log(t)/Math.log(s));return`${Number.parseFloat((t/s**n).toFixed(2))} ${r[n]}`}createErrorResponse(t,s){return new Response(JSON.stringify({error:t}),{status:s,headers:{"Content-Type":"application/json"}})}}function Lt(t={}){return new f(t)}function _t(t,s={}){return new f({...s,maxFiles:1})}function zt(t=10,s={}){return new f({...s,maxFiles:t})}function Vt(t={}){return new f({...t,allowedMimeTypes:["image/jpeg","image/jpg","image/png","image/gif","image/webp","image/svg+xml"],allowedExtensions:[".jpg",".jpeg",".png",".gif",".webp",".svg"]})}function Wt(t={}){return new f({...t,allowedMimeTypes:["application/pdf","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/plain"],allowedExtensions:[".pdf",".doc",".docx",".txt"]})}class W{options;constructor(t={}){let s=e.server?.security?.helmet||{};this.options={contentSecurityPolicy:t.contentSecurityPolicy??s.contentSecurityPolicy??{directives:{"default-src":["'self'"],"script-src":["'self'","'unsafe-inline'"],"style-src":["'self'","'unsafe-inline'"],"img-src":["'self'","data:","https:"],"font-src":["'self'"],"connect-src":["'self'"],"media-src":["'self'"],"object-src":["'none'"],"child-src":["'self'"],"worker-src":["'self'"],"frame-ancestors":["'none'"],"form-action":["'self'"],"base-uri":["'self'"],"manifest-src":["'self'"]}},crossOriginEmbedderPolicy:t.crossOriginEmbedderPolicy??!0,crossOriginOpenerPolicy:t.crossOriginOpenerPolicy??!0,crossOriginResourcePolicy:t.crossOriginResourcePolicy??!0,dnsPrefetchControl:t.dnsPrefetchControl??!0,expectCt:t.expectCt??s.expectCt??!1,frameguard:t.frameguard??{action:s.frameOptions?.toLowerCase()||"deny"},hidePoweredBy:t.hidePoweredBy??s.hidePoweredBy??!0,hsts:t.hsts??s.hsts??{maxAge:31536000,includeSubDomains:!0,preload:!0},ieNoOpen:t.ieNoOpen??!0,noSniff:t.noSniff??s.noSniff??!0,originAgentCluster:t.originAgentCluster??!0,permittedCrossDomainPolicies:t.permittedCrossDomainPolicies??{permittedPolicies:"none"},referrerPolicy:t.referrerPolicy??s.referrerPolicy??{policy:"strict-origin-when-cross-origin"},xssFilter:t.xssFilter??s.xssFilter??!0}}async handle(t,s){if((e.server?.security?.helmet||{}).enabled===!1)return await s()||new Response("Not Found",{status:404});let n=await s();if(!n)return new Response("Not Found",{status:404});let i=new Headers(n.headers);if(this.options.contentSecurityPolicy){let l=this.options.contentSecurityPolicy;if(typeof l==="object"&&l.directives){let d=Object.entries(l.directives).map(([p,m])=>`${p} ${m.join(" ")}`).join("; "),u=l.reportOnly?"Content-Security-Policy-Report-Only":"Content-Security-Policy";if(i.set(u,d),l.reportUri)i.set("Report-To",JSON.stringify({group:"csp-endpoint",max_age:10886400,endpoints:[{url:l.reportUri}]}))}}if(this.options.crossOriginEmbedderPolicy){let l=this.options.crossOriginEmbedderPolicy,d=typeof l==="object"?l.policy||"require-corp":"require-corp";i.set("Cross-Origin-Embedder-Policy",d)}if(this.options.crossOriginOpenerPolicy){let l=this.options.crossOriginOpenerPolicy,d=typeof l==="object"?l.policy||"same-origin":"same-origin";i.set("Cross-Origin-Opener-Policy",d)}if(this.options.crossOriginResourcePolicy){let l=this.options.crossOriginResourcePolicy,d=typeof l==="object"?l.policy||"same-origin":"same-origin";i.set("Cross-Origin-Resource-Policy",d)}if(this.options.dnsPrefetchControl){let l=this.options.dnsPrefetchControl,d=typeof l==="object"?l.allow:!1;i.set("X-DNS-Prefetch-Control",d?"on":"off")}if(this.options.expectCt){let l=this.options.expectCt;if(typeof l==="object"){let d=[];if(l.enforce)d.push("enforce");if(l.maxAge)d.push(`max-age=${l.maxAge}`);if(l.reportUri)d.push(`report-uri="${l.reportUri}"`);i.set("Expect-CT",d.join(", "))}}if(this.options.frameguard){let l=this.options.frameguard;if(typeof l==="object"){let d=l.action||"deny",u=d==="sameorigin"&&l.domain?`ALLOW-FROM ${l.domain}`:d.toUpperCase();i.set("X-Frame-Options",u)}}if(this.options.hidePoweredBy)i.delete("X-Powered-By");if(this.options.hsts){let l=this.options.hsts;if(typeof l==="object"){let d=[`max-age=${l.maxAge||31536000}`];if(l.includeSubDomains)d.push("includeSubDomains");if(l.preload)d.push("preload");i.set("Strict-Transport-Security",d.join("; "))}}if(this.options.ieNoOpen)i.set("X-Download-Options","noopen");if(this.options.noSniff)i.set("X-Content-Type-Options","nosniff");if(this.options.originAgentCluster)i.set("Origin-Agent-Cluster","?1");if(this.options.permittedCrossDomainPolicies){let l=this.options.permittedCrossDomainPolicies,d=typeof l==="object"?l.permittedPolicies||"none":"none";i.set("X-Permitted-Cross-Domain-Policies",d)}if(this.options.referrerPolicy){let l=this.options.referrerPolicy;if(typeof l==="object"){let d=Array.isArray(l.policy)?l.policy.join(", "):l.policy||"strict-origin-when-cross-origin";i.set("Referrer-Policy",d)}else i.set("Referrer-Policy","strict-origin-when-cross-origin")}if(this.options.xssFilter){let l=this.options.xssFilter,d=typeof l==="object"&&l.setOnOldIE?"1; mode=block":"0";i.set("X-XSS-Protection",d)}return new Response(n.body,{status:n.status,statusText:n.statusText,headers:i})}}var De=/^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/,Oe=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;class F{options;constructor(t={}){let s=e.server?.security?.inputValidation||{};this.options={enabled:t.enabled??s.enabled??!0,schemas:t.schemas??s.schemas??{},sanitizeByDefault:t.sanitizeByDefault??s.sanitizeByDefault??!0,strictMode:t.strictMode??s.strictMode??!1,allowUnknownFields:t.allowUnknownFields??s.allowUnknownFields??!0,maxDepth:t.maxDepth??s.maxDepth??10,onValidationError:t.onValidationError}}validateValue(t,s,r){let n=[];if(s.required&&(t===void 0||t===null||t===""))return n.push({field:r,message:"Field is required",value:t,rule:"required"}),n;if(t===void 0||t===null)return n;switch(s.type){case"string":if(typeof t!=="string")n.push({field:r,message:"Must be a string",value:t,rule:"type"});else{if(s.min!==void 0&&t.length<s.min)n.push({field:r,message:`Must be at least ${s.min} characters`,value:t,rule:"min"});if(s.max!==void 0&&t.length>s.max)n.push({field:r,message:`Must be at most ${s.max} characters`,value:t,rule:"max"})}break;case"number":{let i=Number(t);if(Number.isNaN(i))n.push({field:r,message:"Must be a number",value:t,rule:"type"});else{if(s.min!==void 0&&i<s.min)n.push({field:r,message:`Must be at least ${s.min}`,value:t,rule:"min"});if(s.max!==void 0&&i>s.max)n.push({field:r,message:`Must be at most ${s.max}`,value:t,rule:"max"})}break}case"boolean":if(typeof t!=="boolean"&&t!=="true"&&t!=="false")n.push({field:r,message:"Must be a boolean",value:t,rule:"type"});break;case"email":{if(typeof t==="string"&&!De.test(t))n.push({field:r,message:"Must be a valid email address",value:t,rule:"format"});break}case"url":try{new URL(t)}catch{n.push({field:r,message:"Must be a valid URL",value:t,rule:"format"})}break;case"uuid":{if(typeof t==="string"&&!Oe.test(t))n.push({field:r,message:"Must be a valid UUID",value:t,rule:"format"});break}case"date":{let i=new Date(t);if(Number.isNaN(i.getTime()))n.push({field:r,message:"Must be a valid date",value:t,rule:"format"});break}case"regex":if(s.pattern&&typeof t==="string"&&!s.pattern.test(t))n.push({field:r,message:"Does not match required pattern",value:t,rule:"pattern"});break;case"custom":if(s.custom){let i=s.custom(t);if(i!==!0)n.push({field:r,message:typeof i==="string"?i:"Custom validation failed",value:t,rule:"custom"})}break}if(s.enum&&!s.enum.includes(t))n.push({field:r,message:`Must be one of: ${s.enum.join(", ")}`,value:t,rule:"enum"});if(s.type!=="regex"&&s.pattern&&typeof t==="string"&&!s.pattern.test(t))n.push({field:r,message:"Does not match required pattern",value:t,rule:"pattern"});return n}sanitizeValue(t,s){if(!s.sanitize&&!this.options.sanitizeByDefault)return t;if(typeof t==="string")t=t.replace(/[<>'"&]/g,(r)=>({"<":"<",">":">",'"':""","'":"'","&":"&"})[r]||r).trim();if(s.transform)t=s.transform(t);return t}validateObject(t,s,r="",n=0){let i=[];if(n>this.options.maxDepth)return i.push({field:r,message:"Maximum nesting depth exceeded",value:t,rule:"depth"}),i;if(this.options.strictMode&&!this.options.allowUnknownFields){for(let l in t)if(!(l in s))i.push({field:r?`${r}.${l}`:l,message:"Unknown field",value:t[l],rule:"unknown"})}for(let[l,d]of Object.entries(s)){let u=r?`${r}.${l}`:l,p=t?.[l];if(typeof d==="object"&&!("type"in d)){if(p&&typeof p==="object")i.push(...this.validateObject(p,d,u,n+1))}else{let m=d;if(i.push(...this.validateValue(p,m,u)),t&&(m.sanitize||this.options.sanitizeByDefault))t[l]=this.sanitizeValue(p,m)}}return i}async parseRequestBody(t){let s=t.headers.get("content-type")||"";try{if(s.includes("application/json"))return await t.json();else if(s.includes("application/x-www-form-urlencoded")){let r=await t.formData(),n={};for(let[i,l]of r.entries())n[i]=l;return n}else if(s.includes("multipart/form-data")){let r=await t.formData(),n={};for(let[i,l]of r.entries())n[i]=l;return n}}catch(r){throw console.error(r),Error("Invalid request body format")}return{}}async handle(t,s){if(!this.options.enabled)return await s()||new Response("Not Found",{status:404});let r=[],n=new URL(t.url);try{if(this.options.schemas?.query){let l={};for(let[u,p]of n.searchParams.entries())l[u]=p;let d=this.validateObject(l,this.options.schemas.query);r.push(...d)}if(this.options.schemas?.body&&t.method!=="GET"&&t.method!=="HEAD")try{let l=await this.parseRequestBody(t),d=this.validateObject(l,this.options.schemas.body);r.push(...d),t.validatedBody=l}catch(l){r.push({field:"body",message:l instanceof Error?l.message:"Invalid request body",value:null,rule:"parse"})}if(this.options.schemas?.headers){let l={};for(let[u,p]of t.headers.entries())l[u]=p;let d=this.validateObject(l,this.options.schemas.headers);r.push(...d)}if(this.options.schemas?.params&&t.params){let l=this.validateObject(t.params,this.options.schemas.params);r.push(...l)}if(r.length>0){if(this.options.onValidationError)return this.options.onValidationError(r);return new Response(JSON.stringify({error:"Validation Error",message:"Request validation failed",errors:r}),{status:400,headers:{"Content-Type":"application/json"}})}return await s()||new Response("Not Found",{status:404})}catch(i){return console.error("Input validation error:",i),new Response("Internal Server Error",{status:500})}}}function Gt(t={}){let s=new F(t);return async(r,n)=>s.handle(r,n)}class ue{options;rules=new Map;channels=[];notifications=[];lastAlertTimes=new Map;metricsBuffer=[];checkInterval;constructor(t={}){if(this.options={enabled:t.enabled??!0,defaultCooldown:t.defaultCooldown??300000,maxAlerts:t.maxAlerts??1000,autoResolve:t.autoResolve??!0,autoResolveTimeout:t.autoResolveTimeout??600000,...t},t.rules)for(let s of t.rules)this.rules.set(s.id,s);if(this.channels=t.channels||[],this.rules.size===0)this.addDefaultRules();if(this.channels.length===0)this.channels.push({type:"console",enabled:!0,config:{}});if(this.options.enabled)this.startAlertingEngine()}addDefaultRules(){let t=[{id:"high-response-time",name:"High Response Time",description:"Alert when average response time exceeds threshold",enabled:!0,metric:"responseTime",condition:"gt",threshold:1000,duration:60000,severity:"warning"},{id:"critical-response-time",name:"Critical Response Time",description:"Alert when response time is critically high",enabled:!0,metric:"responseTime",condition:"gt",threshold:5000,duration:30000,severity:"critical"},{id:"high-error-rate",name:"High Error Rate",description:"Alert when error rate exceeds threshold",enabled:!0,metric:"errorRate",condition:"gt",threshold:0.05,duration:120000,severity:"warning"},{id:"critical-error-rate",name:"Critical Error Rate",description:"Alert when error rate is critically high",enabled:!0,metric:"errorRate",condition:"gt",threshold:0.1,duration:60000,severity:"critical"},{id:"high-memory-usage",name:"High Memory Usage",description:"Alert when memory usage exceeds threshold",enabled:!0,metric:"memoryUsage",condition:"gt",threshold:536870912,duration:300000,severity:"warning"},{id:"low-request-rate",name:"Low Request Rate",description:"Alert when request rate drops significantly",enabled:!1,metric:"requestRate",condition:"lt",threshold:1,duration:300000,severity:"info"}];for(let s of t)this.rules.set(s.id,s)}startAlertingEngine(){this.checkInterval=setInterval(()=>{this.evaluateRules(),this.cleanupOldNotifications(),this.autoResolveAlerts()},1e4),this.checkInterval.unref?.()}evaluateRules(){let t=Date.now();for(let s of this.rules.values()){if(!s.enabled)continue;let r=this.lastAlertTimes.get(s.id),n=s.cooldown||this.options.defaultCooldown||300000;if(r&&t-r<n)continue;let i=s.duration||60000,l=this.metricsBuffer.filter((p)=>t-p.timestamp<=i);if(l.length===0)continue;let d=!1,u;if(s.metric==="custom"&&s.customEvaluator)d=s.customEvaluator(l),u="custom condition";else{let p=this.extractMetricValues(l,s.metric);if(p.length===0)continue;let m=p.reduce((h,g)=>h+g,0)/p.length;u=m,d=this.evaluateCondition(m,s.condition,s.threshold)}if(d)this.triggerAlert(s,u,l),this.lastAlertTimes.set(s.id,t)}}extractMetricValues(t,s){switch(s){case"responseTime":return t.map((r)=>r.responseTime);case"errorRate":return t.map((r)=>r.statusCode>=400?1:0);case"memoryUsage":return t.map((r)=>r.memoryUsage.heapUsed);case"cpuUsage":return t.map((r)=>r.cpuUsage.user+r.cpuUsage.system);case"requestRate":{if(t.length<2)return[];let r=(t[t.length-1].timestamp-t[0].timestamp)/1000;return[t.length/Math.max(r,1)]}default:return[]}}evaluateCondition(t,s,r){switch(s){case"gt":return t>r;case"gte":return t>=r;case"lt":return t<r;case"lte":return t<=r;case"eq":return Math.abs(t-r)<0.001;default:return!1}}async triggerAlert(t,s,r){let n={id:this.generateId(),ruleId:t.id,ruleName:t.name,severity:t.severity,message:this.formatAlertMessage(t,s,r),timestamp:Date.now(),resolved:!1,metadata:{rule:t,value:s,threshold:t.threshold,condition:t.condition,metricsCount:r.length}};this.notifications.push(n);for(let i of this.channels){if(!i.enabled)continue;if(i.filters?.severities&&!i.filters.severities.includes(t.severity))continue;if(i.filters?.rules&&!i.filters.rules.includes(t.id))continue;try{await this.sendNotification(i,n)}catch(l){console.error(`Failed to send alert to ${i.type}:`,l)}}if(this.notifications.length>(this.options.maxAlerts||1000))this.notifications=this.notifications.slice(-(this.options.maxAlerts||1000))}formatAlertMessage(t,s,r){let n=(d,u)=>{switch(u){case"responseTime":return`${Math.round(d)}ms`;case"errorRate":return`${Math.round(d*100)}%`;case"memoryUsage":return`${Math.round(d/1024/1024)}MB`;case"cpuUsage":return`${Math.round(d)}%`;case"requestRate":return`${Math.round(d)}/s`;default:return String(d)}},i=typeof s==="number"?n(s,t.metric):String(s),l=n(t.threshold,t.metric);return`${t.name}: ${i} ${t.condition} ${l} (${r.length} samples)`}async sendNotification(t,s){switch(t.type){case"console":this.sendConsoleNotification(s);break;case"webhook":await this.sendWebhookNotification(t,s);break;case"slack":await this.sendSlackNotification(t,s);break;case"email":await this.sendEmailNotification(t,s);break;case"custom":if(t.config.customHandler)await t.config.customHandler(s);break}}sendConsoleNotification(t){let s=t.severity==="critical"?"\uD83D\uDEA8":t.severity==="warning"?"\u26A0\uFE0F":"\u2139\uFE0F";console.log(`${s} ALERT [${t.severity.toUpperCase()}]: ${t.message}`),console.log(` Rule: ${t.ruleName} (${t.ruleId})`),console.log(` Time: ${new Date(t.timestamp).toISOString()}`)}async sendWebhookNotification(t,s){if(!t.config.url)return;let r={alert:s,timestamp:new Date(s.timestamp).toISOString(),service:"bun-router"};await fetch(t.config.url,{method:"POST",headers:{"Content-Type":"application/json",...t.config.token&&{Authorization:`Bearer ${t.config.token}`}},body:JSON.stringify(r)})}async sendSlackNotification(t,s){if(!t.config.url)return;let r=s.severity==="critical"?"danger":s.severity==="warning"?"warning":"good",n=s.severity==="critical"?":rotating_light:":s.severity==="warning"?":warning:":":information_source:",i=(()=>({channel:t.config.channel,username:"Performance Monitor",icon_emoji:":chart_with_upwards_trend:",attachments:[{color:r,title:`${n} ${s.ruleName}`,text:s.message,fields:[{title:"Severity",value:s.severity.toUpperCase(),short:!0},{title:"Time",value:new Date(s.timestamp).toISOString(),short:!0}],footer:"bun-router Performance Monitor",ts:Math.floor(s.timestamp/1000)}]}))();await fetch(t.config.url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})}async sendEmailNotification(t,s){console.log(`Email notification would be sent to ${t.config.email}:`,s.message)}cleanupOldNotifications(){let s=Date.now()-86400000;this.notifications=this.notifications.filter((r)=>r.timestamp>s)}autoResolveAlerts(){if(!this.options.autoResolve)return;let t=this.options.autoResolveTimeout||600000,s=Date.now()-t;for(let r of this.notifications)if(!r.resolved&&r.timestamp<s)r.resolved=!0,r.resolvedAt=Date.now()}generateId(){return Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15)}addMetrics(t){this.metricsBuffer.push(t);let s=3600000,r=Date.now()-s;this.metricsBuffer=this.metricsBuffer.filter((n)=>n.timestamp>r)}addRule(t){this.rules.set(t.id,t)}removeRule(t){this.rules.delete(t)}updateRule(t,s){let r=this.rules.get(t);if(r)this.rules.set(t,{...r,...s})}addChannel(t){this.channels.push(t)}removeChannel(t){this.channels.splice(t,1)}getActiveAlerts(){return this.notifications.filter((t)=>!t.resolved)}getAllNotifications(){return[...this.notifications]}resolveAlert(t){let s=this.notifications.find((r)=>r.id===t);if(s&&!s.resolved)s.resolved=!0,s.resolvedAt=Date.now()}async handle(t,s){let r=await s();if(r)return r;return new Response("No response from next middleware",{status:500})}destroy(){if(this.checkInterval)clearInterval(this.checkInterval);this.rules.clear(),this.channels=[],this.notifications=[],this.lastAlertTimes.clear(),this.metricsBuffer=[]}}function Kt(t={}){return new ue(t)}import T from"process";class de{options;metricsHistory=[];alerts=[];startTime=Date.now();constructor(t={}){this.options={enabled:t.enabled??!0,path:t.path??"/performance",title:t.title??"Performance Dashboard",refreshInterval:t.refreshInterval??5000,maxMetrics:t.maxMetrics??1000,authentication:{enabled:!1,...t.authentication},features:{realTimeMetrics:!0,historicalCharts:!0,alertsPanel:!0,tracingView:!0,systemMetrics:!0,...t.features}}}isAuthenticated(t){if(!this.options.authentication?.enabled)return!0;let s=t.headers.get("authorization"),r=t.headers.get("x-api-key");if(this.options.authentication.apiKey&&r===this.options.authentication.apiKey)return!0;if(s&&this.options.authentication.username&&this.options.authentication.password){let[n,i]=s.split(" ");if(n==="Basic"){let l=atob(i),[d,u]=l.split(":");return d===this.options.authentication.username&&u===this.options.authentication.password}}return!1}generateDashboardHTML(t){return`
|
|
5
|
+
<!DOCTYPE html>
|
|
6
|
+
<html lang="en">
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8">
|
|
9
|
+
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
|
10
|
+
<title>${this.options.title}</title>
|
|
11
|
+
<style>
|
|
12
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
13
|
+
body {
|
|
14
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
15
|
+
background: #f5f5f5;
|
|
16
|
+
color: #333;
|
|
17
|
+
line-height: 1.6;
|
|
18
|
+
}
|
|
19
|
+
.header {
|
|
20
|
+
background: #2c3e50;
|
|
21
|
+
color: white;
|
|
22
|
+
padding: 1rem 2rem;
|
|
23
|
+
display: flex;
|
|
24
|
+
justify-content: space-between;
|
|
25
|
+
align-items: center;
|
|
26
|
+
}
|
|
27
|
+
.header h1 { font-size: 1.5rem; }
|
|
28
|
+
.status {
|
|
29
|
+
display: flex;
|
|
30
|
+
gap: 1rem;
|
|
31
|
+
align-items: center;
|
|
32
|
+
}
|
|
33
|
+
.status-item {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
align-items: center;
|
|
37
|
+
font-size: 0.8rem;
|
|
38
|
+
}
|
|
39
|
+
.status-value {
|
|
40
|
+
font-size: 1.2rem;
|
|
41
|
+
font-weight: bold;
|
|
42
|
+
}
|
|
43
|
+
.container {
|
|
44
|
+
max-width: 1400px;
|
|
45
|
+
margin: 0 auto;
|
|
46
|
+
padding: 2rem;
|
|
47
|
+
display: grid;
|
|
48
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
49
|
+
gap: 2rem;
|
|
50
|
+
}
|
|
51
|
+
.card {
|
|
52
|
+
background: white;
|
|
53
|
+
border-radius: 8px;
|
|
54
|
+
padding: 1.5rem;
|
|
55
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
56
|
+
}
|
|
57
|
+
.card h2 {
|
|
58
|
+
margin-bottom: 1rem;
|
|
59
|
+
color: #2c3e50;
|
|
60
|
+
font-size: 1.2rem;
|
|
61
|
+
}
|
|
62
|
+
.metric {
|
|
63
|
+
display: flex;
|
|
64
|
+
justify-content: space-between;
|
|
65
|
+
align-items: center;
|
|
66
|
+
padding: 0.5rem 0;
|
|
67
|
+
border-bottom: 1px solid #eee;
|
|
68
|
+
}
|
|
69
|
+
.metric:last-child { border-bottom: none; }
|
|
70
|
+
.metric-label { font-weight: 500; }
|
|
71
|
+
.metric-value {
|
|
72
|
+
font-weight: bold;
|
|
73
|
+
color: #27ae60;
|
|
74
|
+
}
|
|
75
|
+
.metric-value.warning { color: #f39c12; }
|
|
76
|
+
.metric-value.critical { color: #e74c3c; }
|
|
77
|
+
.alert {
|
|
78
|
+
padding: 0.75rem;
|
|
79
|
+
margin: 0.5rem 0;
|
|
80
|
+
border-radius: 4px;
|
|
81
|
+
border-left: 4px solid;
|
|
82
|
+
}
|
|
83
|
+
.alert.warning {
|
|
84
|
+
background: #fff3cd;
|
|
85
|
+
border-color: #f39c12;
|
|
86
|
+
color: #856404;
|
|
87
|
+
}
|
|
88
|
+
.alert.critical {
|
|
89
|
+
background: #f8d7da;
|
|
90
|
+
border-color: #e74c3c;
|
|
91
|
+
color: #721c24;
|
|
92
|
+
}
|
|
93
|
+
.chart-container {
|
|
94
|
+
height: 200px;
|
|
95
|
+
background: #f8f9fa;
|
|
96
|
+
border-radius: 4px;
|
|
97
|
+
display: flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
color: #666;
|
|
101
|
+
}
|
|
102
|
+
.distribution {
|
|
103
|
+
display: grid;
|
|
104
|
+
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
105
|
+
gap: 1rem;
|
|
106
|
+
margin-top: 1rem;
|
|
107
|
+
}
|
|
108
|
+
.distribution-item {
|
|
109
|
+
text-align: center;
|
|
110
|
+
padding: 1rem;
|
|
111
|
+
background: #f8f9fa;
|
|
112
|
+
border-radius: 4px;
|
|
113
|
+
}
|
|
114
|
+
.distribution-value {
|
|
115
|
+
font-size: 1.5rem;
|
|
116
|
+
font-weight: bold;
|
|
117
|
+
color: #2c3e50;
|
|
118
|
+
}
|
|
119
|
+
.distribution-label {
|
|
120
|
+
font-size: 0.8rem;
|
|
121
|
+
color: #666;
|
|
122
|
+
margin-top: 0.5rem;
|
|
123
|
+
}
|
|
124
|
+
.trace {
|
|
125
|
+
padding: 0.75rem;
|
|
126
|
+
margin: 0.5rem 0;
|
|
127
|
+
background: #f8f9fa;
|
|
128
|
+
border-radius: 4px;
|
|
129
|
+
border-left: 4px solid #3498db;
|
|
130
|
+
}
|
|
131
|
+
.trace-header {
|
|
132
|
+
display: flex;
|
|
133
|
+
justify-content: space-between;
|
|
134
|
+
align-items: center;
|
|
135
|
+
margin-bottom: 0.5rem;
|
|
136
|
+
}
|
|
137
|
+
.trace-operation {
|
|
138
|
+
font-weight: bold;
|
|
139
|
+
color: #2c3e50;
|
|
140
|
+
}
|
|
141
|
+
.trace-duration {
|
|
142
|
+
color: #666;
|
|
143
|
+
font-size: 0.9rem;
|
|
144
|
+
}
|
|
145
|
+
.trace-details {
|
|
146
|
+
font-size: 0.8rem;
|
|
147
|
+
color: #666;
|
|
148
|
+
}
|
|
149
|
+
.refresh-indicator {
|
|
150
|
+
position: fixed;
|
|
151
|
+
top: 1rem;
|
|
152
|
+
right: 1rem;
|
|
153
|
+
background: #27ae60;
|
|
154
|
+
color: white;
|
|
155
|
+
padding: 0.5rem 1rem;
|
|
156
|
+
border-radius: 4px;
|
|
157
|
+
font-size: 0.8rem;
|
|
158
|
+
opacity: 0;
|
|
159
|
+
transition: opacity 0.3s;
|
|
160
|
+
}
|
|
161
|
+
.refresh-indicator.active { opacity: 1; }
|
|
162
|
+
@media (max-width: 768px) {
|
|
163
|
+
.container {
|
|
164
|
+
grid-template-columns: 1fr;
|
|
165
|
+
padding: 1rem;
|
|
166
|
+
}
|
|
167
|
+
.header {
|
|
168
|
+
padding: 1rem;
|
|
169
|
+
flex-direction: column;
|
|
170
|
+
gap: 1rem;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
</style>
|
|
174
|
+
</head>
|
|
175
|
+
<body>
|
|
176
|
+
<div class='header'>
|
|
177
|
+
<h1>${this.options.title}</h1>
|
|
178
|
+
<div class='status'>
|
|
179
|
+
<div class='status-item'>
|
|
180
|
+
<div class='status-value'>${t.metrics.current.totalRequests}</div>
|
|
181
|
+
<div>Total Requests</div>
|
|
182
|
+
</div>
|
|
183
|
+
<div class='status-item'>
|
|
184
|
+
<div class='status-value'>${Math.round(t.metrics.current.averageResponseTime)}ms</div>
|
|
185
|
+
<div>Avg Response</div>
|
|
186
|
+
</div>
|
|
187
|
+
<div class='status-item'>
|
|
188
|
+
<div class='status-value'>${Math.round(t.metrics.current.errorRate*100)}%</div>
|
|
189
|
+
<div>Error Rate</div>
|
|
190
|
+
</div>
|
|
191
|
+
<div class='status-item'>
|
|
192
|
+
<div class='status-value'>${Math.round(t.metrics.current.requestsPerSecond)}/s</div>
|
|
193
|
+
<div>Requests/sec</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<div class='container'>
|
|
199
|
+
${this.options.features?.realTimeMetrics?`
|
|
200
|
+
<div class='card'>
|
|
201
|
+
<h2>Real-time Metrics</h2>
|
|
202
|
+
<div class='metric'>
|
|
203
|
+
<span class='metric-label'>Response Time</span>
|
|
204
|
+
<span class='metric-value'>${Math.round(t.metrics.current.averageResponseTime)}ms</span>
|
|
205
|
+
</div>
|
|
206
|
+
<div class='metric'>
|
|
207
|
+
<span class='metric-label'>Memory Usage</span>
|
|
208
|
+
<span class='metric-value'>${Math.round(t.metrics.current.memoryUsage/1024/1024)}MB</span>
|
|
209
|
+
</div>
|
|
210
|
+
<div class='metric'>
|
|
211
|
+
<span class='metric-label'>CPU Usage</span>
|
|
212
|
+
<span class='metric-value'>${Math.round(t.metrics.current.cpuUsage)}%</span>
|
|
213
|
+
</div>
|
|
214
|
+
<div class='metric'>
|
|
215
|
+
<span class='metric-label'>Requests/sec</span>
|
|
216
|
+
<span class='metric-value'>${Math.round(t.metrics.current.requestsPerSecond)}</span>
|
|
217
|
+
</div>
|
|
218
|
+
<div class='metric'>
|
|
219
|
+
<span class='metric-label'>Error Rate</span>
|
|
220
|
+
<span class='metric-value ${t.metrics.current.errorRate>0.1?"critical":t.metrics.current.errorRate>0.05?"warning":""}'>${Math.round(t.metrics.current.errorRate*100)}%</span>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
`:""}
|
|
224
|
+
|
|
225
|
+
${this.options.features?.historicalCharts?`
|
|
226
|
+
<div class='card'>
|
|
227
|
+
<h2>Historical Performance</h2>
|
|
228
|
+
<div class='chart-container'>
|
|
229
|
+
Response Time Chart (${t.metrics.historical.length} data points)
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
`:""}
|
|
233
|
+
|
|
234
|
+
<div class='card'>
|
|
235
|
+
<h2>Request Distribution</h2>
|
|
236
|
+
<div class='distribution'>
|
|
237
|
+
${Object.entries(t.metrics.distribution.statusCodes).map(([s,r])=>`
|
|
238
|
+
<div class='distribution-item'>
|
|
239
|
+
<div class='distribution-value'>${r}</div>
|
|
240
|
+
<div class='distribution-label'>HTTP ${s}</div>
|
|
241
|
+
</div>
|
|
242
|
+
`).join("")}
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
<div class='card'>
|
|
247
|
+
<h2>Top Endpoints</h2>
|
|
248
|
+
${Object.entries(t.metrics.distribution.paths).sort(([,s],[,r])=>r-s).slice(0,10).map(([s,r])=>`
|
|
249
|
+
<div class='metric'>
|
|
250
|
+
<span class='metric-label'>${s}</span>
|
|
251
|
+
<span class='metric-value'>${r}</span>
|
|
252
|
+
</div>
|
|
253
|
+
`).join("")}
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
${this.options.features?.alertsPanel?`
|
|
257
|
+
<div class='card'>
|
|
258
|
+
<h2>Active Alerts</h2>
|
|
259
|
+
${t.alerts.length===0?"<p>No active alerts</p>":""}
|
|
260
|
+
${t.alerts.filter((s)=>!s.resolved).map((s)=>`
|
|
261
|
+
<div class='${s.type} alert'>
|
|
262
|
+
<strong>${s.type.toUpperCase()}:</strong> ${s.message}
|
|
263
|
+
<br><small>${new Date(s.timestamp).toLocaleString()}</small>
|
|
264
|
+
</div>
|
|
265
|
+
`).join("")}
|
|
266
|
+
</div>
|
|
267
|
+
`:""}
|
|
268
|
+
|
|
269
|
+
${this.options.features?.tracingView?`
|
|
270
|
+
<div class='card'>
|
|
271
|
+
<h2>Recent Traces</h2>
|
|
272
|
+
${t.traces.slice(0,10).map((s)=>`
|
|
273
|
+
<div class='trace'>
|
|
274
|
+
<div class='trace-header'>
|
|
275
|
+
<span class='trace-operation'>${s.operationName}</span>
|
|
276
|
+
<span class='trace-duration'>${Math.round((s.duration||0)*100)/100}ms</span>
|
|
277
|
+
</div>
|
|
278
|
+
<div class='trace-details'>
|
|
279
|
+
Trace ID: ${s.traceId} | Status: ${s.status}
|
|
280
|
+
${s.error?` | Error: ${s.error}`:""}
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
`).join("")}
|
|
284
|
+
</div>
|
|
285
|
+
`:""}
|
|
286
|
+
|
|
287
|
+
${this.options.features?.systemMetrics?`
|
|
288
|
+
<div class='card'>
|
|
289
|
+
<h2>System Information</h2>
|
|
290
|
+
<div class='metric'>
|
|
291
|
+
<span class='metric-label'>Uptime</span>
|
|
292
|
+
<span class='metric-value'>${Math.round(t.system.uptime/1000/60)} minutes</span>
|
|
293
|
+
</div>
|
|
294
|
+
<div class='metric'>
|
|
295
|
+
<span class='metric-label'>Node.js</span>
|
|
296
|
+
<span class='metric-value'>${t.system.nodeVersion}</span>
|
|
297
|
+
</div>
|
|
298
|
+
<div class='metric'>
|
|
299
|
+
<span class='metric-label'>Platform</span>
|
|
300
|
+
<span class='metric-value'>${t.system.platform} ${t.system.arch}</span>
|
|
301
|
+
</div>
|
|
302
|
+
<div class='metric'>
|
|
303
|
+
<span class='metric-label'>Heap Used</span>
|
|
304
|
+
<span class='metric-value'>${Math.round(t.system.memory.heapUsed/1024/1024)}MB</span>
|
|
305
|
+
</div>
|
|
306
|
+
<div class='metric'>
|
|
307
|
+
<span class='metric-label'>RSS</span>
|
|
308
|
+
<span class='metric-value'>${Math.round(t.system.memory.rss/1024/1024)}MB</span>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
`:""}
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<div class='refresh-indicator' id='refreshIndicator'>Updated</div>
|
|
315
|
+
|
|
316
|
+
<script>
|
|
317
|
+
let refreshInterval;
|
|
318
|
+
|
|
319
|
+
function startAutoRefresh() {
|
|
320
|
+
refreshInterval = setInterval(async () => {
|
|
321
|
+
try {
|
|
322
|
+
const response = await fetch('${this.options.path}/api/data');
|
|
323
|
+
if (response.ok) {
|
|
324
|
+
const indicator = document.getElementById('refreshIndicator');
|
|
325
|
+
indicator.classList.add('active');
|
|
326
|
+
setTimeout(() => indicator.classList.remove('active'), 1000);
|
|
327
|
+
|
|
328
|
+
// In a real implementation, we would update the DOM with new data
|
|
329
|
+
// For now, we'll just refresh the page
|
|
330
|
+
setTimeout(() => window.location.reload(), ${this.options.refreshInterval});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
console.error('Failed to refresh data:', error);
|
|
335
|
+
}
|
|
336
|
+
}, ${this.options.refreshInterval});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Start auto-refresh
|
|
340
|
+
startAutoRefresh();
|
|
341
|
+
|
|
342
|
+
// Stop refresh when page is hidden
|
|
343
|
+
document.addEventListener('visibilitychange', () => {
|
|
344
|
+
if (document.hidden) {
|
|
345
|
+
clearInterval(refreshInterval);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
startAutoRefresh();
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
</script>
|
|
352
|
+
</body>
|
|
353
|
+
</html>
|
|
354
|
+
`}async getDashboardData(t,s){let r=Date.now(),n={current:{totalRequests:0,averageResponseTime:0,errorRate:0,requestsPerSecond:0,memoryUsage:0,cpuUsage:0},historical:this.metricsHistory,distribution:{statusCodes:{},paths:{},methods:{},responseTimes:[]}};if(t&&typeof t.getAggregatedMetrics==="function"){let d=t.getAggregatedMetrics(60000);n.current={totalRequests:d.totalRequests,averageResponseTime:d.averageResponseTime,errorRate:d.errorRate,requestsPerSecond:d.requestsPerSecond,memoryUsage:d.averageMemoryUsage,cpuUsage:0},n.distribution.statusCodes=d.statusCodeDistribution,n.distribution.paths=d.pathDistribution}let i=[];if(s&&typeof s.getActiveSpans==="function")i=s.getActiveSpans();let l={uptime:r-this.startTime,nodeVersion:T.version,bunVersion:T.versions.bun||"N/A",platform:T.platform,arch:T.arch,memory:T.memoryUsage(),cpu:T.cpuUsage()};return{metrics:n,alerts:this.alerts,traces:i,system:l}}async handle(t,s){if(!this.options.enabled)return await s()||new Response("Internal Server Error",{status:500});let r=new URL(t.url);if(r.pathname===this.options.path){if(!this.isAuthenticated(t))return new Response("Unauthorized",{status:401,headers:{"WWW-Authenticate":'Basic realm="Performance Dashboard"'}});let n=await this.getDashboardData(),i=this.generateDashboardHTML(n);return new Response(i,{headers:{"Content-Type":"text/html","Cache-Control":"no-cache, no-store, must-revalidate"}})}if(r.pathname===`${this.options.path}/api/data`){if(!this.isAuthenticated(t))return new Response("Unauthorized",{status:401});let n=await this.getDashboardData();return new Response(JSON.stringify(n),{headers:{"Content-Type":"application/json","Cache-Control":"no-cache, no-store, must-revalidate"}})}return await s()}addAlert(t,s){if(this.alerts.push({id:Math.random().toString(36).substring(2,15),type:t,message:s,timestamp:Date.now(),resolved:!1}),this.alerts.length>100)this.alerts=this.alerts.slice(-100)}resolveAlert(t){let s=this.alerts.find((r)=>r.id===t);if(s)s.resolved=!0}updateMetricsHistory(t){this.metricsHistory.push({timestamp:Date.now(),...t});let s=this.options.maxMetrics||1000;if(this.metricsHistory.length>s)this.metricsHistory=this.metricsHistory.slice(-s)}}function Jt(t={}){let s=new de(t);return async(r,n)=>s.handle(r,n)}import R from"process";class pe{options;metrics=[];lastAlertTime={};requestsThisSecond=0;lastSecondTimestamp=Date.now();requestContexts=new Map;samplingCounter=0;alertCooldowns=new Map;cleanupInterval;constructor(t={}){let s=e.server?.performance?.monitoring||{};if(this.options={enabled:t.enabled??s.enabled??!0,sampleRate:t.sampleRate??t.sampling?.rate??1,collectMetrics:{responseTime:!0,memoryUsage:!0,cpuUsage:!0,requestDetails:!0,headers:!1,queryParams:!0,...t.collectMetrics},sampling:{rate:t.sampling?.rate??t.sampleRate??1,maxRequestsPerSecond:t.sampling?.maxRequestsPerSecond??1000,...t.sampling},thresholds:{responseTime:{warning:1000,critical:5000},memoryUsage:{warning:536870912,critical:1073741824},errorRate:{warning:0.05,critical:0.1}},profiling:{enabled:!1,sampleInterval:100,maxSamples:10,includeStackTrace:!1,maxStackDepth:10},alerts:{enabled:!1,thresholds:{responseTime:1000,memoryUsage:104857600,errorRate:0.05},cooldown:60000},...t},this.options.storage?.type==="memory")this.startCleanupInterval()}startCleanupInterval(){this.cleanupInterval=setInterval(()=>{this.cleanupOldMetrics()},60000),this.cleanupInterval.unref?.()}cleanupOldMetrics(){let t=Date.now(),s=this.options.storage?.retentionPeriod||86400000;this.metrics=this.metrics.filter((n)=>t-n.timestamp<s);let r=this.options.storage?.maxEntries||1e4;if(this.metrics.length>r)this.metrics=this.metrics.slice(-r)}shouldSample(){let t=this.options.sampling?.rate||this.options.sampleRate||1;return Math.random()<t}generateTraceId(){return Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15)}generateSpanId(){return Math.random().toString(36).substring(2,10)}getClientIP(t){return t.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||t.headers.get("x-real-ip")||t.headers.get("cf-connecting-ip")||"unknown"}async collectSystemMetrics(){let t=R.memoryUsage(),s=R.cpuUsage();return{memory:t,cpu:s}}takeSample(t){let s=R.memoryUsage(),r=R.cpuUsage(),n=Date.now();if(!t.systemSamples)t.systemSamples=[];if(!t.samples)t.samples=[];t.systemSamples.push({timestamp:n,memory:s,cpu:r}),t.samples.push({timestamp:n,memory:s,cpu:r,stack:this.options.profiling?.includeStackTrace?Error("Profile sample").stack?.slice(0,this.options.profiling.maxStackDepth||10):void 0})}calculateCpuPercent(t,s,r){let n=s.user-t.user,i=s.system-t.system;return{user:n/r*100,system:i/r*100}}async storeMetrics(t){if(this.metrics.push(t),console.warn(`[PerformanceMonitor] Stored metric: ${t.path} ${t.method} ${t.responseTime}ms`),console.warn(`[PerformanceMonitor] Added metric to internal array: ${t.path} ${t.method} ${t.responseTime}ms`),this.options.storage?.type)switch(this.options.storage.type){case"file":if(this.options.storage.filePath){let s=`${JSON.stringify(t)}
|
|
355
|
+
`;await Bun.write(this.options.storage.filePath,s,{createPath:!0})}break;case"custom":if(this.options.storage.customHandler)await this.options.storage.customHandler(t);break;case"memory":default:break}}async checkThresholds(t){let s=typeof this.options.alerts?.customHandler==="function";if(!this.options.alerts?.enabled&&!s)return;let r=this.options.alerts?.thresholds,n=this.options.thresholds;if(console.warn(`[PerformanceMonitor] Checking thresholds for ${t.path}: responseTime=${t.responseTime}ms, threshold=${r?.responseTime||n?.responseTime?.warning||"none"}`),r?.responseTime&&t.responseTime>r.responseTime)await this.sendAlert({type:"responseTime",message:`Response time threshold exceeded: ${t.responseTime}ms > ${r.responseTime}ms`,value:t.responseTime,threshold:r.responseTime,path:t.path,method:t.method,statusCode:t.statusCode,timestamp:t.timestamp,severity:"warning"});else if(n?.responseTime?.warning&&t.responseTime>n.responseTime.warning)await this.sendAlert({type:"responseTime",message:`Response time threshold exceeded: ${t.responseTime}ms > ${n.responseTime.warning}ms`,value:t.responseTime,threshold:n.responseTime.warning,path:t.path,method:t.method,statusCode:t.statusCode,timestamp:t.timestamp,severity:"warning"});let i=t.memoryUsage.heapUsed;if(r?.memoryUsage&&i>r.memoryUsage)await this.sendAlert({type:"memoryUsage",message:`Memory usage threshold exceeded: ${i} bytes > ${r.memoryUsage} bytes`,value:i,threshold:r.memoryUsage,path:t.path,method:t.method,statusCode:t.statusCode,timestamp:t.timestamp,severity:"warning"});else if(n?.memoryUsage?.warning&&i>n.memoryUsage.warning)await this.sendAlert({type:"memoryUsage",message:`Memory usage threshold exceeded: ${i} bytes > ${n.memoryUsage.warning} bytes`,value:i,threshold:n.memoryUsage.warning,path:t.path,method:t.method,statusCode:t.statusCode,timestamp:t.timestamp,severity:"warning"});if((r?.errorRate||n?.errorRate?.warning)&&t.statusCode>=500){let l=this.metrics.filter((h)=>h.timestamp>Date.now()-60000),d=l.length,u=l.filter((h)=>h.statusCode>=500).length,p=d>0?u/d:0,m=r?.errorRate||n?.errorRate?.warning;if(m&&p>m)await this.sendAlert({type:"errorRate",message:`Error rate threshold exceeded: ${p.toFixed(2)} > ${m.toFixed(2)}`,value:p,threshold:m,path:t.path,method:t.method,statusCode:t.statusCode,timestamp:t.timestamp,severity:"critical"})}}async sendAlert(t){let s=typeof this.options.alerts?.customHandler==="function";if(!s){let r=`${t.type}:${t.path}`,n=Date.now(),i=this.alertCooldowns.get(r)||0,l=this.options.alerts?.cooldown||60000;if(n-i<l)return;this.alertCooldowns.set(r,n)}if(s)try{await this.options.alerts.customHandler(t)}catch(r){console.error("Error in custom alert handler:",r)}if(this.options.alerts?.handler)try{await this.options.alerts.handler(t)}catch(r){console.error("Error in alert handler:",r)}console.warn(`[PerformanceMonitor] Alert: ${t.message} (${t.severity})`)}async sendAlerts(t,s){let r=`${s.path}-${t.join(",")}`,n=Date.now(),i=300000,l=this.alertCooldowns.get(r);if(l&&n-l<300000)return;this.alertCooldowns.set(r,n);let d={timestamp:new Date(s.timestamp).toISOString(),requestId:s.requestId,path:s.path,method:s.method,alerts:t,metrics:{responseTime:s.responseTime,memoryUsage:Math.round(s.memoryUsage.heapUsed/1024/1024),statusCode:s.statusCode}};if(this.options.alerts?.webhookUrl)try{await fetch(this.options.alerts.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)})}catch(u){console.error("Failed to send webhook alert:",u)}if(this.options.alerts?.slackConfig?.webhookUrl)try{await fetch(this.options.alerts.slackConfig.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({channel:this.options.alerts.slackConfig.channel,text:`\uD83D\uDEA8 Performance Alert: ${t.join(", ")}`,attachments:[{color:"danger",fields:[{title:"Path",value:s.path,short:!0},{title:"Response Time",value:`${s.responseTime}ms`,short:!0},{title:"Memory Usage",value:`${Math.round(s.memoryUsage.heapUsed/1024/1024)}MB`,short:!0},{title:"Status Code",value:s.statusCode.toString(),short:!0}]}]})})}catch(u){console.error("Failed to send Slack alert:",u)}}async collectMetrics(t){let{req:s,res:r,startTime:n,startMemory:i,startCPU:l,error:d}=t,u=performance.now(),p=R.memoryUsage(),m=R.cpuUsage(l),h=new URL(s.url),g=s.requestId||c().randomUUID(),y={user:m.user,system:m.system},b={requestId:g,timestamp:Date.now(),responseTime:u-n,memoryUsage:{rss:p.rss,heapTotal:p.heapTotal,heapUsed:p.heapUsed,external:p.external,arrayBuffers:p.arrayBuffers},cpuUsage:y,statusCode:r?.status||500,method:s.method,path:h.pathname};if(d)b.error=d.message||String(d);if(s.traceId)b.traceId=s.traceId;if(s.spanId)b.spanId=s.spanId;if(r){let v=r.headers.get("content-length");if(v)b.contentLength=Number.parseInt(v,10)}return console.warn(`[PerformanceMonitor] Collected metrics for ${s.method} ${h.pathname}: responseTime=${b.responseTime}ms, memory=${b.memoryUsage.heapUsed} bytes`),b}async handle(t,s){if(!this.options.enabled)return s();let r=this.options.sampling?.rate??this.options.sampleRate??1,n=Math.random();if(r<=0||n>r)return s();let i=Date.now();if(i-this.lastSecondTimestamp>1000)this.lastSecondTimestamp=i,this.requestsThisSecond=0;if(this.options.maxRequestsPerSecond&&this.requestsThisSecond>=this.options.maxRequestsPerSecond)return s();this.requestsThisSecond++,console.warn(`[PerformanceMonitor] Handling request: ${t.method} ${new URL(t.url).pathname}`);let l=performance.now(),d=R.memoryUsage(),u=R.cpuUsage(),p=[],m;if(this.options.profiling?.enabled){let y=t.requestId||c().randomUUID();if(!t.profiling)t.profiling={requestId:y,samples:[],systemSamples:[]};if(this.takeSample(t.profiling),this.options.profiling.sampleInterval)m=setInterval(()=>{if(t.profiling&&t.profiling.samples.length<(this.options.profiling?.maxSamples||100))this.takeSample(t.profiling)},this.options.profiling.sampleInterval)}let h=null,g;try{h=await s()}catch(y){throw g=y instanceof Error?y:Error(String(y)),g}finally{if(m)clearInterval(m);let y=await this.collectMetrics({req:t,res:h||new Response("Internal Server Error",{status:500}),startTime:l,startMemory:d,startCPU:u,profilingSamples:p,error:g});await this.storeMetrics(y),await this.checkThresholds(y)}if(!h)return new Response("Internal Server Error",{status:500});return h}addMetrics(t){this.metrics.push(t),console.warn(`[PerformanceMonitor] Added metric to internal array: ${t.path} ${t.method} ${t.responseTime}ms`)}async checkThresholdsPublic(t){return this.checkThresholds(t)}getMetrics(t){let s=this.metrics;if(t?.startTime)s=s.filter((r)=>r.timestamp>=t.startTime);if(t?.endTime)s=s.filter((r)=>r.timestamp<=t.endTime);if(t?.path)s=s.filter((r)=>r.path===t.path);if(t?.method)s=s.filter((r)=>r.method===t.method);if(t?.statusCode)s=s.filter((r)=>r.statusCode===t.statusCode);if(t?.limit)s=s.slice(-t.limit);return s}getAggregatedMetrics(t=60000){let r=Date.now()-t,n=this.metrics.filter((m)=>m.timestamp>=r);if(n.length===0)return{totalRequests:0,averageResponseTime:0,medianResponseTime:0,p95ResponseTime:0,p99ResponseTime:0,errorRate:0,averageMemoryUsage:0,requestsPerSecond:0,statusCodeDistribution:{},pathDistribution:{}};let i=n.map((m)=>m.responseTime).sort((m,h)=>m-h),l=n.filter((m)=>m.statusCode>=400).length,d=n.map((m)=>m.memoryUsage.heapUsed),u={},p={};return n.forEach((m)=>{u[m.statusCode]=(u[m.statusCode]||0)+1,p[m.path]=(p[m.path]||0)+1}),{totalRequests:n.length,averageResponseTime:i.reduce((m,h)=>m+h,0)/i.length,medianResponseTime:i[Math.floor(i.length/2)],p95ResponseTime:i[Math.floor(i.length*0.95)],p99ResponseTime:i[Math.floor(i.length*0.99)],errorRate:l/n.length,averageMemoryUsage:d.reduce((m,h)=>m+h,0)/d.length,requestsPerSecond:n.length/(t/1000),statusCodeDistribution:u,pathDistribution:p}}getProfiles(){let t=[],s=R.memoryUsage(),r=R.cpuUsage();t.push({timestamp:Date.now(),memoryUsage:s,cpuUsage:r});for(let n of this.requestContexts.values())if(n.samples&&n.samples.length>0)for(let i of n.samples)t.push({timestamp:i.timestamp,memoryUsage:i.memory,cpuUsage:i.cpu});return t}destroy(){if(this.cleanupInterval)clearInterval(this.cleanupInterval);this.requestContexts.clear(),this.alertCooldowns.clear()}}function Xt(t={}){let s=new pe(t);return async(r,n)=>s.handle(r,n)}class he{options;spans=new Map;activeSpans=new Map;exportQueue=[];exportInterval;constructor(t={}){let s=e.server?.performance?.monitoring?.tracing||{};if(this.options={enabled:t.enabled??s.enabled??!1,sampleRate:t.sampleRate??s.sampleRate??1,maxSpans:t.maxSpans??1e4,includeHeaders:t.includeHeaders??!1,includeQueryParams:t.includeQueryParams??!0,includeRequestBody:t.includeRequestBody??!1,includeResponseBody:t.includeResponseBody??!1,maxBodySize:t.maxBodySize??1048576,exporters:t.exporters??[{type:"console"}],propagation:{enabled:!0,headers:["x-trace-id","x-span-id","x-parent-span-id"],...t.propagation}},this.options.enabled)this.startExportInterval()}startExportInterval(){this.exportInterval=setInterval(async()=>{try{await this.exportSpans()}catch(t){console.warn("Error exporting spans:",t)}},100),this.exportInterval.unref?.()}shouldSample(){return Math.random()<(this.options.sampleRate||1)}generateId(){return Math.random().toString(36).substring(2,15)+Math.random().toString(36).substring(2,15)}extractPropagationHeaders(t){if(!this.options.propagation?.enabled)return{};let s=this.options.propagation.headers||[],r;for(let i of s){let l=t.headers.get(i);if(l){r=l;break}}let n=t.headers.get("x-parent-span-id")||void 0;return{traceId:r,parentSpanId:n}}async captureRequestBody(t){if(!this.options.includeRequestBody)return;try{let s=t.headers.get("content-type")||"",r=Number.parseInt(t.headers.get("content-length")||"0",10);if(r>(this.options.maxBodySize||1048576))return{truncated:!0,reason:"Body too large",size:r};if(s.includes("application/json"))return await t.clone().json();else if(s.includes("application/x-www-form-urlencoded")){let i=await t.clone().formData(),l={};for(let[d,u]of i.entries())l[d]=u;return l}else if(s.includes("text/"))return await t.clone().text()}catch(s){return{error:"Failed to capture body",message:s instanceof Error?s.message:String(s)}}return}async captureResponseBody(t){if(!this.options.includeResponseBody)return;try{let s=t.headers.get("content-type")||"",r=Number.parseInt(t.headers.get("content-length")||"0",10);if(r>(this.options.maxBodySize||1048576))return{truncated:!0,reason:"Body too large",size:r};if(s.includes("application/json"))return await t.clone().json();else if(s.includes("text/"))return await t.clone().text()}catch(s){return{error:"Failed to capture body",message:s instanceof Error?s.message:String(s)}}return}createSpan(t,s,r,n){return{traceId:t,spanId:s,parentSpanId:n,operationName:r,startTime:performance.now(),tags:{},logs:[],status:"ok"}}addSpanTag(t,s,r){let n=this.spans.get(t);if(n)n.tags[s]=r}addSpanLog(t,s,r,n){let i=this.spans.get(t);if(i)i.logs.push({timestamp:performance.now(),level:s,message:r,fields:n})}finishSpan(t,s="ok",r){let n=this.spans.get(t);if(n){if(n.endTime=performance.now(),n.duration=n.endTime-n.startTime,n.status=s,r){if(n.error=r,this.options.includeHeaders)n.stackTrace=Error("Trace error stack").stack?.split(`
|
|
356
|
+
`)}this.exportQueue.push(n),this.spans.delete(t)}}async exportSpans(){if(this.spans.size>0){let r=performance.now()-60000;for(let[n,i]of this.spans)if(i.endTime===void 0&&i.startTime<r)this.spans.delete(n)}if(this.exportQueue.length===0){let r=Array.from(this.spans.values()).filter((n)=>n.endTime!==void 0);if(r.length>0){this.exportQueue.push(...r);for(let n of r)this.spans.delete(n.spanId)}if(this.exportQueue.length===0)return}let t=[...this.exportQueue];this.exportQueue=[];let s=this.options.exporters||[];if(s.length===0){this.exportToConsole(t);return}for(let r of s)try{switch(r.type){case"console":this.exportToConsole(t);break;case"jaeger":await this.exportToJaeger(t,r);break;case"zipkin":await this.exportToZipkin(t,r);break;case"custom":if(typeof r.customExporter==="function")await r.customExporter(t);break}}catch(n){console.warn(`Failed to export spans to ${r.type}:`,n)}}exportToConsole(t){for(let s of t)console.warn("Trace Span:",{traceId:s.traceId,spanId:s.spanId,operation:s.operationName,duration:`${Math.round((s.duration||0)*100)/100}ms`,status:s.status,tags:s.tags,logs:s.logs.length,error:s.error})}async exportToJaeger(t,s){if(!s.endpoint)return;let r=t.map((n)=>({traceID:n.traceId,spanID:n.spanId,parentSpanID:n.parentSpanId,operationName:n.operationName,startTime:Math.floor(n.startTime*1000),duration:Math.floor((n.duration||0)*1000),tags:Object.entries(n.tags).map(([i,l])=>({key:i,type:typeof l==="string"?"string":"number",value:String(l)})),logs:n.logs.map((i)=>({timestamp:Math.floor(i.timestamp*1000),fields:[{key:"level",value:i.level},{key:"message",value:i.message},...i.fields?Object.entries(i.fields).map(([l,d])=>({key:l,value:String(d)})):[]]})),process:{serviceName:"bun-router",tags:[{key:"hostname",value:Bun.env.HOSTNAME||"localhost"},{key:"pid",value:String(123)}]}}));await fetch(`${s.endpoint}/api/traces`,{method:"POST",headers:{"Content-Type":"application/json",...s.headers},body:JSON.stringify({data:[{spans:r}]})})}async exportToZipkin(t,s){if(!s.endpoint)return;let r=t.map((n)=>({traceId:n.traceId,id:n.spanId,parentId:n.parentSpanId,name:n.operationName,timestamp:Math.floor(n.startTime*1000),duration:Math.floor((n.duration||0)*1000),kind:"SERVER",localEndpoint:{serviceName:"bun-router"},tags:n.tags,annotations:n.logs.map((i)=>({timestamp:Math.floor(i.timestamp*1000),value:`${i.level}: ${i.message}`}))}));await fetch(`${s.endpoint}/api/v2/spans`,{method:"POST",headers:{"Content-Type":"application/json",...s.headers},body:JSON.stringify(r)})}async handle(t,s){if(!this.options.enabled||!this.shouldSample())return await s()||new Response("Internal Server Error",{status:500});let r=t.requestId||this.generateId(),n=this.extractPropagationHeaders(t),i=n.traceId||this.generateId(),l=this.generateId(),d=new URL(t.url);console.warn(`[RequestTracer] Creating span for ${t.method} ${d.pathname}, traceId=${i}, spanId=${l}`);let u=this.createSpan(i,l,`${t.method} ${d.pathname}`,n.parentSpanId);if(this.spans.set(l,u),this.activeSpans.set(r,l),t.traceId=i,t.spanId=l,Object.defineProperties(t,{traceId:{value:i,writable:!0,enumerable:!0,configurable:!0},spanId:{value:l,writable:!0,enumerable:!0,configurable:!0}}),this.addSpanTag(l,"http.method",t.method),this.addSpanTag(l,"http.url",t.url),this.addSpanTag(l,"http.path",d.pathname),this.addSpanTag(l,"user_agent",t.headers.get("user-agent")),this.options.includeHeaders){let h={};for(let[g,y]of t.headers.entries())h[g]=y;this.addSpanTag(l,"http.headers",h)}if(this.options.includeQueryParams&&d.searchParams.size>0){let h={};for(let[g,y]of d.searchParams.entries())h[g]=y;this.addSpanTag(l,"http.query_params",h)}if(this.options.includeRequestBody&&t.method!=="GET"&&t.method!=="HEAD")try{let h=await this.captureRequestBody(t);if(h!==void 0)this.addSpanTag(l,"http.request_body",h)}catch(h){this.addSpanLog(l,"warn","Failed to capture request body",{error:String(h)})}this.addSpanLog(l,"info","Request started");let p,m;try{if(p=await s()||new Response("Internal Server Error",{status:500}),this.addSpanTag(l,"http.status_code",p.status),this.addSpanTag(l,"http.status_text",p.statusText),this.options.includeResponseBody)try{let y=await this.captureResponseBody(p);if(y!==void 0)this.addSpanTag(l,"http.response_body",y)}catch(y){this.addSpanLog(l,"warn","Failed to capture response body",{error:String(y)})}this.addSpanLog(l,"info","Request completed",{status:p.status,statusText:p.statusText});let g=p.status>=400;if(g)this.addSpanTag(l,"error",!0),this.addSpanTag(l,"error.status_code",p.status);this.finishSpan(l,g?"error":"ok",g?`HTTP ${p.status}`:void 0)}catch(h){m=h instanceof Error?h.message:String(h),this.addSpanTag(l,"error",!0),this.addSpanTag(l,"error.message",m),this.addSpanTag(l,"error.type",h instanceof Error?h.constructor.name:"Unknown"),this.addSpanLog(l,"error","Request failed",{error:m}),this.finishSpan(l,"error",m);let g=this.spans.get(l);if(g){if(g.endTime===void 0)g.endTime=performance.now(),g.duration=g.endTime-g.startTime,g.status="error",g.error=m;this.exportQueue.push(g),this.spans.delete(l),this.exportSpans().catch((y)=>{console.warn("Failed to export error span:",y)})}p=new Response("Internal Server Error",{status:500})}if(this.activeSpans.delete(r),this.options.propagation?.enabled)p.headers.set("x-trace-id",i),p.headers.set("x-span-id",l);return p}getActiveSpans(){return Array.from(this.spans.values())}getSpanById(t){return this.spans.get(t)}createChildSpan(t,s){let r=this.spans.get(t);if(!r)return null;let n=this.generateId(),i=this.createSpan(r.traceId,n,s,t);return this.spans.set(n,i),n}addTag(t,s,r){this.addSpanTag(t,s,r)}addLog(t,s,r,n){this.addSpanLog(t,s,r,n)}finish(t,s="ok",r){this.finishSpan(t,s,r)}async flush(){let t=Array.from(this.spans.keys());console.warn(`[RequestTracer] Flushing ${t.length} active spans`);for(let s of t){let r=this.spans.get(s);if(r&&!r.endTime)this.finishSpan(s,"ok")}await this.exportSpans()}destroy(){if(this.exportInterval)clearInterval(this.exportInterval);this.spans.clear(),this.activeSpans.clear(),this.exportQueue=[]}}function Yt(t={}){let s=new he(t);return async(r,n)=>s.handle(r,n)}class N{options;suspiciousPatterns=[];sqlInjectionPatterns=[];xssPatterns=[];pathTraversalPatterns=[];commandInjectionPatterns=[];constructor(t={}){let s=e.server?.security||{};this.options={inputValidation:{enabled:!0,maxBodySize:10485760,maxUrlLength:2048,maxHeaderSize:8192,allowedContentTypes:["application/json","application/x-www-form-urlencoded","multipart/form-data","text/plain","text/html","application/xml","text/xml"],sanitizeInput:!0,validateEncoding:!0,...t.inputValidation},requestFiltering:{enabled:!0,blockSuspiciousPatterns:!0,maxRequestsPerMinute:1000,blockUserAgents:["sqlmap","nikto","nessus","openvas","nmap","masscan","zap","w3af"],allowedMethods:["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"],requireUserAgent:!1,...t.requestFiltering},ipFiltering:{enabled:!1,whitelist:[],blacklist:[],blockPrivateIPs:!1,blockCloudProviders:!1,geoBlocking:{enabled:!1,allowedCountries:[],blockedCountries:[]},...t.ipFiltering},attackPrevention:{enabled:!0,sqlInjection:!0,xss:!0,pathTraversal:!0,commandInjection:!0,ldapInjection:!0,xxe:!0,customPatterns:[],...t.attackPrevention},responseSecurity:{enabled:!0,removeServerHeaders:!0,addSecurityHeaders:!0,sanitizeErrors:!0,preventInfoDisclosure:!0,...t.responseSecurity}},this.initializePatterns()}initializePatterns(){this.suspiciousPatterns=[/\.\.\//g,/\.\.\\/g,/%2e%2e%2f/gi,/%2e%2e%5c/gi,/\/etc\/passwd/gi,/\/proc\/self\/environ/gi,/cmd\.exe/gi,/powershell/gi,/<script/gi,/javascript:/gi,/vbscript:/gi,/onload=/gi,/onerror=/gi],this.sqlInjectionPatterns=[/(\bunion\b.+\bselect\b)|(\bselect\b.+\bunion\b)/gi,/\b(select|insert|update|delete|drop|create|alter|exec|execute)\b.+\b(from|into|set|where|table|database|schema)\b/gi,/(\bor\b|\band\b).+['"]\s*=\s*['"]|['"]\s*=\s*['"].+(\bor\b|\band\b)/gi,/\b(sleep|benchmark|waitfor)\s*\(/gi,/\b(information_schema|sys\.databases|sysobjects)\b/gi,/('|(\\')).+(or|and)\s+(?:\S.*|[\t\v\f \xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF])[=><]/gi,/\b(concat|group_concat|load_file|into\s+outfile)\b/gi],this.xssPatterns=[/<script[^>]*>.*?<\/script>/gi,/<iframe[^>]*>.*?<\/iframe>/gi,/<object[^>]*>.*?<\/object>/gi,/<embed[^>]*>/gi,/<link[^>]*>/gi,/<meta[^>]*>/gi,/javascript:/gi,/vbscript:/gi,/on\w+\s*=/gi,/<[^>]*\son\w+\s*=.*?>/gi,/expression\s*\(/gi,/url\s*\(\s*javascript:/gi],this.pathTraversalPatterns=[/\.\.\//g,/\.\.\\/g,/%2e%2e%2f/gi,/%2e%2e%5c/gi,/\.\.%2f/gi,/\.\.%5c/gi,/%252e%252e%252f/gi,/\.\/%2e%2e%2f/gi],this.commandInjectionPatterns=[/[;&|`${}[\]]/g,/\b(cat|ls|pwd|id|whoami|uname|ps|netstat|ifconfig|ping|nslookup|dig|curl|wget)\s/gi,/\b(cmd|powershell|bash|sh|zsh|fish)\s/gi,/\b(exec|system|shell_exec|passthru|eval)\s*\(/gi,/\$\{.*\}/g,/#\{.*\}/g]}getClientIP(t){return t.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||t.headers.get("x-real-ip")||t.headers.get("cf-connecting-ip")||t.headers.get("x-client-ip")||"unknown"}isPrivateIP(t){return[/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^127\./,/^169\.254\./,/^::1$/,/^fc00:/,/^fe80:/].some((r)=>r.test(t))}validateInput(t){let s=[];if(!this.options.attackPrevention?.enabled)return{isValid:!0,threats:s};if(this.options.attackPrevention.sqlInjection){for(let r of this.sqlInjectionPatterns)if(r.test(t)){s.push("SQL Injection");break}}if(this.options.attackPrevention.xss){for(let r of this.xssPatterns)if(r.test(t)){s.push("XSS");break}}if(this.options.attackPrevention.pathTraversal){for(let r of this.pathTraversalPatterns)if(r.test(t)){s.push("Path Traversal");break}}if(this.options.attackPrevention.commandInjection){for(let r of this.commandInjectionPatterns)if(r.test(t)){s.push("Command Injection");break}}if(this.options.attackPrevention.customPatterns){for(let r of this.options.attackPrevention.customPatterns)if(r.pattern.test(t))s.push(r.name)}return{isValid:s.length===0,threats:s}}sanitizeInput(t){if(!this.options.inputValidation?.sanitizeInput)return t;return t.replace(/[<>'"&]/g,(s)=>({"<":"<",">":">",'"':""","'":"'","&":"&"})[s]||s).replace(/javascript:/gi,"blocked:").replace(/vbscript:/gi,"blocked:").replace(/on\w+=/gi,"blocked=")}async handle(t,s){let r=this.getClientIP(t),n=t.headers.get("user-agent")||"",i=new URL(t.url);if(this.options.ipFiltering?.enabled){let d=this.options.ipFiltering;if(d.whitelist?.length&&!d.whitelist.includes(r))return new Response("Access Denied",{status:403});if(d.blacklist?.includes(r))return new Response("Access Denied",{status:403});if(d.blockPrivateIPs&&this.isPrivateIP(r))return new Response("Access Denied",{status:403})}if(this.options.requestFiltering?.enabled){let d=this.options.requestFiltering;if(d.allowedMethods&&!d.allowedMethods.includes(t.method))return new Response("Method Not Allowed",{status:405});if(d.requireUserAgent&&!n)return new Response("Bad Request",{status:400});if(d.blockUserAgents){if(d.blockUserAgents.some((p)=>n.toLowerCase().includes(p.toLowerCase())))return new Response("Access Denied",{status:403})}if(d.blockSuspiciousPatterns){let u=i.pathname+i.search;for(let p of this.suspiciousPatterns)if(p.test(u))return new Response("Suspicious Request Blocked",{status:400})}}if(this.options.inputValidation?.enabled){let d=this.options.inputValidation;if(d.maxUrlLength&&t.url.length>d.maxUrlLength)return new Response("URL Too Long",{status:414});let u=t.headers.get("content-type");if(u&&d.allowedContentTypes){if(!d.allowedContentTypes.some((m)=>u.toLowerCase().startsWith(m.toLowerCase())))return new Response("Unsupported Media Type",{status:415})}for(let[p,m]of i.searchParams.entries()){let h=this.validateInput(m);if(!h.isValid)return console.warn(`Security threat detected in query param ${p}:`,h.threats),new Response(`Security threat detected: ${h.threats.join(", ")}`,{status:400})}for(let[p,m]of t.headers.entries()){if(d.maxHeaderSize&&m.length>d.maxHeaderSize)return new Response("Header Too Large",{status:431});let h=this.validateInput(m);if(!h.isValid)return console.warn(`Security threat detected in header ${p}:`,h.threats),new Response(`Security threat detected: ${h.threats.join(", ")}`,{status:400})}}if(t.method!=="GET"&&t.method!=="HEAD"&&t.method!=="OPTIONS")try{let d=t.headers.get("content-length");if(d&&this.options.inputValidation?.maxBodySize){if(Number.parseInt(d,10)>this.options.inputValidation.maxBodySize)return new Response("Payload Too Large",{status:413})}}catch(d){console.error("Error checking content length:",d)}let l=await s();if(!l)return new Response("Not Found",{status:404});if(this.options.responseSecurity?.enabled){let d=new Headers(l.headers),u=this.options.responseSecurity;if(u.removeServerHeaders)d.delete("Server"),d.delete("X-Powered-By"),d.delete("X-AspNet-Version"),d.delete("X-AspNetMvc-Version");if(u.addSecurityHeaders)d.set("X-Content-Type-Options","nosniff"),d.set("X-Frame-Options","DENY"),d.set("X-XSS-Protection","0"),d.set("Referrer-Policy","strict-origin-when-cross-origin");return new Response(l.body,{status:l.status,statusText:l.statusText,headers:d})}return l}}function Qt(t={}){let s=new N(t);return async(r,n)=>s.handle(r,n)}class me{middlewares=[];constructor(t={}){let s=e.server?.security||{},r=["ddosProtection","security","helmet","contentSecurityPolicy","inputValidation"],n=t.order||r;for(let i of n)switch(i){case"ddosProtection":if(t.ddosProtection!==!1&&s.ddos?.enabled!==!1){let l=typeof t.ddosProtection==="object"?t.ddosProtection:{},d=new I(l);this.middlewares.push((u,p)=>d.handle(u,p))}break;case"security":if(t.security!==!1){let l=typeof t.security==="object"?t.security:{},d=new N(l);this.middlewares.push((u,p)=>d.handle(u,p))}break;case"helmet":if(t.helmet!==!1&&s.helmet?.enabled!==!1){let l=typeof t.helmet==="object"?t.helmet:{},d=new W(l);this.middlewares.push((u,p)=>d.handle(u,p))}break;case"contentSecurityPolicy":if(t.contentSecurityPolicy!==!1&&s.helmet?.contentSecurityPolicy!==!1){let l=typeof t.contentSecurityPolicy==="object"?t.contentSecurityPolicy:{},d=new O(l);this.middlewares.push((u,p)=>d.handle(u,p))}break;case"inputValidation":if(t.inputValidation!==!1&&s.inputValidation?.enabled!==!1){let l=typeof t.inputValidation==="object"?t.inputValidation:{},d=new F(l);this.middlewares.push((u,p)=>d.handle(u,p))}break}}async handle(t,s){let r=0,n=async()=>{if(r>=this.middlewares.length)return await s();let i=this.middlewares[r++];return await i(t,n)};return await n()}}function Zt(t={}){let s=new me(t);return async(r,n)=>s.handle(r,n)}var Cr=()=>new E,Sr=()=>new P,Er=()=>new M,Pr=()=>new A,Mr=()=>new o;function kr(){return new x({type:"bearer",validator:()=>!0})}var X=null;function G(){if(!X)X={"Middleware/Cors":new E,"Middleware/JsonBody":new P,"Middleware/RequestId":new M,"Middleware/Session":new A,"Middleware/Csrf":new o,"Middleware/Auth":new x({type:"bearer",validator:()=>!0}),"Middleware/RateLimit":Ee(),"Middleware/RequestSigning":new k({secret:""})};return X}var Me=new Proxy({},{get(t,s){return G()[s]},ownKeys(){return Object.keys(G())},getOwnPropertyDescriptor(t,s){let r=G()[s];if(r!==void 0)return{configurable:!0,enumerable:!0,value:r};return}});
|
|
357
|
+
export{At,c,Ze,xr,e,et,Se,tt,Ot,It,Ft,Nt,Dt,E,o,P,ie,Ee,M,a,rt,k,qt,Ht,Bt,w,oe,ae,ce,Tr,Pe,le,A,O,jt,I,Ut,V,f,Lt,_t,zt,Vt,Wt,W,F,Gt,ue,Kt,de,Jt,pe,Xt,he,Yt,N,Qt,me,Zt,Cr,Sr,Er,Pr,Mr,kr,Me};
|