@stacksjs/router 0.70.73 → 0.70.74
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/dist/index.js +2 -2
- package/dist/request-augmentation.d.ts +5 -1
- package/dist/stacks-router.d.ts +1 -1
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -46,5 +46,5 @@ export type ConfigOf = Config
|
|
|
46
46
|
- Window: ${this.windowMs}ms
|
|
47
47
|
- Max Requests: ${this.maxRequests}
|
|
48
48
|
- Storage: ${Z}
|
|
49
|
-
- Draft Mode: ${this.draftMode?"enabled":"disabled"}`)}}defaultKeyGenerator($){let Z=$.headers.get("x-forwarded-for");if(Z)return Z.split(",")[0].trim();let W=$.headers.get("x-client-ip");if(W)return W;let X=$.headers.get("x-real-ip");if(X)return X;return $.socket?.remoteAddress||"127.0.0.1"}async check($){try{if(this.skipFn&&await this.skipFn($))return this.createAllowedResult();if(this.maxRequests===0)return{allowed:!1,current:1,limit:0,remaining:this.windowMs,resetTime:Date.now()+this.windowMs};let Z=await this.keyGenerator($);if(this.algorithm==="sliding-window"&&this.storage.getSlidingWindowCount)return this.checkSlidingWindow(Z);else if(this.algorithm==="token-bucket")return this.checkTokenBucket(Z);else return this.checkFixedWindow(Z)}catch(Z){if(this.skipFailedRequests)return this.createAllowedResult();throw Z}}async checkFixedWindow($){let{count:Z,resetTime:W}=await this.storage.increment($,this.windowMs),X=Math.max(0,W-Date.now());return{allowed:this.draftMode?!0:Z<=this.maxRequests,current:Z,limit:this.maxRequests,remaining:X,resetTime:W}}async checkSlidingWindow($){if(!this.storage.getSlidingWindowCount)return this.checkFixedWindow($);await this.storage.increment($,this.windowMs);let Z=await this.storage.getSlidingWindowCount($,this.windowMs),X=Date.now()+this.windowMs;return{allowed:this.draftMode?!0:Z<=this.maxRequests,current:Z,limit:this.maxRequests,remaining:this.windowMs,resetTime:X}}async checkTokenBucket($){if(!this.tokenBucketOptions)return this.checkFixedWindow($);let Z=Date.now(),W=this.tokenBuckets.get($);if(!W)W={tokens:this.tokenBucketOptions.capacity,lastRefill:Z},this.tokenBuckets.set($,W);let Y=(Z-W.lastRefill)*this.tokenBucketOptions.refillRate;if(Y>0)W.tokens=Math.min(W.tokens+Y,this.tokenBucketOptions.capacity),W.lastRefill=Z;let J=this.draftMode?!0:W.tokens>=1;if(J&&!this.draftMode)W.tokens-=1;let G=W.tokens>=this.tokenBucketOptions.capacity?this.windowMs:Math.ceil(1/this.tokenBucketOptions.refillRate);return{allowed:J,current:this.tokenBucketOptions.capacity-Math.floor(W.tokens),limit:this.tokenBucketOptions.capacity,remaining:G,resetTime:Z+G}}createAllowedResult(){return{allowed:!0,current:0,limit:this.maxRequests,remaining:this.windowMs,resetTime:Date.now()+this.windowMs}}async consume($){if(this.algorithm==="sliding-window"&&this.storage.getSlidingWindowCount)return this.checkSlidingWindow($);else if(this.algorithm==="token-bucket")return this.checkTokenBucket($);else return this.checkFixedWindow($)}async peek($){if(typeof this.storage.getCount!=="function")return null;let Z=await this.storage.getCount($),W=Date.now();return{allowed:this.draftMode?!0:Z<this.maxRequests,current:Z,limit:this.maxRequests,remaining:this.windowMs,resetTime:W+this.windowMs}}async enforce($){let Z=await this.consume($);if(!Z.allowed)throw new J8(`Rate limit exceeded for '${$}'`,Z);return Z}async reset($){if(await this.storage.reset($),this.algorithm==="token-bucket")this.tokenBuckets.delete($)}async resetAll(){if(this.algorithm==="token-bucket")this.tokenBuckets.clear();if(this.storage.cleanExpired)this.storage.cleanExpired()}getHeaders($){let Z={};if(this.standardHeaders)Z["RateLimit-Limit"]=this.maxRequests.toString(),Z["RateLimit-Remaining"]=Math.max(0,this.maxRequests-$.current).toString(),Z["RateLimit-Reset"]=Math.ceil($.resetTime/1000).toString();if(this.legacyHeaders){if(Z["X-RateLimit-Limit"]=this.maxRequests.toString(),Z["X-RateLimit-Remaining"]=Math.max(0,this.maxRequests-$.current).toString(),Z["X-RateLimit-Reset"]=Math.ceil($.resetTime/1000).toString(),!$.allowed)Z["Retry-After"]=Math.ceil($.remaining/1000).toString()}return Z}middleware(){return async($)=>{let Z=await this.check($);if(!Z.allowed){if(this.handler)return this.handler($,Z);return new Response("Rate limit exceeded",{status:429,headers:this.getHeaders(Z)})}return null}}dispose(){if(this.storage.dispose)this.storage.dispose();this.tokenBuckets.clear()}}function e9($){let Z=$,W=Z._authenticatedUser?.id;if(W!==void 0)return`user:${String(W)}`;let X=Z._currentAccessToken?.id;if(X!==void 0)return`token:${String(X)}`;let Y=$.headers.get("authorization");if(Y?.startsWith("Bearer "))return`bearer:${Y.slice(7,39)}`;let J=$.headers.get("x-forwarded-for");if(J)return`ip:${J.split(",")[0]?.trim()??"unknown"}`;let G=$.headers.get("x-real-ip");if(G)return`ip:${G}`;return"anon"}var EZ,RZ=($)=>$,bZ=($,Z)=>{for(var W in Z)EZ($,W,{get:Z[W],enumerable:!0,configurable:!0,set:qZ.bind(Z,W)})},d=($,Z)=>()=>($&&(Z=$($=0)),Z),wZ,V5,b5,v9,w5,R9,S8,E5,gZ,N,_,hZ,q9,mZ,b9,pZ,cZ,N8,dZ,w9,P9,uZ,C8,lZ,nZ,iZ,sZ,oZ,r5,f9,tZ,aZ,rZ="0.15.9",eZ=()=>{},P,$8,R5,E8,R8,Z8,q8,b8,q5,w8,P8,n,_5,m9,u9,h8,l9,n9,i9,v,c,o9,t9,L1,A1=()=>{},a9,r9,V1,k,J8;var $$=u(()=>{EZ=Object.defineProperty;wZ=import.meta.require;w5=d(()=>{V5=new y8,b5=new f8,v9={createKey:PZ,isEquivalent:kZ,estimateMemoryUsage:vZ}});aZ=d(()=>{R9=e5.env.CLARITY_LOG_DIR||BZ(yZ(),"logs"),S8={level:"info",defaultName:"clarity",timestamp:!0,colors:!0,format:"text",maxLogSize:10485760,logDatePattern:"YYYY-MM-DD",logDirectory:R9,rotation:{frequency:"daily",maxSize:10485760,maxFiles:5,compress:!1,rotateHour:0,rotateMinute:0,rotateDayOfWeek:0,rotateDayOfMonth:1,encrypt:!1},verbose:!1,writeToFile:!1},E5={...S8},gZ=(async()=>{try{let{loadConfig:$}=await Promise.resolve().then(()=>(r9(),a9)),Z=await $({name:"clarity",alias:"logging",defaultConfig:S8,cwd:e5.cwd()});if(Z)Object.assign(E5,Z)}catch{}return E5})(),N={red:($)=>`\x1B[31m${$}\x1B[0m`,green:($)=>`\x1B[32m${$}\x1B[0m`,yellow:($)=>`\x1B[33m${$}\x1B[0m`,blue:($)=>`\x1B[34m${$}\x1B[0m`,magenta:($)=>`\x1B[35m${$}\x1B[0m`,cyan:($)=>`\x1B[36m${$}\x1B[0m`,white:($)=>`\x1B[37m${$}\x1B[0m`,gray:($)=>`\x1B[90m${$}\x1B[0m`,bgRed:($)=>`\x1B[41m${$}\x1B[0m`,bgYellow:($)=>`\x1B[43m${$}\x1B[0m`,bgGray:($)=>`\x1B[100m${$}\x1B[0m`,bold:($)=>`\x1B[1m${$}\x1B[0m`,dim:($)=>`\x1B[2m${$}\x1B[0m`,italic:($)=>`\x1B[3m${$}\x1B[0m`,underline:($)=>`\x1B[4m${$}\x1B[0m`,strikethrough:($)=>`\x1B[9m${$}\x1B[0m`,reset:"\x1B[0m"},_=N,hZ=N.red,q9=N.green,mZ=N.yellow,b9=N.blue,pZ=N.magenta,cZ=N.cyan,N8=N.white,dZ=N.gray,w9=N.bgRed,P9=N.bgYellow,uZ=N.bgGray,C8=N.bold,lZ=N.dim,nZ=N.italic,iZ=N.underline,sZ=N.strikethrough,oZ=N.reset,r5={activationLevel:"error",bufferSize:50,flushOnDeactivation:!0,stopBuffering:!1},f9={debug:"\uD83D\uDD0D",info:b9("\u2139"),success:q9("\u2713"),warning:P9(N8(C8(" WARN "))),error:w9(N8(C8(" ERROR ")))},tZ=new W8("stacks")});_5=d(()=>{P=class extends Error{timestamp;context;constructor(Z,W={}){super(Z);if(this.name=this.constructor.name,this.timestamp=new Date,this.context=W,Error.captureStackTrace)Error.captureStackTrace(this,this.constructor)}toJSON(){return{name:this.name,code:this.code,message:this.message,timestamp:this.timestamp.toISOString(),context:this.context,stack:this.stack}}toString(){let Z=Object.keys(this.context).length>0?` (${Object.entries(this.context).map(([W,X])=>`${W}: ${X}`).join(", ")})`:"";return`${this.name} [${this.code}]: ${this.message}${Z}`}},$8=class extends P{code="CONFIG_NOT_FOUND";constructor(Z,W,X){let Y=X===void 0?[]:Array.isArray(X)?X.filter(Boolean):[X],J="";if(Y.length===1)J=` or alias "${Y[0]}"`;else if(Y.length>1)J=` or aliases ${Y.map((G)=>`"${G}"`).join(", ")}`;super(`Configuration "${Z}"${J} not found`,{configName:Z,alias:X,searchPaths:W,searchPathCount:W.length})}},R5=class extends P{code="CONFIG_LOAD_ERROR";constructor(Z,W,X){super(`Failed to load configuration from "${Z}": ${W.message}`,{configPath:Z,configName:X,originalError:W.name,originalMessage:W.message});this.cause=W}},E8=class extends P{code="CONFIG_VALIDATION_ERROR";constructor(Z,W,X){super(`Configuration validation failed for "${Z}"`,{configPath:Z,configName:X,validationErrors:W,errorCount:W.length})}},R8=class extends P{code="CONFIG_MERGE_ERROR";constructor(Z,W,X,Y){super(`Failed to merge configuration from "${Z}" with "${W}": ${X.message}`,{sourcePath:Z,targetPath:W,configName:Y,originalError:X.name,originalMessage:X.message});this.cause=X}},Z8=class extends P{code="ENV_VAR_ERROR";constructor(Z,W,X,Y){super(`Failed to parse environment variable "${Z}" with value "${W}" as ${X}`,{envKey:Z,envValue:W,expectedType:X,configName:Y})}},q8=class extends P{code="FILE_SYSTEM_ERROR";constructor(Z,W,X){super(`File system ${Z} failed for "${W}": ${X.message}`,{operation:Z,path:W,originalError:X.name,originalMessage:X.message});this.cause=X}},b8=class extends P{code="TYPE_GENERATION_ERROR";constructor(Z,W,X){super(`Failed to generate types from "${Z}" to "${W}": ${X.message}`,{configDir:Z,outputPath:W,originalError:X.name,originalMessage:X.message});this.cause=X}},q5=class extends P{code="SCHEMA_VALIDATION_ERROR";constructor(Z,W,X){super(`Schema validation failed${X?` for config "${X}"`:""}`,{schemaPath:Z,configName:X,validationErrors:W,errorCount:W.length})}},w8=class extends P{code="BROWSER_CONFIG_ERROR";constructor(Z,W,X,Y){super(`Failed to fetch configuration from "${Z}": ${W} ${X}`,{endpoint:Z,status:W,statusText:X,configName:Y})}},P8=class extends P{code="PLUGIN_ERROR";constructor(Z,W,X){super(`Plugin "${Z}" failed during ${W}: ${X.message}`,{pluginName:Z,operation:W,originalError:X.name,originalMessage:X.message});this.cause=X}},n={configNotFound($,Z,W){return new $8($,Z,W)},configLoad($,Z,W){return new R5($,Z,W)},configValidation($,Z,W){return new E8($,Z,W)},configMerge($,Z,W,X){return new R8($,Z,W,X)},envVar($,Z,W,X){return new Z8($,Z,W,X)},fileSystem($,Z,W){return new q8($,Z,W)},typeGeneration($,Z,W){return new b8($,Z,W)},schemaValidation($,Z,W){return new q5($,Z,W)},browserConfig($,Z,W,X){return new w8($,Z,W,X)},plugin($,Z,W){return new P8($,Z,W)}}});m9=d(()=>{w5(),_5()});h8=d(()=>{u9={replace:"replace",concat:"concat",smart:"smart"}});l9=d(()=>{w5(),_5(),h8()});i9=d(()=>{w5(),_5(),n9=/^https?:\/\//});L1=d(()=>{aZ(),eZ(),w5(),_5(),m9(),l9(),i9(),h8(),v=new W8("bunfig",{showTags:!0}),c=new p8,o9=R($5.cwd(),"config"),t9=R($5.cwd(),"src/generated")});a9={};bZ(a9,{withErrorRecovery:()=>g9,tryLoadConfig:()=>U1,loadConfigWithResult:()=>Q1,loadConfig:()=>s9,isRetryableError:()=>Z1,isConfigNotFoundError:()=>$1,isBunfigError:()=>h9,globalPerformanceMonitor:()=>b5,globalCache:()=>V5,getEnvOrDefault:()=>W1,generateConfigTypes:()=>j1,defaultGeneratedDir:()=>t9,defaultConfigDir:()=>o9,deepMergeWithArrayStrategy:()=>g8,deepMerge:()=>p9,createLibraryConfig:()=>H1,config:()=>B1,bunfigPlugin:()=>F1,applyEnvVarsToConfig:()=>x5,TypeGenerationError:()=>b8,SchemaValidationError:()=>q5,PluginError:()=>P8,PerformanceMonitor:()=>f8,FileSystemError:()=>q8,ErrorFactory:()=>n,EnvVarError:()=>Z8,EnvProcessor:()=>X8,ConfigValidator:()=>m8,ConfigValidationError:()=>E8,ConfigNotFoundError:()=>$8,ConfigMergeError:()=>R8,ConfigLoader:()=>p8,ConfigLoadError:()=>R5,ConfigFileLoader:()=>Y8,ConfigCache:()=>y8,CacheUtils:()=>v9,BunfigError:()=>P,BrowserConfigError:()=>w8,ArrayMergeStrategies:()=>u9});r9=d(()=>{L1(),_5(),w5(),_5(),A1(),m9(),l9(),i9(),h8()});r9();V1={verbose:!1,storage:"memory",algorithm:"fixed-window",windowMs:60000,maxRequests:100,standardHeaders:!0,legacyHeaders:!0,draftMode:!1,redisKeyPrefix:"ratelimit:",memoryStorage:{enableAutoCleanup:!0,cleanupIntervalMs:60000},redis:{url:"redis://localhost:6379",enableSlidingWindow:!1}},k=V1;J8=class J8 extends Error{name="RateLimitError";retryAfter;result;constructor($,Z){super($);this.result=Z,this.retryAfter=Math.max(1,Math.ceil(Z.remaining/1000))}toHeaders(){return{"Retry-After":String(this.retryAfter),"RateLimit-Limit":String(this.result.limit),"RateLimit-Remaining":"0","RateLimit-Reset":String(Math.ceil(this.result.resetTime/1000))}}}});import{HttpError as _1}from"@stacksjs/error-handling";function d8($,Z){let W=`${Z}:${$}`,X=Z$.get(W);if(!X)X=new c8({windowMs:Z,maxRequests:$,algorithm:"fixed-window",standardHeaders:!1,legacyHeaders:!1}),Z$.set(W,X);return X}function u8($){if($!==void 0)return $;let Z=t();return Z?e9(Z):"anon"}function l8($,Z,W={}){let X=u8(W.identity),Y=`${$}:${X}`,J=async(G)=>{let z=d8(Z,G);try{await z.enforce(Y)}catch(Q){if(Q instanceof J8)throw Object.assign(new _1(429,"Too many requests",{key:$,max:Z,retryAfter:Q.retryAfter}),{headers:Q.toHeaders()});throw Q}};return{async per(G){let z=I1[G];if(!z)throw Error(`rateLimit().per: unknown period '${G}'`);await J(z*1000)},async over(G){if(!Number.isFinite(G)||G<=0)throw Error(`rateLimit().over: ttl must be a positive number, got ${G}`);await J(G*1000)}}}async function D1($,Z,W,X={}){let Y=u8(X.identity),J=`${$}:${Y}`,z=await d8(Z,W*1000).peek(J);if(!z)return null;return{count:z.current,limit:z.limit,remaining:Math.max(0,z.limit-z.current)}}async function O1($,Z,W,X={}){let Y=u8(X.identity),J=`${$}:${Y}`;await d8(Z,W*1000).reset(J)}var I1,Z$;var n8=u(()=>{$$();N5();I1={second:1,minute:60,hour:3600,day:86400},Z$=new Map});import Z5 from"process";function K1(){if(G8!==void 0)return G8;return G8=(Z5.env.APP_ENV??Z5.env.NODE_ENV??"").toLowerCase()==="production",G8}function T1(){if(z8!==void 0)return z8;return z8=Z5.env.STACKS_SECURITY_HEADERS_DISABLE==="true",z8}function M1(){if(I5!==void 0)return I5;let $=Z5.env.STACKS_CSP,Z=Z5.env.STACKS_CSP_REPORT_ONLY;if($)I5={header:"Content-Security-Policy",value:$};else if(Z)I5={header:"Content-Security-Policy-Report-Only",value:Z};else I5=null;return I5}function W$($){if(T1())return;if(!$.has("X-Content-Type-Options"))$.set("X-Content-Type-Options","nosniff");if(!$.has("X-Frame-Options"))$.set("X-Frame-Options","SAMEORIGIN");if(!$.has("Referrer-Policy"))$.set("Referrer-Policy","strict-origin-when-cross-origin");if(K1()&&!$.has("Strict-Transport-Security"))$.set("Strict-Transport-Security","max-age=31536000; includeSubDomains");let Z=M1();if(Z&&!$.has(Z.header))$.set(Z.header,Z.value)}var G8,z8,I5;var X$=()=>{};var G$={};G9(G$,{loadRoutes:()=>J$});import{log as S1}from"@stacksjs/logging";async function J$($){for(let[Z,W]of Object.entries($)){let X=E1(W),Y=X.prefix!==void 0?X.prefix?X.prefix.startsWith("/")?X.prefix:`/${X.prefix}`:void 0:N1.includes(Z)?void 0:`/${Z}`,J=R1(X.middleware);S1.debug(`[route-loader] Loading: ${X.path} prefix=${Y||"/"} middleware=[${J.join(", ")}]`);try{if(Y||J.length>0)await D5.group({prefix:Y,middleware:J.length>0?J:void 0},async()=>{await Y$(X.path)});else await Y$(X.path)}catch(G){let z=G instanceof Error?G.message:String(G);throw console.error(`[Routes] Failed to load route file '${X.path}': ${z}`),Error(`Route loading failed for '${X.path}': ${z}`)}}await C1()}async function C1(){if(process.env.STACKS_SKIP_DEFAULT_ROUTES==="1")return;try{let{frameworkPath:$}=await import("@stacksjs/path"),Z=$("defaults/bootstrap.ts");if(await Bun.file(Z).exists())await import(Z)}catch($){let Z=$ instanceof Error?$.message:String($);if(!Z.includes("Cannot find module")&&!Z.includes("MODULE_NOT_FOUND"))console.error(`[Routes] Failed to load framework bootstrap: ${Z}`)}}function x1($){if(typeof $!=="string"||$.length===0)throw Error("[route-loader] Invalid route path: empty or non-string");if($.includes("\x00"))throw Error("[route-loader] Invalid route path: null byte");let Z;try{Z=decodeURIComponent($)}catch{throw Error("[route-loader] Invalid route path: malformed URL encoding")}let W=Z.replace(/\.ts$/,"");if(W.startsWith("/")||/^[A-Za-z]:[\\/]/.test(W))throw Error(`[route-loader] Invalid route path: absolute paths not allowed (${W})`);if(W.split(/[/\\]/).some((Y)=>Y===".."))throw Error(`[route-loader] Invalid route path: '..' segment not allowed (${W})`);return W}async function Y$($){let Z=x1($),{projectPath:W}=await import("@stacksjs/path");await import(W(`routes/${Z}`))}function E1($){if(typeof $==="string")return{path:$};return $}function R1($){if(!$)return[];if(typeof $==="string")return[$];return $}var N1;var i8=u(()=>{O5();N1=["web"]});import T from"process";import{Buffer as z$}from"buffer";import{existsSync as q1}from"fs";import{timingSafeEqual as b1}from"crypto";import{log as A,report as F$}from"@stacksjs/logging";import{path as w}from"@stacksjs/path";import{UploadedFile as Q8}from"@stacksjs/storage";import{applyRequestEnhancements as w1,Router as P1}from"@stacksjs/bun-router";import{isCursorPaginator as k1,isPaginator as v1,isSimplePaginator as y1}from"@stacksjs/orm";function i($){let Z=w.storagePath(`framework/defaults/${$}`);if(q1(Z))return Z;if(P5===void 0)try{let W=Bun.resolveSync("@stacksjs/defaults/package.json",T.cwd());P5=W.slice(0,W.lastIndexOf("/"))}catch{P5=null}return P5?`${P5}/${$}`:Z}function f1($){if(typeof $==="number"){if(!Number.isFinite($)||$<=0)throw Error(`[Router] .rateLimit(): window must be a positive number of seconds, got ${$}`);return Math.floor($)}switch($){case"second":return 1;case"minute":return 60;case"hour":return 3600;case"day":return 86400;default:throw Error(`[Router] .rateLimit(): unknown period '${String($)}'`)}}class e8{max;map=new Map;constructor($){this.max=$}get($){return this.map.get($)}has($){return this.map.has($)}set($,Z){if(this.map.has($))this.map.delete($);if(this.map.set($,Z),this.map.size>this.max){let W=this.map.keys().next().value;if(W!==void 0)this.map.delete(W)}return this}delete($){return this.map.delete($)}clear(){this.map.clear()}get size(){return this.map.size}}function Q$($){let Z=T.env.STACKS_EXPOSE_ROUTES??"";if(!Z)return!((T.env.APP_ENV??"").toLowerCase()==="production"||T.env.NODE_ENV==="production");if(Z==="1")return!((T.env.APP_ENV??"").toLowerCase()==="production"||T.env.NODE_ENV==="production");let W=new URL($.url),X=$.headers.get("x-stacks-routes-token")||$.headers.get("X-Stacks-Routes-Token")||W.searchParams.get("token")||"";if(typeof X!=="string"||X.length===0||X.length!==Z.length)return!1;try{return b1(z$.from(X),z$.from(Z))}catch{return!1}}async function B8($,Z){if(!$._corsConfig||!Z)return Z;try{let{applyCorsHeaders:W}=await import(i("app/Middleware/Cors.ts"));return W($,Z,$._corsConfig)}catch(W){return A.warn("[router] CORS header injection failed",{error:W}),Z}}function g1($){let Z=h1($),W=new Map;for(let X of Z)W.set(X,new RegExp(`(^|/):${X}(?=$|/)`,"g"));return{path:$,paramNames:Z,colonRegex:W}}function h1($){let Z=new Set;for(let W of $.matchAll(/\{(\w+)\}/g))if(W[1])Z.add(W[1]);for(let W of $.matchAll(/(?:^|\/):(\w+)(?=$|\/)/g))if(W[1])Z.add(W[1]);return[...Z]}function W9($,Z={}){let W=v5.get($);if(!W)throw Error(`Route '${$}' is not defined. Available routes: ${[...v5.keys()].join(", ")}`);let X=W.paramNames.filter((Q)=>!(Q in Z)||Z[Q]===void 0);if(X.length>0)throw Error(`url('${$}'): missing required path param${X.length>1?"s":""} [${X.join(", ")}] for path '${W.path}'. Pass them as the second argument: url('${$}', { ${W.paramNames.join(", ")} })`);let Y;try{Y=T.env.APP_URL||"https://localhost"}catch{Y="https://localhost"}if(Y=Y.replace(/\/$/,""),!Y.startsWith("http"))Y=`https://${Y}`;let J=W.path,G={};for(let[Q,B]of Object.entries(Z)){let U=`{${Q}}`;if(J.includes(U))J=J.replaceAll(U,encodeURIComponent(String(B)));else{let j=W.colonRegex.get(Q);if(j&&j.test(J))j.lastIndex=0,J=J.replace(j,`$1${encodeURIComponent(String(B))}`);else G[Q]=String(B)}}let z=Object.keys(G).length>0?`?${new URLSearchParams(G).toString()}`:"";return`${Y}${J}${z}`}function m1($){let Z=v5.get($);return Z?[...Z.paramNames]:[]}function _$(){let $=[],Z=new Set;for(let W of J5.keys()){if(Z.has(W))continue;Z.add(W);let X=W.indexOf(":");if(X===-1)continue;let Y=W.slice(0,X),J=W.slice(X+1),G;for(let[z,Q]of v5.entries())if(Q.path===J){G=z;break}$.push({method:Y,path:J,name:G})}return $.sort((W,X)=>W.path.localeCompare(X.path))}function p1($,Z){let W=`${$}:${String(Z)}`;if(U$.has(W))return;U$.add(W),A.warn(`[Router] Middleware '${$}' declared an invalid priority (${String(Z)}). Priorities must be a finite non-negative number; falling back to default ${I$}.`)}function c1($){if($ instanceof h5)return $.toRouterHandler();if($&&typeof $==="object"&&typeof $.handle==="function"&&typeof $!=="function"){let Z=$.handle.bind($);return async(X,Y)=>{try{await Z(X)}catch(J){if(J instanceof Response)return J;throw J}return Y()}}return $}async function d1(){if(k5)return k5;return k5=(async()=>{try{return(await import(w.appPath("Middleware.ts"))).default||{}}catch{try{return(await import(i("app/Middleware.ts"))).default||{}}catch{return{}}}})(),k5}function l1($){if(!$)return $;let Z=j$.get($);if(Z!==void 0)return Z;let W=$.split(u1).filter(Boolean).map((X)=>X.charAt(0).toUpperCase()+X.slice(1)).join("");return j$.set($,W),W}async function n1($){let W=(await d1())[$]||l1($);return A.debug(`[middleware] Resolved: ${$} \u2192 ${W}`),W}async function D$($){if(Y5.has($))return Y5.get($)??null;let Z=await n1($),W;try{let X=w.appPath(`Middleware/${Z}.ts`),J=(await import(X)).default??null;if(!J||typeof J.handle!=="function")return A.error(`[Router] Middleware '${$}' resolved to ${X}, but the file has no default export with a handle() method`),Y5.set($,null),null;return Y5.set($,J),J}catch(X){W=X}try{let X=i(`app/Middleware/${Z}.ts`),J=(await import(X)).default??null;if(!J||typeof J.handle!=="function")return A.error(`[Router] Middleware '${$}' resolved to ${X}, but the file has no default export with a handle() method`),Y5.set($,null),null;return Y5.set($,J),J}catch(X){let Y=W instanceof Error?W.message:String(W);return A.error(`[Router] Failed to load middleware '${$}' (resolved to '${Z}'). app/Middleware: ${Y}; defaults:`,X),null}}function O$(){Y5.clear(),k5=null,$9.clear(),Z9.clear()}function i1(){if(T.env.APP_ENV==="production"||T.env.NODE_ENV==="production")return()=>{};let $=[];return(async()=>{try{let Z=await import("fs"),W=[w.appPath("Middleware"),w.appPath("Middleware.ts")];for(let X of W)try{if(!Z.existsSync(X))continue;let Y=Z.watch(X,{recursive:!0},()=>{A.debug("[middleware] hot-reload: clearing cache"),O$()});$.push(Y)}catch{}}catch{}})(),()=>{for(let Z of $)try{Z.close()}catch{}$=[]}}function T$($){let Z=$.indexOf(":");if(Z===-1)return{name:$};return{name:$.substring(0,Z),params:$.substring(Z+1)}}async function M$(){let $=new Map;for(let[W,X]of J5)for(let Y of X){let{name:J}=T$(Y),G=$.get(J)??[];G.push(W),$.set(J,G)}if(!$.has("csrf"))$.set("csrf",["(auto-injected on POST/PUT/PATCH/DELETE)"]);let Z=[];for(let[W,X]of $){let Y=await D$(W);if(!Y||typeof Y.handle!=="function")Z.push({alias:W,routes:X})}return Z}async function S$(){let $=await M$();if($.length===0)return;let Z=$.map((W)=>`"${W.alias}" (used by ${W.routes.join(", ")})`).join("; ");throw Error(`[Router] Unresolvable middleware alias(es): ${Z}. Check the alias map in app/Middleware.ts or add app/Middleware/<Class>.ts.`)}function W5($,Z){let W=Z6(Z,!0),X=null;if(typeof Z==="string"){let Y=$.slice(0,$.indexOf(":")).toUpperCase();if(B$.has(Y))X=N$(Z).then(()=>{return}).catch(()=>{return})}return async(Y)=>{try{await x$(Y)}catch(G){let z=G instanceof Error?G:Error(String(G));return j5(z,Y)}let J=C$(Y);if(X)await X;if(K$.has($))Y._forceJson=!0;return _8(J,async()=>{let G=A$.get($);if(G)try{await l8($,G.max).over(G.windowSeconds)}catch(D){return j5(D,Y)}let z=J5.get($)||[],Q=Y.method.toUpperCase(),B=[...z],U=z.some((D)=>D==="csrf"||D.startsWith("csrf:")),j=t8.has($),H=a8.has($),L=Z9.get($),F=L?$9.get(L)===!0:!1;if(B$.has(Q)&&!U&&(H||!j&&!F))B.unshift("csrf");if(B.length>0){let D=(T.env.LOG_LEVEL||"info").toLowerCase();if(D!=="info"&&D!=="warn"&&D!=="error"){let K=Y.url.indexOf("://"),M=K===-1?0:Y.url.indexOf("/",K+3),E=Y.url.indexOf("?",M<0?0:M),x=M<0?"/":Y.url.slice(M,E===-1?void 0:E);A.debug(`[middleware] Executing chain: [${B.join(", ")}] for ${Q} ${x}`)}}let f=[];for(let D of B){let{name:K,params:M}=T$(D);if(M)J._middlewareParams=J._middlewareParams||{},J._middlewareParams[K]=M;let E=await D$(K);if(!E||typeof E.handle!=="function"){A.error(`[Router] Middleware '${K}' on ${$} could not be resolved \u2014 failing closed`);let h=Error(`Middleware '${K}' could not be resolved`),Q5=await l(h,J,{status:500});return await B8(J,Q5)}let x=E.priority,z5=I$;if(typeof x==="number"&&Number.isFinite(x)&&x>=0)z5=x;else if(x!==void 0)p1(K,x);f.push({name:K,handler:E,priority:z5})}f.sort((D,K)=>D.priority-K.priority);let q=[];for(let{name:D,handler:K}of f){let M=T.hrtime.bigint(),E;try{let z5=new Promise((Q5,s)=>{E=setTimeout(()=>s(Error(`Middleware '${D}' exceeded 30000ms`)),30000)});await Promise.race([K.handle(J),z5]);let h=Number(T.hrtime.bigint()-M)/1e6;q.push({name:D,ms:h})}catch(x){let z5=Number(T.hrtime.bigint()-M)/1e6;if(q.push({name:D,ms:z5}),A.debug(`[middleware] Blocked by: ${D}`),x instanceof Response){try{let{_requestId:s,_startNs:K5}=J,T5=K5!=null?Number(T.hrtime.bigint()-K5)/1e6:null,o=T5!=null?[`total;dur=${T5.toFixed(1)}`]:[];for(let M5 of q){let F8=M5.name.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,32);o.push(`mw_${F8};dur=${M5.ms.toFixed(1)}`)}if(o.length>0)x.headers.set("Server-Timing",o.join(", "));if(s)x.headers.set("X-Request-ID",s)}catch{}return await B8(J,x)}let h=x instanceof Error?x:Error(String(x)),Q5="statusCode"in h||"status"in h?await j5(h,J):await(()=>{return A.error(`[Router] Middleware '${D}' threw an unexpected error:`,h),l(h,J,{status:500})})();try{let{_requestId:s,_startNs:K5}=J,T5=K5!=null?Number(T.hrtime.bigint()-K5)/1e6:null,o=T5!=null?[`total;dur=${T5.toFixed(1)}`]:[];for(let M5 of q){let F8=M5.name.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,32);o.push(`mw_${F8};dur=${M5.ms.toFixed(1)}`)}if(o.length>0)Q5.headers.set("Server-Timing",o.join(", "));if(s)Q5.headers.set("X-Request-ID",s)}catch{}return await B8(J,Q5)}finally{clearTimeout(E)}}let O=await W(J);if(l5(),O){if(Y.method==="GET"||Y.method==="HEAD"||Y.method==="OPTIONS")try{let{seedCsrfCookieIfMissing:K}=await import(i("app/Middleware/Csrf.ts"));O=K(J,O)}catch(K){A.warn("[router] CSRF cookie seeding failed",{error:K})}}if(O)O=await B8(J,O);let{_requestId:G5,_startNs:f5}=J,g5=f5!=null?Number(T.hrtime.bigint()-f5)/1e6:null,L8=(D)=>{if(G5)D.set("X-Request-ID",G5);if(g5!=null){let K=[`total;dur=${g5.toFixed(1)}`];for(let M of q){let E=M.name.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,32);K.push(`mw_${E};dur=${M.ms.toFixed(1)}`)}D.set("Server-Timing",K.join(", "))}W$(D)};if(O&&typeof O.headers?.set==="function"){if(O.status>=400&&(O.headers.get("content-type")||"").includes("json")&&G5)try{let K=await O.clone().text(),M=JSON.parse(K);if(M&&typeof M==="object"){let E=new Headers(O.headers);return L8(E),new Response(JSON.stringify({...M,request_id:G5}),{status:O.status,statusText:O.statusText,headers:E})}}catch{}try{L8(O.headers)}catch{try{let K=O.clone(),M=new Headers(O.headers);return L8(M),new Response(K.body,{status:O.status,statusText:O.statusText,headers:M})}catch{}}}if(J._compress===!0&&O)try{let{applyCompression:D}=await import(i("app/Middleware/Compress.ts"));return await D(J,O)}catch(D){A.warn(`[router] Compression failed; sending uncompressed response: ${D instanceof Error?D.message:String(D)}`)}return O})}}function X5($){if(!J5.has($))J5.set($,[]);let Z=$.includes(":")?$.substring($.indexOf(":")+1):$,W={middleware(X){let Y=J5.get($);if(Y)Y.push(X);return W},name(X){return v5.set(X,g1(Z)),W},skipCsrf(){return t8.add($),a8.delete($),W},requireCsrf(){return a8.add($),t8.delete($),W},rateLimit(X,Y){if(!Number.isFinite(X)||X<=0)throw Error(`[Router] .rateLimit(): max must be a positive number, got ${String(X)}`);let J=f1(Y);return A$.set($,{max:Math.floor(X),windowSeconds:J}),W}};return W}async function s8($){try{return await Bun.file($).exists()}catch{return!1}}function s1($){if(typeof $!=="string"||$.length===0)throw Error(`[Router] Refusing to resolve handler '${String($)}': empty or non-string`);if($.includes("\x00"))throw Error("[Router] Refusing to resolve handler with null byte");if($.startsWith("/")||/^[A-Za-z]:[\\/]/.test($))throw Error(`[Router] Refusing to resolve absolute handler path '${$}'`);if($.split(/[/\\]/).some((W)=>W===".."))throw Error(`[Router] Refusing to resolve handler path '${$}' (contains '..' segment)`)}function L$($){let Z=H$.get($);if(!Z)Z=import($),H$.set($,Z);return Z}function N$($){let Z=o8.get($);if(!Z)Z=o1($),o8.set($,Z),Z.catch(()=>o8.delete($));return Z}async function o1($){s1($);let Z=$;if(Z=Z.endsWith(".ts")?Z.slice(0,-3):Z,Z.includes("Controller")){let[X,Y="index"]=Z.split("@"),J=w.appPath(`${X}.ts`),G=i(`app/${X}.ts`),z=await s8(J)?J:G;try{let Q=await L$(z);if(!Q.default||typeof Q.default!=="function")throw Error(`Controller ${X} does not export a default class`);let B=new Q.default;if(typeof B[Y]!=="function")throw Error(`Method ${Y} not found in controller ${X}`);return async(U)=>{let j=await B[Y](U);return r8(j,U)}}catch(Q){throw A.error(`[Router] Failed to load controller '${z}':`,Q),Q}}let W;if(Z.includes("storage/framework/orm"))W=Z;else if(Z.includes("OrmAction"))W=w.storagePath(`framework/actions/src/${Z}.ts`);else if(Z.includes("Actions")){let X=w.projectPath(`app/${Z}.ts`),Y=i(`app/${Z}.ts`);W=await s8(X)?X:Y}else{let X=w.appPath(`${Z}.ts`),Y=i(`app/${Z}.ts`);W=await s8(X)?X:Y}try{let Y=(await L$(W)).default;if(!Y)throw Error(`Action '${$}' has no default export`);if(typeof Y.handle!=="function")throw A.error(`[Router] Action '${$}' structure:`,Object.keys(Y)),Error(`Action '${$}' has no handle() method. Got: ${typeof Y.handle}`);let J=Y.skipCsrf===!0||Y.csrf===!1;$9.set($,J);let G=Y.apiResponse===!0;return async(z)=>{if(J)z._skipCsrf=!0;if(G)z._forceJson=!0;try{if(Y.validations){let B=await t1(z,Y.validations);if(!B.valid)return Response.json({error:"Validation failed",errors:B.errors},422)}if(typeof Y.authorize==="function"){let B=await Y.authorize(z);if(B instanceof Response)return B;if(B===!1)return Response.json({error:"Forbidden"},403)}if(typeof Y.before==="function"){let B=await Y.before(z);if(B instanceof Response)return B}let Q=await Y.handle(z);return r8(Q,z)}catch(Q){throw F$(Q,{label:`[Router] action.handle() for '${$}'`}),Q}}}catch(X){throw A.error(`[Router] Failed to import action '${W}':`,X),X}}async function t1($,Z){let W={},X=await a1($,Z);for(let[Y,J]of Object.entries(Z)){let G=X[Y],z;try{z=J.rule.validate(G)}catch{z={valid:!1,errors:[{message:`${Y} validation failed`}]}}if(!z.valid){let Q=[],B=Y.replace(/[-_]+/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").replace(/^./,(j)=>j.toUpperCase()),U=(j)=>j.toLowerCase().startsWith(Y.toLowerCase())||j.includes(B)?j:`${B} ${j}`;if(z.errors&&z.errors.length>0)if(J.message){let j=z.errors[0]?.message??"";Q.push(typeof J.message==="string"?J.message:J.message[Y]||U(j))}else z.errors.forEach((j)=>Q.push(U(j.message)));else Q.push(J.message?typeof J.message==="string"?J.message:`${B} is invalid`:`${B} is invalid`);W[Y]=Q}}return{valid:Object.keys(W).length===0,errors:W}}async function a1($,Z){let W={},X=$.query;if(X)for(let Y in X)W[Y]=X[Y];else new URL($.url).searchParams.forEach((J,G)=>{W[G]=J});if($.params)Object.assign(W,$.params);if($.jsonBody&&typeof $.jsonBody==="object")Object.assign(W,$.jsonBody);else if($.formBody&&typeof $.formBody==="object")Object.assign(W,$.formBody);if(typeof $.allFiles==="function")try{let Y=$.allFiles();for(let J of Object.keys(Y??{}))if(!(J in W))W[J]=Y[J]}catch{}if(!Z)return W;for(let[Y,J]of Object.entries(Z)){let G=W[Y];if(typeof G!=="string")continue;let z=J.rule?.name;if(z==="number"){let Q=Number(G);if(Number.isFinite(Q))W[Y]=Q}else if(z==="boolean"){if(G==="true"||G==="1")W[Y]=!0;else if(G==="false"||G==="0")W[Y]=!1}}return W}function r8($,Z){if($ instanceof Response)return $;if($ instanceof ReadableStream)return new Response($,{headers:{"Content-Type":"application/octet-stream"}});let X=Z._forceJson===!0||a(Z);if($===null||$===void 0)return X?new Response(null,{status:204}):new Response("",{status:200});if(typeof $==="object"){let Y=r1($);if(Y)return Response.json($,{headers:{Link:Y}});return Response.json($)}if(X)return Response.json($);return new Response(String($),{headers:{"Content-Type":"text/plain; charset=utf-8"}})}function r1($){if(!v1($)&&!y1($)&&!k1($))return null;let Z=$,W=[];if(Z.prev_page_url)W.push(`<${Z.prev_page_url}>; rel="prev"`);if(Z.next_page_url)W.push(`<${Z.next_page_url}>; rel="next"`);if(Z.first_page_url)W.push(`<${Z.first_page_url}>; rel="first"`);if(Z.last_page_url)W.push(`<${Z.last_page_url}>; rel="last"`);return W.length>0?W.join(", "):null}function e1($,Z={}){let W={};if(Z.type==="sse")W["Content-Type"]="text/event-stream; charset=utf-8",W["Cache-Control"]="no-cache",W.Connection="keep-alive";else if(Z.type==="ndjson")W["Content-Type"]="application/x-ndjson; charset=utf-8";else W["Content-Type"]=Z.contentType??"application/octet-stream";let X=$ instanceof ReadableStream?$:new ReadableStream({async start(J){try{for await(let G of $)J.enqueue(typeof G==="string"?new TextEncoder().encode(G):G);J.close()}catch(G){J.error(G)}}}),Y=new Headers(W);if(Z.headers)new Headers(Z.headers).forEach((G,z)=>Y.set(z,G));return new Response(X,{status:Z.status??200,headers:Y})}function b($){let Z=$._allInputCache;if(Z)return Z;let W={},X=$.query;if(X)for(let Y in X)W[Y]=X[Y];if($.jsonBody&&typeof $.jsonBody==="object")Object.assign(W,$.jsonBody);if($.formBody&&typeof $.formBody==="object")Object.assign(W,$.formBody);if($.params&&typeof $.params==="object")Object.assign(W,$.params);return $._allInputCache=W,W}function C$($){w1($,$.params||{});let Z=$.query;if(!Z){let W=new URL($.url);Z={},W.searchParams.forEach((X,Y)=>{Z[Y]=X}),$.query=Z}return Object.assign($,$6),$}function Z6($,Z=!1){if(typeof $==="string"){let X=$;return async(Y)=>{try{if(!Z)await x$(Y),Y=C$(Y);return await(await N$(X))(Y)}catch(J){F$(J,{label:`[Router] ${X}`});let G=J?.statusCode??J?.status,z=typeof G==="number"&&Number.isInteger(G)&&G>=400&&G<600?G:void 0;return await l(J instanceof Error?J:Error(String(J)),Y,{handlerPath:X,status:z})}}}let W=$;return async(X)=>{let Y=await W(X);return r8(Y,X)}}async function x$($){if($._bodyParsed)return;$._bodyParsed=!0;let Z=$.headers.get("content-type")||"";try{if(m5.test(Z)){let X=await $.clone().text();if($._rawBody=X,X.length===0)$.jsonBody={};else try{let Y=JSON.parse(X);$.jsonBody=Y&&typeof Y==="object"?Y:{}}catch(Y){let J=Y instanceof Error?Y.message:"Invalid JSON",{HttpError:G}=await import("@stacksjs/error-handling");throw new G(400,`Invalid JSON body: ${J}`)}}else if(Z.includes("application/x-www-form-urlencoded")){let W=await $.clone().text(),X=new URLSearchParams(W),Y={};X.forEach((J,G)=>{Y[G]=J}),$.formBody=Y}else if(Z.includes("multipart/form-data")){let W=await $.clone().formData(),X={},Y={};W.forEach((J,G)=>{if(J instanceof File)if(Y[G])if(Array.isArray(Y[G]))Y[G].push(J);else Y[G]=[Y[G],J];else Y[G]=J;else X[G]=J}),$.formBody=X,$.files=Y}}catch(W){if(typeof(W?.status??W?.statusCode)==="number")throw W;A.debug("[stacks-router] Body parsing failed:",W)}}function E$($={}){let Z=new P1({verbose:$.verbose??!1}),W="",X=[],Y=!1;function J(z,Q,B){let U=W+Q,j=`${z}:${U}`;if(A.debug(`[router] ${z} ${U} \u2192 ${typeof B==="string"?B:"function"}`),X.length>0)J5.set(j,[...X]);if(Y)K$.add(j);if(typeof B==="string")Z9.set(j,B);return{fullPath:U,routeKey:j}}let G={bunRouter:Z,get routes(){return Z.routes},get(z,Q){let{fullPath:B,routeKey:U}=J("GET",z,Q);return Z.get(B,W5(U,Q)),X5(U)},post(z,Q){let{fullPath:B,routeKey:U}=J("POST",z,Q);return Z.post(B,W5(U,Q)),X5(U)},put(z,Q){let{fullPath:B,routeKey:U}=J("PUT",z,Q);return Z.put(B,W5(U,Q)),X5(U)},patch(z,Q){let{fullPath:B,routeKey:U}=J("PATCH",z,Q);return Z.patch(B,W5(U,Q)),X5(U)},delete(z,Q){let{fullPath:B,routeKey:U}=J("DELETE",z,Q);return Z.delete(B,W5(U,Q)),X5(U)},options(z,Q){let{fullPath:B,routeKey:U}=J("OPTIONS",z,Q);return Z.options(B,W5(U,Q)),X5(U)},group(z,Q){let B=W,U=[...X],j=Y;if(z.prefix)W=B+z.prefix;let H=z.middleware?Array.isArray(z.middleware)?z.middleware:[z.middleware]:void 0;if(H)X=[...X,...H];if(z.apiResponse===!0)Y=!0;A.debug(`[router] Entering group: prefix=${z.prefix||"/"} middleware=[${H?.join(", ")||""}]${Y?" apiResponse=true":""}`);let L=Q();if(L instanceof Promise)return L.then(()=>{return W=B,X=U,Y=j,G}).catch((F)=>{throw W=B,X=U,Y=j,F});return W=B,X=U,Y=j,G},resource(z,Q,B){let U=["index","store","show","update","destroy"],j=B?.only?U.filter((F)=>B.only.includes(F)):B?.except?U.filter((F)=>!B.except.includes(F)):U,H=Q.replace(/Action$/,"");A.debug(`[router] Resource: /${z} \u2192 ${Q} [${j.join(", ")}]`);let L=()=>{for(let F of j)switch(F){case"index":G.get(`/${z}`,`${H}IndexAction`);break;case"store":G.post(`/${z}`,`${H}StoreAction`);break;case"show":G.get(`/${z}/:id`,`${H}ShowAction`);break;case"update":G.put(`/${z}/:id`,`${H}UpdateAction`);break;case"destroy":G.delete(`/${z}/:id`,`${H}DestroyAction`);break}};if(B?.middleware)G.group({middleware:B.middleware},L);else L();return G},match(z,Q,B){A.debug(`[router] Match: [${z.join(", ")}] ${Q} \u2192 ${typeof B==="string"?B:"function"}`);for(let U of z){let j=U.toUpperCase(),{fullPath:H,routeKey:L}=J(j,Q,B),F=W5(L,B);switch(j){case"GET":Z.get(H,F);break;case"POST":Z.post(H,F);break;case"PUT":Z.put(H,F);break;case"PATCH":Z.patch(H,F);break;case"DELETE":Z.delete(H,F);break;case"OPTIONS":Z.options(H,F);break}}return X5(`${z[0]}:${W}${Q}`)},health(){return Z.get("/api/health",async()=>{let z={},Q=async(j,H)=>{let L=Date.now();try{let F=new AbortController,I=setTimeout(()=>F.abort(),1500);await Promise.race([H(),new Promise((f,q)=>F.signal.addEventListener("abort",()=>q(Error("timeout"))))]),clearTimeout(I),z[j]={ok:!0,ms:Date.now()-L}}catch(F){z[j]={ok:!1,ms:Date.now()-L,message:F instanceof Error?F.message:String(F)}}};await Promise.all([Q("database",async()=>{let{db:j}=await import("@stacksjs/database");await j.unsafe?.("SELECT 1")}),Q("cache",async()=>{let{cache:j}=await import("@stacksjs/cache"),H=`__health__:${Date.now()}`;await j.set(H,1,5),await j.del(H)})]);let B=Object.values(z).every((j)=>j.ok),U={status:B?"healthy":"degraded",checks:z,timestamp:Date.now()};return Response.json(U,B?200:503)}),Z.get("/__routes",(z)=>{if(!Q$(z))return Response.json({error:"disabled"},404);return Response.json(_$())}),Z.get("/__storage/:path",async(z)=>{let Q=new URL(z.url),B=Q.searchParams.get("token"),U=z.params,j=U?.path?decodeURIComponent(U.path):decodeURIComponent(Q.pathname.replace(/^\/__storage\//,""));if(!B||typeof j!=="string"||j.length===0)return new Response("Forbidden",{status:403});let{verifySignedStorageToken:H,Storage:L}=await import("@stacksjs/storage");if(!H(B,j).valid)return new Response("Forbidden",{status:403});try{let I=L.disk();if(!await I.fileExists(j))return new Response("Not Found",{status:404});let q=await I.readToBuffer(j),O=await I.mimeType(j).catch(()=>"application/octet-stream");return new Response(q,{status:200,headers:{"Content-Type":O,"Cache-Control":"private, max-age=60","X-Content-Type-Options":"nosniff"}})}catch(I){return A.error("[storage] signed-url fetch failed:",I),new Response("Internal Error",{status:500})}}),Z.get("/__openapi.json",async(z)=>{if(!Q$(z))return Response.json({error:"disabled"},404);try{let{generateOpenApi:Q}=await import("@stacksjs/api"),B=await Q();return Response.json(B)}catch(Q){return Response.json({error:"OpenAPI generation failed",message:Q instanceof Error?Q.message:String(Q)},500)}}),G},use(z){let Q=c1(z);return Z.globalMiddleware.push(Q),G},async serve(z={}){return Z.serve(z)},async handleRequest(z){return Z.handleRequest(z)},getAllowedMethods(z,Q){return Z.getAllowedMethods(z,Q)},async register(z,Q){A.debug(`[router] Register: ${z} prefix=${Q?.prefix||"none"}`);let B=async()=>{await import(z)};if(Q?.prefix||Q?.middleware)await G.group({prefix:Q.prefix,middleware:Q.middleware},B);else await B();return G},async importRoutes(){A.debug("[router] Loading user routes from registry...");try{let{loadRoutes:B}=await Promise.resolve().then(() => (i8(),G$)),{appPath:U}=await import("@stacksjs/path"),j=(await import(U("Routes.ts"))).default;await B(j)}catch(B){throw A.error("Failed to load route registry:",B),B}A.debug("[router] Loading ORM routes...");let z=[w.frameworkPath("orm/routes.ts"),w.frameworkPath("core/orm/routes.ts")],Q=!1;for(let B of z)try{if(await Bun.file(B).exists()){await import(B),Q=!0;break}}catch(U){A.warn(`[router] ORM routes candidate failed to load, falling back to next: ${B}
|
|
50
|
-
`,U)}if(!Q)A.warn("[router] No ORM routes candidate loaded \u2014 model useApi endpoints are unavailable.");A.debug("[router] Loading discovered package routes...");try{await G.loadDiscoveredRoutes()}catch(B){A.debug("Package route discovery skipped:",B)}await S$()},async loadDiscoveredRoutes(){try{let z=w.storagePath("framework/discovered-packages.json"),Q=Bun.file(z);if(!await Q.exists())return;let U=(await Q.json())?.packages;if(!U)return;let j=w.projectPath("pantry");for(let[H,L]of Object.entries(U)){let F=L?.routes;if(!F)continue;let I=Array.isArray(F)?F:[F],f=`${j}/${H}`;for(let q of I){A.debug(`[router] Discovered route: ${H} \u2192 ${q}`);let O=q.startsWith("/")?q:`${f}/${q}`,G5=L?.routePrefix,f5=L?.routeMiddleware;try{await G.register(O,{prefix:G5,middleware:f5})}catch(g5){A.warn(`Failed to load routes from package '${H}': ${g5}`)}}}}catch{}}};return G}async function W6($,Z){if(!U8)A.debug("[router] Loading routes for first time..."),U8=D5.importRoutes().catch((X)=>{throw U8=null,X});await U8;let W=await D5.handleRequest($);if(W.status===404&&W.headers.get("content-type")?.includes("json"))try{let X=await W.clone().json();if(X?.message==="Not Found"||X?.error==="Not Found"){let J=new URL($.url),G={...X,path:J.pathname,method:$.method};return new Response(JSON.stringify(G),{status:404,headers:W.headers})}}catch{}return W}async function X6($={}){return D5.serve($)}var P5,t8,a8,A$,V$=5000,$9,Z9,B$,v5,I$=10,U$,Y5,k5=null,u1,j$,J5,K$,H$,o8,$6,D5,U8=null;var O5=u(()=>{N5();p5();n5();n8();X$();t8=new Set,a8=new Set,A$=new Map;$9=new e8(V$),Z9=new e8(V$),B$=new Set(["POST","PUT","PATCH","DELETE"]),v5=new Map;U$=new Set;Y5=new Map;u1=/[-_\s]+/,j$=new Map;J5=new Map,K$=new Set;H$=new Map;o8=new Map;$6={get($,Z){let X=b(this)[$];return X!==void 0?X:Z},input($,Z){let X=b(this)[$];return X!==void 0?X:Z},all(){return b(this)},only($){let Z=b(this),W={};for(let X of $)if(X in Z)W[X]=Z[X];return W},except($){let W={...b(this)};for(let X of $)delete W[X];return W},has($){let Z=b(this);if(Array.isArray($))return $.every((W)=>(W in Z)&&Z[W]!==void 0);return $ in Z&&Z[$]!==void 0},hasAny($){let Z=b(this);return $.some((W)=>(W in Z)&&Z[W]!==void 0)},filled($){let Z=b(this),W=(X)=>{let Y=Z[X];return Y!==void 0&&Y!==null&&Y!==""&&!(Array.isArray(Y)&&Y.length===0)};if(Array.isArray($))return $.every(W);return W($)},missing($){let Z=b(this);if(Array.isArray($))return $.every((W)=>!(W in Z)||Z[W]===void 0);return!($ in Z)||Z[$]===void 0},string($,Z=""){let X=b(this)[$];return X!==void 0&&X!==null?String(X):Z},integer($,Z=0){let X=b(this)[$];if(X===void 0||X===null||X==="")return Z;if(typeof X==="number")return Number.isFinite(X)?Math.trunc(X):Z;let Y=String(X).trim();if(!/^-?\d+$/.test(Y))return Z;let J=Number.parseInt(Y,10);return Number.isFinite(J)?J:Z},float($,Z=0){let X=b(this)[$];if(X===void 0||X===null||X==="")return Z;if(typeof X==="number")return Number.isFinite(X)?X:Z;let Y=String(X).trim();if(!/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(Y))return Z;let J=Number.parseFloat(Y);return Number.isFinite(J)?J:Z},boolean($,Z=!1){let X=b(this)[$];if(X===void 0||X===null)return Z;if(typeof X==="boolean")return X;if(X==="true"||X==="1"||X===1)return!0;if(X==="false"||X==="0"||X===0)return!1;return Z},array($){let W=b(this)[$];if(Array.isArray(W))return W;return W!==void 0&&W!==null?[W]:[]},file($){let W=(this.files||{})[$];if(!W)return null;let X=Array.isArray(W)?W[0]:W;return X?new Q8(X):null},getFiles($){let W=(this.files||{})[$];if(!W)return[];return(Array.isArray(W)?W:[W]).map((Y)=>new Q8(Y))},hasFile($){let Z=this.files||{};return $ in Z&&Z[$]!==void 0},allFiles(){let $=this.files||{},Z={};for(let[W,X]of Object.entries($))if(Array.isArray(X))Z[W]=X.map((Y)=>new Q8(Y));else Z[W]=new Q8(X);return Z},async user(){return this._authenticatedUser},async userToken(){return this._currentAccessToken},async tokenCan($){if(typeof $!=="string"||$.length===0)return!1;let Z=this._currentAccessToken;if(!Z||typeof Z!=="object")return!1;if(!Array.isArray(Z.abilities))return!1;if(Z.abilities.includes("*"))return!0;return Z.abilities.includes($)},async tokenCant($){return!await this.tokenCan($)},async can($,...Z){if(typeof $!=="string"||$.length===0)return!1;let{Gate:W}=await import("@stacksjs/auth"),X=this._authenticatedUser??null;return W.allows($,X,...Z)},async cannot($,...Z){return!await this.can($,...Z)},async authorize($,...Z){let{Gate:W}=await import("@stacksjs/auth"),X=this._authenticatedUser??null;await W.authorize($,X,...Z)}};D5=E$()});O5();N5();i8();n5();O5();p5();n8();export*from"@stacksjs/bun-router";class g extends Error{reason;constructor($,Z,W){let X=W?` in ${W}`:"";super(`[router] Refusing to use ${JSON.stringify(Z)} as a path parameter${X} \u2014 ${$}`);this.name="PathParamError",this.reason=$}}var Y6=/[\u0000-\u001F\u007F]/;function R$($,Z={}){if(typeof $!=="string")throw new g("not-string",$,Z.context);if($.length===0)throw new g("empty",$,Z.context);let W=Z.maxLength??255;if($.length>W)throw new g("too-long",$,Z.context);if($.includes("\x00"))throw new g("null-byte",$,Z.context);if(Y6.test($))throw new g("control-char",$,Z.context);if($.startsWith("/")||/^[A-Z]:[\\/]/i.test($))throw new g("absolute-path",$,Z.context);if(/(^|[\\/])\.\.([\\/]|$)/.test($))throw new g("traversal",$,Z.context);if(!Z.allowSlashes&&/[\\/]/.test($))throw new g("traversal",$,Z.context);return $}function J6($,Z={}){try{return R$($,Z)}catch{return null}}O5();O5();import{timingSafeEqual as G6}from"crypto";import{Buffer as q$}from"buffer";import j8 from"process";var Y9="signature",X9="expires";function w$(){let $=j8.env.APP_KEY||j8.env.STACKS_SIGNED_URL_SECRET;if(!$||$.length<16)throw Error("[router] signed URLs require APP_KEY (\u2265 16 chars) or STACKS_SIGNED_URL_SECRET. "+"Run `./buddy key:generate` or set the env var.");return $}function P$($,Z){return new Bun.CryptoHasher("sha256",Z).update($).digest("hex")}function z6($,Z){let W=q$.from($.toLowerCase(),"hex"),X=q$.from(Z.toLowerCase(),"hex");if(W.length!==X.length)return!1;return G6(W,X)}function Q6($){let Z=new URL($.toString());return Z.searchParams.delete(Y9),Z}function k$($){let Z=Q6($);return Z.searchParams.sort(),Z.toString()}function v$($,Z={}){let W=w$(),X=$.startsWith("http")?new URL($):new URL($.startsWith("/")?$:`/${$}`,j8.env.APP_URL||"https://localhost");if(Z.ttl!==void 0&&Z.expiresAt!==void 0)B6("dual-expiry","[router] signUrl: both `ttl` and `expiresAt` provided \u2014 using `ttl`.");if(Z.ttl!==void 0)X.searchParams.set(X9,String(Math.floor(Date.now()/1000)+Z.ttl));else if(Z.expiresAt!==void 0)X.searchParams.set(X9,String(Math.floor(Z.expiresAt)));let Y=k$(X);return X.searchParams.set(Y9,P$(Y,W)),X.toString()}var b$=new Set;function B6($,Z){if(b$.has($))return;b$.add($),console.warn(Z)}function U6($,Z={},W={}){return v$(W9($,Z),W)}function y$($){let Z=typeof $==="string"?new URL($,j8.env.APP_URL||"https://localhost"):$,W=Z.searchParams.get(Y9);if(!W)return{valid:!1,reason:"missing-signature"};let X=Z.searchParams.get(X9);if(X!==null){let Y=Number.parseInt(X,10);if(!Number.isFinite(Y)||Date.now()/1000>Y)return{valid:!1,reason:"expired"}}try{let Y=P$(k$(Z),w$());return z6(W,Y)?{valid:!0}:{valid:!1,reason:"invalid-signature"}}catch{return{valid:!1,reason:"invalid-signature"}}}async function j6($){let Z=y$($.url);if(Z.valid)return;let W=Z.reason==="expired"?410:401;throw Response.json({error:Z.reason},{status:W})}import{decrypt as H6,encrypt as L6}from"@stacksjs/security";class H8{inner;opts;constructor($,Z={}){this.inner=$;this.opts=Z}async set($,Z,W){let X=await this.wrap($,Z);await this.inner.set($,X,W)}async touch($,Z,W){let X=await this.wrap($,Z);await this.inner.touch($,X,W)}async get($){let Z=await this.inner.get($);if(!Z)return null;return this.unwrap(Z)}destroy($){return this.inner.destroy($)}async all(){let $=await this.inner.all(),Z={};for(let[W,X]of Object.entries($)){let Y=await this.unwrap(X);if(Y)Z[W]=Y}return Z}length(){return this.inner.length()}clear(){return this.inner.clear()}async wrap($,Z){let{id:W,...X}=Z,Y=await L6(JSON.stringify(X),this.opts.appKey);return{_enc:!0,id:W??$,data:Y}}async unwrap($){if(!$||typeof $!=="object")return null;let Z=$;if(Z._enc===!0&&typeof Z.data==="string")try{let W=await H6(Z.data,this.opts.appKey),X=JSON.parse(W);if(Z.id!==void 0)X.id=Z.id;return X}catch{return null}return Z}}import y5 from"process";import{createSessionStore as F6}from"@stacksjs/bun-router";import{DatabaseSessionStore as _6,FileSessionStore as I6,MemorySessionStore as D6,RedisSessionStore as O6,createSessionStore as K6}from"@stacksjs/bun-router";function A6($){let Z=F6($);if(!V6($.encrypt))return Z;let X=$.appKey??y5.env.APP_KEY;if(!X||X.length<16)throw Error("[session] createStacksSessionStore: encryption requested but APP_KEY is missing or too short "+"(need \u226516 chars). Either set APP_KEY in env, pass `appKey` in config, or set `encrypt: false` to opt out.");return new H8(Z,{appKey:X})}function V6($){if($===!0)return!0;if($===!1)return!1;return(y5.env.APP_ENV??y5.env.NODE_ENV??"").toLowerCase()==="production"}import("@stacksjs/database").then(({setQueryTracker:$})=>{if(typeof $==="function"){let{trackQuery:Z}=(n5(),p$(_9));$(Z)}}).catch(()=>{});export{i$ as withTraceId,j6 as verifySignedUrlMiddleware,y$ as verifySignedUrl,W9 as url,L9 as trackQuery,e1 as stream,U6 as signedUrl,v$ as signUrl,t$ as setCurrentRequest,W6 as serverResponse,X6 as serve,R$ as sanitizePathParam,J6 as safePathParam,_8 as runWithRequest,m1 as routeParams,D5 as route,a$ as request,D1 as rateLimitStatus,l8 as rateLimit,J$ as loadRoutes,_$ as listRegisteredRoutes,a as isApiRequest,i1 as installMiddlewareHotReload,n$ as getTraceId,F9 as getQueryShapeCounts,t as getCurrentRequest,M$ as findUnresolvableRouteMiddleware,A9 as createValidationErrorResponse,A6 as createStacksSessionStore,E$ as createStacksRouter,K6 as createSessionStore,V9 as createNotFoundResponse,j5 as createMiddlewareErrorResponse,l as createErrorResponse,l5 as clearTrackedQueries,O1 as clearRateLimit,O$ as clearMiddlewareCache,o$ as cacheRequestQuery,S$ as assertRouteMiddlewareResolvable,O6 as RedisSessionStore,g as PathParamError,h5 as Middleware,D6 as MemorySessionStore,m5 as JSON_CONTENT_TYPE,I6 as FileSessionStore,H8 as EncryptedSessionStore,_6 as DatabaseSessionStore};
|
|
49
|
+
- Draft Mode: ${this.draftMode?"enabled":"disabled"}`)}}defaultKeyGenerator($){let Z=$.headers.get("x-forwarded-for");if(Z)return Z.split(",")[0].trim();let W=$.headers.get("x-client-ip");if(W)return W;let X=$.headers.get("x-real-ip");if(X)return X;return $.socket?.remoteAddress||"127.0.0.1"}async check($){try{if(this.skipFn&&await this.skipFn($))return this.createAllowedResult();if(this.maxRequests===0)return{allowed:!1,current:1,limit:0,remaining:this.windowMs,resetTime:Date.now()+this.windowMs};let Z=await this.keyGenerator($);if(this.algorithm==="sliding-window"&&this.storage.getSlidingWindowCount)return this.checkSlidingWindow(Z);else if(this.algorithm==="token-bucket")return this.checkTokenBucket(Z);else return this.checkFixedWindow(Z)}catch(Z){if(this.skipFailedRequests)return this.createAllowedResult();throw Z}}async checkFixedWindow($){let{count:Z,resetTime:W}=await this.storage.increment($,this.windowMs),X=Math.max(0,W-Date.now());return{allowed:this.draftMode?!0:Z<=this.maxRequests,current:Z,limit:this.maxRequests,remaining:X,resetTime:W}}async checkSlidingWindow($){if(!this.storage.getSlidingWindowCount)return this.checkFixedWindow($);await this.storage.increment($,this.windowMs);let Z=await this.storage.getSlidingWindowCount($,this.windowMs),X=Date.now()+this.windowMs;return{allowed:this.draftMode?!0:Z<=this.maxRequests,current:Z,limit:this.maxRequests,remaining:this.windowMs,resetTime:X}}async checkTokenBucket($){if(!this.tokenBucketOptions)return this.checkFixedWindow($);let Z=Date.now(),W=this.tokenBuckets.get($);if(!W)W={tokens:this.tokenBucketOptions.capacity,lastRefill:Z},this.tokenBuckets.set($,W);let Y=(Z-W.lastRefill)*this.tokenBucketOptions.refillRate;if(Y>0)W.tokens=Math.min(W.tokens+Y,this.tokenBucketOptions.capacity),W.lastRefill=Z;let J=this.draftMode?!0:W.tokens>=1;if(J&&!this.draftMode)W.tokens-=1;let G=W.tokens>=this.tokenBucketOptions.capacity?this.windowMs:Math.ceil(1/this.tokenBucketOptions.refillRate);return{allowed:J,current:this.tokenBucketOptions.capacity-Math.floor(W.tokens),limit:this.tokenBucketOptions.capacity,remaining:G,resetTime:Z+G}}createAllowedResult(){return{allowed:!0,current:0,limit:this.maxRequests,remaining:this.windowMs,resetTime:Date.now()+this.windowMs}}async consume($){if(this.algorithm==="sliding-window"&&this.storage.getSlidingWindowCount)return this.checkSlidingWindow($);else if(this.algorithm==="token-bucket")return this.checkTokenBucket($);else return this.checkFixedWindow($)}async peek($){if(typeof this.storage.getCount!=="function")return null;let Z=await this.storage.getCount($),W=Date.now();return{allowed:this.draftMode?!0:Z<this.maxRequests,current:Z,limit:this.maxRequests,remaining:this.windowMs,resetTime:W+this.windowMs}}async enforce($){let Z=await this.consume($);if(!Z.allowed)throw new J8(`Rate limit exceeded for '${$}'`,Z);return Z}async reset($){if(await this.storage.reset($),this.algorithm==="token-bucket")this.tokenBuckets.delete($)}async resetAll(){if(this.algorithm==="token-bucket")this.tokenBuckets.clear();if(this.storage.cleanExpired)this.storage.cleanExpired()}getHeaders($){let Z={};if(this.standardHeaders)Z["RateLimit-Limit"]=this.maxRequests.toString(),Z["RateLimit-Remaining"]=Math.max(0,this.maxRequests-$.current).toString(),Z["RateLimit-Reset"]=Math.ceil($.resetTime/1000).toString();if(this.legacyHeaders){if(Z["X-RateLimit-Limit"]=this.maxRequests.toString(),Z["X-RateLimit-Remaining"]=Math.max(0,this.maxRequests-$.current).toString(),Z["X-RateLimit-Reset"]=Math.ceil($.resetTime/1000).toString(),!$.allowed)Z["Retry-After"]=Math.ceil($.remaining/1000).toString()}return Z}middleware(){return async($)=>{let Z=await this.check($);if(!Z.allowed){if(this.handler)return this.handler($,Z);return new Response("Rate limit exceeded",{status:429,headers:this.getHeaders(Z)})}return null}}dispose(){if(this.storage.dispose)this.storage.dispose();this.tokenBuckets.clear()}}function e9($){let Z=$,W=Z._authenticatedUser?.id;if(W!==void 0)return`user:${String(W)}`;let X=Z._currentAccessToken?.id;if(X!==void 0)return`token:${String(X)}`;let Y=$.headers.get("authorization");if(Y?.startsWith("Bearer "))return`bearer:${Y.slice(7,39)}`;let J=$.headers.get("x-forwarded-for");if(J)return`ip:${J.split(",")[0]?.trim()??"unknown"}`;let G=$.headers.get("x-real-ip");if(G)return`ip:${G}`;return"anon"}var EZ,RZ=($)=>$,bZ=($,Z)=>{for(var W in Z)EZ($,W,{get:Z[W],enumerable:!0,configurable:!0,set:qZ.bind(Z,W)})},d=($,Z)=>()=>($&&(Z=$($=0)),Z),wZ,V5,b5,v9,w5,R9,S8,E5,gZ,N,_,hZ,q9,mZ,b9,pZ,cZ,N8,dZ,w9,P9,uZ,C8,lZ,nZ,iZ,sZ,oZ,r5,f9,tZ,aZ,rZ="0.15.9",eZ=()=>{},P,$8,R5,E8,R8,Z8,q8,b8,q5,w8,P8,n,_5,m9,u9,h8,l9,n9,i9,v,c,o9,t9,L1,A1=()=>{},a9,r9,V1,k,J8;var $$=u(()=>{EZ=Object.defineProperty;wZ=import.meta.require;w5=d(()=>{V5=new y8,b5=new f8,v9={createKey:PZ,isEquivalent:kZ,estimateMemoryUsage:vZ}});aZ=d(()=>{R9=e5.env.CLARITY_LOG_DIR||BZ(yZ(),"logs"),S8={level:"info",defaultName:"clarity",timestamp:!0,colors:!0,format:"text",maxLogSize:10485760,logDatePattern:"YYYY-MM-DD",logDirectory:R9,rotation:{frequency:"daily",maxSize:10485760,maxFiles:5,compress:!1,rotateHour:0,rotateMinute:0,rotateDayOfWeek:0,rotateDayOfMonth:1,encrypt:!1},verbose:!1,writeToFile:!1},E5={...S8},gZ=(async()=>{try{let{loadConfig:$}=await Promise.resolve().then(()=>(r9(),a9)),Z=await $({name:"clarity",alias:"logging",defaultConfig:S8,cwd:e5.cwd()});if(Z)Object.assign(E5,Z)}catch{}return E5})(),N={red:($)=>`\x1B[31m${$}\x1B[0m`,green:($)=>`\x1B[32m${$}\x1B[0m`,yellow:($)=>`\x1B[33m${$}\x1B[0m`,blue:($)=>`\x1B[34m${$}\x1B[0m`,magenta:($)=>`\x1B[35m${$}\x1B[0m`,cyan:($)=>`\x1B[36m${$}\x1B[0m`,white:($)=>`\x1B[37m${$}\x1B[0m`,gray:($)=>`\x1B[90m${$}\x1B[0m`,bgRed:($)=>`\x1B[41m${$}\x1B[0m`,bgYellow:($)=>`\x1B[43m${$}\x1B[0m`,bgGray:($)=>`\x1B[100m${$}\x1B[0m`,bold:($)=>`\x1B[1m${$}\x1B[0m`,dim:($)=>`\x1B[2m${$}\x1B[0m`,italic:($)=>`\x1B[3m${$}\x1B[0m`,underline:($)=>`\x1B[4m${$}\x1B[0m`,strikethrough:($)=>`\x1B[9m${$}\x1B[0m`,reset:"\x1B[0m"},_=N,hZ=N.red,q9=N.green,mZ=N.yellow,b9=N.blue,pZ=N.magenta,cZ=N.cyan,N8=N.white,dZ=N.gray,w9=N.bgRed,P9=N.bgYellow,uZ=N.bgGray,C8=N.bold,lZ=N.dim,nZ=N.italic,iZ=N.underline,sZ=N.strikethrough,oZ=N.reset,r5={activationLevel:"error",bufferSize:50,flushOnDeactivation:!0,stopBuffering:!1},f9={debug:"\uD83D\uDD0D",info:b9("\u2139"),success:q9("\u2713"),warning:P9(N8(C8(" WARN "))),error:w9(N8(C8(" ERROR ")))},tZ=new W8("stacks")});_5=d(()=>{P=class extends Error{timestamp;context;constructor(Z,W={}){super(Z);if(this.name=this.constructor.name,this.timestamp=new Date,this.context=W,Error.captureStackTrace)Error.captureStackTrace(this,this.constructor)}toJSON(){return{name:this.name,code:this.code,message:this.message,timestamp:this.timestamp.toISOString(),context:this.context,stack:this.stack}}toString(){let Z=Object.keys(this.context).length>0?` (${Object.entries(this.context).map(([W,X])=>`${W}: ${X}`).join(", ")})`:"";return`${this.name} [${this.code}]: ${this.message}${Z}`}},$8=class extends P{code="CONFIG_NOT_FOUND";constructor(Z,W,X){let Y=X===void 0?[]:Array.isArray(X)?X.filter(Boolean):[X],J="";if(Y.length===1)J=` or alias "${Y[0]}"`;else if(Y.length>1)J=` or aliases ${Y.map((G)=>`"${G}"`).join(", ")}`;super(`Configuration "${Z}"${J} not found`,{configName:Z,alias:X,searchPaths:W,searchPathCount:W.length})}},R5=class extends P{code="CONFIG_LOAD_ERROR";constructor(Z,W,X){super(`Failed to load configuration from "${Z}": ${W.message}`,{configPath:Z,configName:X,originalError:W.name,originalMessage:W.message});this.cause=W}},E8=class extends P{code="CONFIG_VALIDATION_ERROR";constructor(Z,W,X){super(`Configuration validation failed for "${Z}"`,{configPath:Z,configName:X,validationErrors:W,errorCount:W.length})}},R8=class extends P{code="CONFIG_MERGE_ERROR";constructor(Z,W,X,Y){super(`Failed to merge configuration from "${Z}" with "${W}": ${X.message}`,{sourcePath:Z,targetPath:W,configName:Y,originalError:X.name,originalMessage:X.message});this.cause=X}},Z8=class extends P{code="ENV_VAR_ERROR";constructor(Z,W,X,Y){super(`Failed to parse environment variable "${Z}" with value "${W}" as ${X}`,{envKey:Z,envValue:W,expectedType:X,configName:Y})}},q8=class extends P{code="FILE_SYSTEM_ERROR";constructor(Z,W,X){super(`File system ${Z} failed for "${W}": ${X.message}`,{operation:Z,path:W,originalError:X.name,originalMessage:X.message});this.cause=X}},b8=class extends P{code="TYPE_GENERATION_ERROR";constructor(Z,W,X){super(`Failed to generate types from "${Z}" to "${W}": ${X.message}`,{configDir:Z,outputPath:W,originalError:X.name,originalMessage:X.message});this.cause=X}},q5=class extends P{code="SCHEMA_VALIDATION_ERROR";constructor(Z,W,X){super(`Schema validation failed${X?` for config "${X}"`:""}`,{schemaPath:Z,configName:X,validationErrors:W,errorCount:W.length})}},w8=class extends P{code="BROWSER_CONFIG_ERROR";constructor(Z,W,X,Y){super(`Failed to fetch configuration from "${Z}": ${W} ${X}`,{endpoint:Z,status:W,statusText:X,configName:Y})}},P8=class extends P{code="PLUGIN_ERROR";constructor(Z,W,X){super(`Plugin "${Z}" failed during ${W}: ${X.message}`,{pluginName:Z,operation:W,originalError:X.name,originalMessage:X.message});this.cause=X}},n={configNotFound($,Z,W){return new $8($,Z,W)},configLoad($,Z,W){return new R5($,Z,W)},configValidation($,Z,W){return new E8($,Z,W)},configMerge($,Z,W,X){return new R8($,Z,W,X)},envVar($,Z,W,X){return new Z8($,Z,W,X)},fileSystem($,Z,W){return new q8($,Z,W)},typeGeneration($,Z,W){return new b8($,Z,W)},schemaValidation($,Z,W){return new q5($,Z,W)},browserConfig($,Z,W,X){return new w8($,Z,W,X)},plugin($,Z,W){return new P8($,Z,W)}}});m9=d(()=>{w5(),_5()});h8=d(()=>{u9={replace:"replace",concat:"concat",smart:"smart"}});l9=d(()=>{w5(),_5(),h8()});i9=d(()=>{w5(),_5(),n9=/^https?:\/\//});L1=d(()=>{aZ(),eZ(),w5(),_5(),m9(),l9(),i9(),h8(),v=new W8("bunfig",{showTags:!0}),c=new p8,o9=R($5.cwd(),"config"),t9=R($5.cwd(),"src/generated")});a9={};bZ(a9,{withErrorRecovery:()=>g9,tryLoadConfig:()=>U1,loadConfigWithResult:()=>Q1,loadConfig:()=>s9,isRetryableError:()=>Z1,isConfigNotFoundError:()=>$1,isBunfigError:()=>h9,globalPerformanceMonitor:()=>b5,globalCache:()=>V5,getEnvOrDefault:()=>W1,generateConfigTypes:()=>j1,defaultGeneratedDir:()=>t9,defaultConfigDir:()=>o9,deepMergeWithArrayStrategy:()=>g8,deepMerge:()=>p9,createLibraryConfig:()=>H1,config:()=>B1,bunfigPlugin:()=>F1,applyEnvVarsToConfig:()=>x5,TypeGenerationError:()=>b8,SchemaValidationError:()=>q5,PluginError:()=>P8,PerformanceMonitor:()=>f8,FileSystemError:()=>q8,ErrorFactory:()=>n,EnvVarError:()=>Z8,EnvProcessor:()=>X8,ConfigValidator:()=>m8,ConfigValidationError:()=>E8,ConfigNotFoundError:()=>$8,ConfigMergeError:()=>R8,ConfigLoader:()=>p8,ConfigLoadError:()=>R5,ConfigFileLoader:()=>Y8,ConfigCache:()=>y8,CacheUtils:()=>v9,BunfigError:()=>P,BrowserConfigError:()=>w8,ArrayMergeStrategies:()=>u9});r9=d(()=>{L1(),_5(),w5(),_5(),A1(),m9(),l9(),i9(),h8()});r9();V1={verbose:!1,storage:"memory",algorithm:"fixed-window",windowMs:60000,maxRequests:100,standardHeaders:!0,legacyHeaders:!0,draftMode:!1,redisKeyPrefix:"ratelimit:",memoryStorage:{enableAutoCleanup:!0,cleanupIntervalMs:60000},redis:{url:"redis://localhost:6379",enableSlidingWindow:!1}},k=V1;J8=class J8 extends Error{name="RateLimitError";retryAfter;result;constructor($,Z){super($);this.result=Z,this.retryAfter=Math.max(1,Math.ceil(Z.remaining/1000))}toHeaders(){return{"Retry-After":String(this.retryAfter),"RateLimit-Limit":String(this.result.limit),"RateLimit-Remaining":"0","RateLimit-Reset":String(Math.ceil(this.result.resetTime/1000))}}}});import{HttpError as _1}from"@stacksjs/error-handling";function d8($,Z){let W=`${Z}:${$}`,X=Z$.get(W);if(!X)X=new c8({windowMs:Z,maxRequests:$,algorithm:"fixed-window",standardHeaders:!1,legacyHeaders:!1}),Z$.set(W,X);return X}function u8($){if($!==void 0)return $;let Z=t();return Z?e9(Z):"anon"}function l8($,Z,W={}){let X=u8(W.identity),Y=`${$}:${X}`,J=async(G)=>{let z=d8(Z,G);try{await z.enforce(Y)}catch(Q){if(Q instanceof J8)throw Object.assign(new _1(429,"Too many requests",{key:$,max:Z,retryAfter:Q.retryAfter}),{headers:Q.toHeaders()});throw Q}};return{async per(G){let z=I1[G];if(!z)throw Error(`rateLimit().per: unknown period '${G}'`);await J(z*1000)},async over(G){if(!Number.isFinite(G)||G<=0)throw Error(`rateLimit().over: ttl must be a positive number, got ${G}`);await J(G*1000)}}}async function D1($,Z,W,X={}){let Y=u8(X.identity),J=`${$}:${Y}`,z=await d8(Z,W*1000).peek(J);if(!z)return null;return{count:z.current,limit:z.limit,remaining:Math.max(0,z.limit-z.current)}}async function O1($,Z,W,X={}){let Y=u8(X.identity),J=`${$}:${Y}`;await d8(Z,W*1000).reset(J)}var I1,Z$;var n8=u(()=>{$$();N5();I1={second:1,minute:60,hour:3600,day:86400},Z$=new Map});import Z5 from"process";function K1(){if(G8!==void 0)return G8;return G8=(Z5.env.APP_ENV??Z5.env.NODE_ENV??"").toLowerCase()==="production",G8}function T1(){if(z8!==void 0)return z8;return z8=Z5.env.STACKS_SECURITY_HEADERS_DISABLE==="true",z8}function M1(){if(I5!==void 0)return I5;let $=Z5.env.STACKS_CSP,Z=Z5.env.STACKS_CSP_REPORT_ONLY;if($)I5={header:"Content-Security-Policy",value:$};else if(Z)I5={header:"Content-Security-Policy-Report-Only",value:Z};else I5=null;return I5}function W$($){if(T1())return;if(!$.has("X-Content-Type-Options"))$.set("X-Content-Type-Options","nosniff");if(!$.has("X-Frame-Options"))$.set("X-Frame-Options","SAMEORIGIN");if(!$.has("Referrer-Policy"))$.set("Referrer-Policy","strict-origin-when-cross-origin");if(K1()&&!$.has("Strict-Transport-Security"))$.set("Strict-Transport-Security","max-age=31536000; includeSubDomains");let Z=M1();if(Z&&!$.has(Z.header))$.set(Z.header,Z.value)}var G8,z8,I5;var X$=()=>{};var G$={};G9(G$,{loadRoutes:()=>J$});import{log as S1}from"@stacksjs/logging";async function J$($){for(let[Z,W]of Object.entries($)){let X=E1(W),Y=X.prefix!==void 0?X.prefix?X.prefix.startsWith("/")?X.prefix:`/${X.prefix}`:void 0:N1.includes(Z)?void 0:`/${Z}`,J=R1(X.middleware);S1.debug(`[route-loader] Loading: ${X.path} prefix=${Y||"/"} middleware=[${J.join(", ")}]`);try{if(Y||J.length>0)await D5.group({prefix:Y,middleware:J.length>0?J:void 0},async()=>{await Y$(X.path)});else await Y$(X.path)}catch(G){let z=G instanceof Error?G.message:String(G);throw console.error(`[Routes] Failed to load route file '${X.path}': ${z}`),Error(`Route loading failed for '${X.path}': ${z}`)}}await C1()}async function C1(){if(process.env.STACKS_SKIP_DEFAULT_ROUTES==="1")return;try{let{frameworkPath:$}=await import("@stacksjs/path"),Z=$("defaults/bootstrap.ts");if(await Bun.file(Z).exists())await import(Z)}catch($){let Z=$ instanceof Error?$.message:String($);if(!Z.includes("Cannot find module")&&!Z.includes("MODULE_NOT_FOUND"))console.error(`[Routes] Failed to load framework bootstrap: ${Z}`)}}function x1($){if(typeof $!=="string"||$.length===0)throw Error("[route-loader] Invalid route path: empty or non-string");if($.includes("\x00"))throw Error("[route-loader] Invalid route path: null byte");let Z;try{Z=decodeURIComponent($)}catch{throw Error("[route-loader] Invalid route path: malformed URL encoding")}let W=Z.replace(/\.ts$/,"");if(W.startsWith("/")||/^[A-Za-z]:[\\/]/.test(W))throw Error(`[route-loader] Invalid route path: absolute paths not allowed (${W})`);if(W.split(/[/\\]/).some((Y)=>Y===".."))throw Error(`[route-loader] Invalid route path: '..' segment not allowed (${W})`);return W}async function Y$($){let Z=x1($),{projectPath:W}=await import("@stacksjs/path");await import(W(`routes/${Z}`))}function E1($){if(typeof $==="string")return{path:$};return $}function R1($){if(!$)return[];if(typeof $==="string")return[$];return $}var N1;var i8=u(()=>{O5();N1=["web"]});import T from"process";import{Buffer as z$}from"buffer";import{existsSync as q1}from"fs";import{timingSafeEqual as b1}from"crypto";import{log as A,report as F$}from"@stacksjs/logging";import{path as w}from"@stacksjs/path";import{UploadedFile as Q8}from"@stacksjs/storage";import{applyRequestEnhancements as w1,Router as P1}from"@stacksjs/bun-router";import{isCursorPaginator as k1,isPaginator as v1,isSimplePaginator as y1}from"@stacksjs/orm";function i($){let Z=w.storagePath(`framework/defaults/${$}`);if(q1(Z))return Z;if(P5===void 0)try{let W=Bun.resolveSync("@stacksjs/defaults/package.json",T.cwd());P5=W.slice(0,W.lastIndexOf("/"))}catch{P5=null}return P5?`${P5}/${$}`:Z}function f1($){if(typeof $==="number"){if(!Number.isFinite($)||$<=0)throw Error(`[Router] .rateLimit(): window must be a positive number of seconds, got ${$}`);return Math.floor($)}switch($){case"second":return 1;case"minute":return 60;case"hour":return 3600;case"day":return 86400;default:throw Error(`[Router] .rateLimit(): unknown period '${String($)}'`)}}class e8{max;map=new Map;constructor($){this.max=$}get($){return this.map.get($)}has($){return this.map.has($)}set($,Z){if(this.map.has($))this.map.delete($);if(this.map.set($,Z),this.map.size>this.max){let W=this.map.keys().next().value;if(W!==void 0)this.map.delete(W)}return this}delete($){return this.map.delete($)}clear(){this.map.clear()}get size(){return this.map.size}}function Q$($){let Z=T.env.STACKS_EXPOSE_ROUTES??"";if(!Z)return!((T.env.APP_ENV??"").toLowerCase()==="production"||T.env.NODE_ENV==="production");if(Z==="1")return!((T.env.APP_ENV??"").toLowerCase()==="production"||T.env.NODE_ENV==="production");let W=new URL($.url),X=$.headers.get("x-stacks-routes-token")||$.headers.get("X-Stacks-Routes-Token")||W.searchParams.get("token")||"";if(typeof X!=="string"||X.length===0||X.length!==Z.length)return!1;try{return b1(z$.from(X),z$.from(Z))}catch{return!1}}async function B8($,Z){if(!$._corsConfig||!Z)return Z;try{let{applyCorsHeaders:W}=await import(i("app/Middleware/Cors.ts"));return W($,Z,$._corsConfig)}catch(W){return A.warn("[router] CORS header injection failed",{error:W}),Z}}function g1($){let Z=h1($),W=new Map;for(let X of Z)W.set(X,new RegExp(`(^|/):${X}(?=$|/)`,"g"));return{path:$,paramNames:Z,colonRegex:W}}function h1($){let Z=new Set;for(let W of $.matchAll(/\{(\w+)\}/g))if(W[1])Z.add(W[1]);for(let W of $.matchAll(/(?:^|\/):(\w+)(?=$|\/)/g))if(W[1])Z.add(W[1]);return[...Z]}function W9($,Z={}){let W=v5.get($);if(!W)throw Error(`Route '${$}' is not defined. Available routes: ${[...v5.keys()].join(", ")}`);let X=W.paramNames.filter((Q)=>!(Q in Z)||Z[Q]===void 0);if(X.length>0)throw Error(`url('${$}'): missing required path param${X.length>1?"s":""} [${X.join(", ")}] for path '${W.path}'. Pass them as the second argument: url('${$}', { ${W.paramNames.join(", ")} })`);let Y;try{Y=T.env.APP_URL||"https://localhost"}catch{Y="https://localhost"}if(Y=Y.replace(/\/$/,""),!Y.startsWith("http"))Y=`https://${Y}`;let J=W.path,G={};for(let[Q,B]of Object.entries(Z)){let U=`{${Q}}`;if(J.includes(U))J=J.replaceAll(U,encodeURIComponent(String(B)));else{let j=W.colonRegex.get(Q);if(j&&j.test(J))j.lastIndex=0,J=J.replace(j,`$1${encodeURIComponent(String(B))}`);else G[Q]=String(B)}}let z=Object.keys(G).length>0?`?${new URLSearchParams(G).toString()}`:"";return`${Y}${J}${z}`}function m1($){let Z=v5.get($);return Z?[...Z.paramNames]:[]}function _$(){let $=[],Z=new Set;for(let W of J5.keys()){if(Z.has(W))continue;Z.add(W);let X=W.indexOf(":");if(X===-1)continue;let Y=W.slice(0,X),J=W.slice(X+1),G;for(let[z,Q]of v5.entries())if(Q.path===J){G=z;break}$.push({method:Y,path:J,name:G})}return $.sort((W,X)=>W.path.localeCompare(X.path))}function p1($,Z){let W=`${$}:${String(Z)}`;if(U$.has(W))return;U$.add(W),A.warn(`[Router] Middleware '${$}' declared an invalid priority (${String(Z)}). Priorities must be a finite non-negative number; falling back to default ${I$}.`)}function c1($){if($ instanceof h5)return $.toRouterHandler();if($&&typeof $==="object"&&typeof $.handle==="function"&&typeof $!=="function"){let Z=$.handle.bind($);return async(X,Y)=>{try{await Z(X)}catch(J){if(J instanceof Response)return J;throw J}return Y()}}return $}async function d1(){if(k5)return k5;return k5=(async()=>{try{return(await import(w.appPath("Middleware.ts"))).default||{}}catch{try{return(await import(i("app/Middleware.ts"))).default||{}}catch{return{}}}})(),k5}function l1($){if(!$)return $;let Z=j$.get($);if(Z!==void 0)return Z;let W=$.split(u1).filter(Boolean).map((X)=>X.charAt(0).toUpperCase()+X.slice(1)).join("");return j$.set($,W),W}async function n1($){let W=(await d1())[$]||l1($);return A.debug(`[middleware] Resolved: ${$} \u2192 ${W}`),W}async function D$($){if(Y5.has($))return Y5.get($)??null;let Z=await n1($),W;try{let X=w.appPath(`Middleware/${Z}.ts`),J=(await import(X)).default??null;if(!J||typeof J.handle!=="function")return A.error(`[Router] Middleware '${$}' resolved to ${X}, but the file has no default export with a handle() method`),Y5.set($,null),null;return Y5.set($,J),J}catch(X){W=X}try{let X=i(`app/Middleware/${Z}.ts`),J=(await import(X)).default??null;if(!J||typeof J.handle!=="function")return A.error(`[Router] Middleware '${$}' resolved to ${X}, but the file has no default export with a handle() method`),Y5.set($,null),null;return Y5.set($,J),J}catch(X){let Y=W instanceof Error?W.message:String(W);return A.error(`[Router] Failed to load middleware '${$}' (resolved to '${Z}'). app/Middleware: ${Y}; defaults:`,X),null}}function O$(){Y5.clear(),k5=null,$9.clear(),Z9.clear()}function i1(){if(T.env.APP_ENV==="production"||T.env.NODE_ENV==="production")return()=>{};let $=[];return(async()=>{try{let Z=await import("fs"),W=[w.appPath("Middleware"),w.appPath("Middleware.ts")];for(let X of W)try{if(!Z.existsSync(X))continue;let Y=Z.watch(X,{recursive:!0},()=>{A.debug("[middleware] hot-reload: clearing cache"),O$()});$.push(Y)}catch{}}catch{}})(),()=>{for(let Z of $)try{Z.close()}catch{}$=[]}}function T$($){let Z=$.indexOf(":");if(Z===-1)return{name:$};return{name:$.substring(0,Z),params:$.substring(Z+1)}}async function M$(){let $=new Map;for(let[W,X]of J5)for(let Y of X){let{name:J}=T$(Y),G=$.get(J)??[];G.push(W),$.set(J,G)}if(!$.has("csrf"))$.set("csrf",["(auto-injected on POST/PUT/PATCH/DELETE)"]);let Z=[];for(let[W,X]of $){let Y=await D$(W);if(!Y||typeof Y.handle!=="function")Z.push({alias:W,routes:X})}return Z}async function S$(){let $=await M$();if($.length===0)return;let Z=$.map((W)=>`"${W.alias}" (used by ${W.routes.join(", ")})`).join("; ");throw Error(`[Router] Unresolvable middleware alias(es): ${Z}. Check the alias map in app/Middleware.ts or add app/Middleware/<Class>.ts.`)}function W5($,Z){let W=Z6(Z,!0),X=null;if(typeof Z==="string"){let Y=$.slice(0,$.indexOf(":")).toUpperCase();if(B$.has(Y))X=N$(Z).then(()=>{return}).catch(()=>{return})}return async(Y)=>{try{await x$(Y)}catch(G){let z=G instanceof Error?G:Error(String(G));return j5(z,Y)}let J=C$(Y);if(X)await X;if(K$.has($))Y._forceJson=!0;return _8(J,async()=>{let G=A$.get($);if(G)try{await l8($,G.max).over(G.windowSeconds)}catch(D){return j5(D,Y)}let z=J5.get($)||[],Q=Y.method.toUpperCase(),B=[...z],U=z.some((D)=>D==="csrf"||D.startsWith("csrf:")),j=t8.has($),H=a8.has($),L=Z9.get($),F=L?$9.get(L)===!0:!1;if(B$.has(Q)&&!U&&(H||!j&&!F))B.unshift("csrf");if(B.length>0){let D=(T.env.LOG_LEVEL||"info").toLowerCase();if(D!=="info"&&D!=="warn"&&D!=="error"){let K=Y.url.indexOf("://"),M=K===-1?0:Y.url.indexOf("/",K+3),E=Y.url.indexOf("?",M<0?0:M),x=M<0?"/":Y.url.slice(M,E===-1?void 0:E);A.debug(`[middleware] Executing chain: [${B.join(", ")}] for ${Q} ${x}`)}}let f=[];for(let D of B){let{name:K,params:M}=T$(D);if(M)J._middlewareParams=J._middlewareParams||{},J._middlewareParams[K]=M;let E=await D$(K);if(!E||typeof E.handle!=="function"){A.error(`[Router] Middleware '${K}' on ${$} could not be resolved \u2014 failing closed`);let h=Error(`Middleware '${K}' could not be resolved`),Q5=await l(h,J,{status:500});return await B8(J,Q5)}let x=E.priority,z5=I$;if(typeof x==="number"&&Number.isFinite(x)&&x>=0)z5=x;else if(x!==void 0)p1(K,x);f.push({name:K,handler:E,priority:z5})}f.sort((D,K)=>D.priority-K.priority);let q=[];for(let{name:D,handler:K}of f){let M=T.hrtime.bigint(),E;try{let z5=new Promise((Q5,s)=>{E=setTimeout(()=>s(Error(`Middleware '${D}' exceeded 30000ms`)),30000)});await Promise.race([K.handle(J),z5]);let h=Number(T.hrtime.bigint()-M)/1e6;q.push({name:D,ms:h})}catch(x){let z5=Number(T.hrtime.bigint()-M)/1e6;if(q.push({name:D,ms:z5}),A.debug(`[middleware] Blocked by: ${D}`),x instanceof Response){try{let{_requestId:s,_startNs:K5}=J,T5=K5!=null?Number(T.hrtime.bigint()-K5)/1e6:null,o=T5!=null?[`total;dur=${T5.toFixed(1)}`]:[];for(let M5 of q){let F8=M5.name.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,32);o.push(`mw_${F8};dur=${M5.ms.toFixed(1)}`)}if(o.length>0)x.headers.set("Server-Timing",o.join(", "));if(s)x.headers.set("X-Request-ID",s)}catch{}return await B8(J,x)}let h=x instanceof Error?x:Error(String(x)),Q5="statusCode"in h||"status"in h?await j5(h,J):await(()=>{return A.error(`[Router] Middleware '${D}' threw an unexpected error:`,h),l(h,J,{status:500})})();try{let{_requestId:s,_startNs:K5}=J,T5=K5!=null?Number(T.hrtime.bigint()-K5)/1e6:null,o=T5!=null?[`total;dur=${T5.toFixed(1)}`]:[];for(let M5 of q){let F8=M5.name.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,32);o.push(`mw_${F8};dur=${M5.ms.toFixed(1)}`)}if(o.length>0)Q5.headers.set("Server-Timing",o.join(", "));if(s)Q5.headers.set("X-Request-ID",s)}catch{}return await B8(J,Q5)}finally{clearTimeout(E)}}let O=await W(J);if(l5(),O){if(Y.method==="GET"||Y.method==="HEAD"||Y.method==="OPTIONS")try{let{seedCsrfCookieIfMissing:K}=await import(i("app/Middleware/Csrf.ts"));O=K(J,O)}catch(K){A.warn("[router] CSRF cookie seeding failed",{error:K})}}if(O)O=await B8(J,O);let{_requestId:G5,_startNs:f5}=J,g5=f5!=null?Number(T.hrtime.bigint()-f5)/1e6:null,L8=(D)=>{if(G5)D.set("X-Request-ID",G5);if(g5!=null){let K=[`total;dur=${g5.toFixed(1)}`];for(let M of q){let E=M.name.replace(/[^A-Za-z0-9_-]/g,"_").slice(0,32);K.push(`mw_${E};dur=${M.ms.toFixed(1)}`)}D.set("Server-Timing",K.join(", "))}W$(D)};if(O&&typeof O.headers?.set==="function"){if(O.status>=400&&(O.headers.get("content-type")||"").includes("json")&&G5)try{let K=await O.clone().text(),M=JSON.parse(K);if(M&&typeof M==="object"){let E=new Headers(O.headers);return L8(E),new Response(JSON.stringify({...M,request_id:G5}),{status:O.status,statusText:O.statusText,headers:E})}}catch{}try{L8(O.headers)}catch{try{let K=O.clone(),M=new Headers(O.headers);return L8(M),new Response(K.body,{status:O.status,statusText:O.statusText,headers:M})}catch{}}}if(J._compress===!0&&O)try{let{applyCompression:D}=await import(i("app/Middleware/Compress.ts"));return await D(J,O)}catch(D){A.warn(`[router] Compression failed; sending uncompressed response: ${D instanceof Error?D.message:String(D)}`)}return O})}}function X5($){if(!J5.has($))J5.set($,[]);let Z=$.includes(":")?$.substring($.indexOf(":")+1):$,W={middleware(X){let Y=J5.get($);if(Y)Y.push(X);return W},name(X){return v5.set(X,g1(Z)),W},skipCsrf(){return t8.add($),a8.delete($),W},requireCsrf(){return a8.add($),t8.delete($),W},rateLimit(X,Y){if(!Number.isFinite(X)||X<=0)throw Error(`[Router] .rateLimit(): max must be a positive number, got ${String(X)}`);let J=f1(Y);return A$.set($,{max:Math.floor(X),windowSeconds:J}),W}};return W}async function s8($){try{return await Bun.file($).exists()}catch{return!1}}function s1($){if(typeof $!=="string"||$.length===0)throw Error(`[Router] Refusing to resolve handler '${String($)}': empty or non-string`);if($.includes("\x00"))throw Error("[Router] Refusing to resolve handler with null byte");if($.startsWith("/")||/^[A-Za-z]:[\\/]/.test($))throw Error(`[Router] Refusing to resolve absolute handler path '${$}'`);if($.split(/[/\\]/).some((W)=>W===".."))throw Error(`[Router] Refusing to resolve handler path '${$}' (contains '..' segment)`)}function L$($){let Z=H$.get($);if(!Z)Z=import($),H$.set($,Z);return Z}function N$($){let Z=o8.get($);if(!Z)Z=o1($),o8.set($,Z),Z.catch(()=>o8.delete($));return Z}async function o1($){s1($);let Z=$;if(Z=Z.endsWith(".ts")?Z.slice(0,-3):Z,Z.includes("Controller")){let[X,Y="index"]=Z.split("@"),J=w.appPath(`${X}.ts`),G=i(`app/${X}.ts`),z=await s8(J)?J:G;try{let Q=await L$(z);if(!Q.default||typeof Q.default!=="function")throw Error(`Controller ${X} does not export a default class`);let B=new Q.default;if(typeof B[Y]!=="function")throw Error(`Method ${Y} not found in controller ${X}`);return async(U)=>{let j=await B[Y](U);return r8(j,U)}}catch(Q){throw A.error(`[Router] Failed to load controller '${z}':`,Q),Q}}let W;if(Z.includes("storage/framework/orm"))W=Z;else if(Z.includes("OrmAction"))W=w.storagePath(`framework/actions/src/${Z}.ts`);else if(Z.includes("Actions")){let X=w.projectPath(`app/${Z}.ts`),Y=i(`app/${Z}.ts`);W=await s8(X)?X:Y}else{let X=w.appPath(`${Z}.ts`),Y=i(`app/${Z}.ts`);W=await s8(X)?X:Y}try{let Y=(await L$(W)).default;if(!Y)throw Error(`Action '${$}' has no default export`);if(typeof Y.handle!=="function")throw A.error(`[Router] Action '${$}' structure:`,Object.keys(Y)),Error(`Action '${$}' has no handle() method. Got: ${typeof Y.handle}`);let J=Y.skipCsrf===!0||Y.csrf===!1;$9.set($,J);let G=Y.apiResponse===!0;return async(z)=>{if(J)z._skipCsrf=!0;if(G)z._forceJson=!0;try{if(Y.validations){let B=await t1(z,Y.validations);if(!B.valid)return Response.json({error:"Validation failed",errors:B.errors},{status:422})}if(typeof Y.authorize==="function"){let B=await Y.authorize(z);if(B instanceof Response)return B;if(B===!1)return Response.json({error:"Forbidden"},{status:403})}if(typeof Y.before==="function"){let B=await Y.before(z);if(B instanceof Response)return B}let Q=await Y.handle(z);return r8(Q,z)}catch(Q){throw F$(Q,{label:`[Router] action.handle() for '${$}'`}),Q}}}catch(X){throw A.error(`[Router] Failed to import action '${W}':`,X),X}}async function t1($,Z){let W={},X=await a1($,Z);for(let[Y,J]of Object.entries(Z)){let G=X[Y],z;try{z=J.rule.validate(G)}catch{z={valid:!1,errors:[{message:`${Y} validation failed`}]}}if(!z.valid){let Q=[],B=Y.replace(/[-_]+/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").replace(/^./,(j)=>j.toUpperCase()),U=(j)=>j.toLowerCase().startsWith(Y.toLowerCase())||j.includes(B)?j:`${B} ${j}`;if(z.errors&&z.errors.length>0)if(J.message){let j=z.errors[0]?.message??"";Q.push(typeof J.message==="string"?J.message:J.message[Y]||U(j))}else z.errors.forEach((j)=>Q.push(U(j.message)));else Q.push(J.message?typeof J.message==="string"?J.message:`${B} is invalid`:`${B} is invalid`);W[Y]=Q}}return{valid:Object.keys(W).length===0,errors:W}}async function a1($,Z){let W={},X=$.query;if(X)for(let Y in X)W[Y]=X[Y];else new URL($.url).searchParams.forEach((J,G)=>{W[G]=J});if($.params)Object.assign(W,$.params);if($.jsonBody&&typeof $.jsonBody==="object")Object.assign(W,$.jsonBody);else if($.formBody&&typeof $.formBody==="object")Object.assign(W,$.formBody);if(typeof $.allFiles==="function")try{let Y=$.allFiles();for(let J of Object.keys(Y??{}))if(!(J in W))W[J]=Y[J]}catch{}if(!Z)return W;for(let[Y,J]of Object.entries(Z)){let G=W[Y];if(typeof G!=="string")continue;let z=J.rule?.name;if(z==="number"){let Q=Number(G);if(Number.isFinite(Q))W[Y]=Q}else if(z==="boolean"){if(G==="true"||G==="1")W[Y]=!0;else if(G==="false"||G==="0")W[Y]=!1}}return W}function r8($,Z){if($ instanceof Response)return $;if($ instanceof ReadableStream)return new Response($,{headers:{"Content-Type":"application/octet-stream"}});let X=Z._forceJson===!0||a(Z);if($===null||$===void 0)return X?new Response(null,{status:204}):new Response("",{status:200});if(typeof $==="object"){let Y=r1($);if(Y)return Response.json($,{headers:{Link:Y}});return Response.json($)}if(X)return Response.json($);return new Response(String($),{headers:{"Content-Type":"text/plain; charset=utf-8"}})}function r1($){if(!v1($)&&!y1($)&&!k1($))return null;let Z=$,W=[];if(Z.prev_page_url)W.push(`<${Z.prev_page_url}>; rel="prev"`);if(Z.next_page_url)W.push(`<${Z.next_page_url}>; rel="next"`);if(Z.first_page_url)W.push(`<${Z.first_page_url}>; rel="first"`);if(Z.last_page_url)W.push(`<${Z.last_page_url}>; rel="last"`);return W.length>0?W.join(", "):null}function e1($,Z={}){let W={};if(Z.type==="sse")W["Content-Type"]="text/event-stream; charset=utf-8",W["Cache-Control"]="no-cache",W.Connection="keep-alive";else if(Z.type==="ndjson")W["Content-Type"]="application/x-ndjson; charset=utf-8";else W["Content-Type"]=Z.contentType??"application/octet-stream";let X=$ instanceof ReadableStream?$:new ReadableStream({async start(J){try{for await(let G of $)J.enqueue(typeof G==="string"?new TextEncoder().encode(G):G);J.close()}catch(G){J.error(G)}}}),Y=new Headers(W);if(Z.headers)new Headers(Z.headers).forEach((G,z)=>Y.set(z,G));return new Response(X,{status:Z.status??200,headers:Y})}function b($){let Z=$._allInputCache;if(Z)return Z;let W={},X=$.query;if(X)for(let Y in X)W[Y]=X[Y];if($.jsonBody&&typeof $.jsonBody==="object")Object.assign(W,$.jsonBody);if($.formBody&&typeof $.formBody==="object")Object.assign(W,$.formBody);if($.params&&typeof $.params==="object")Object.assign(W,$.params);return $._allInputCache=W,W}function C$($){w1($,$.params||{});let Z=$.query;if(!Z){let W=new URL($.url);Z={},W.searchParams.forEach((X,Y)=>{Z[Y]=X}),$.query=Z}return Object.assign($,$6),$}function Z6($,Z=!1){if(typeof $==="string"){let X=$;return async(Y)=>{try{if(!Z)await x$(Y),Y=C$(Y);return await(await N$(X))(Y)}catch(J){F$(J,{label:`[Router] ${X}`});let G=J?.statusCode??J?.status,z=typeof G==="number"&&Number.isInteger(G)&&G>=400&&G<600?G:void 0;return await l(J instanceof Error?J:Error(String(J)),Y,{handlerPath:X,status:z})}}}let W=$;return async(X)=>{let Y=await W(X);return r8(Y,X)}}async function x$($){if($._bodyParsed)return;$._bodyParsed=!0;let Z=$.headers.get("content-type")||"";try{if(m5.test(Z)){let X=await $.clone().text();if($._rawBody=X,X.length===0)$.jsonBody={};else try{let Y=JSON.parse(X);$.jsonBody=Y&&typeof Y==="object"?Y:{}}catch(Y){let J=Y instanceof Error?Y.message:"Invalid JSON",{HttpError:G}=await import("@stacksjs/error-handling");throw new G(400,`Invalid JSON body: ${J}`)}}else if(Z.includes("application/x-www-form-urlencoded")){let W=await $.clone().text(),X=new URLSearchParams(W),Y={};X.forEach((J,G)=>{Y[G]=J}),$.formBody=Y}else if(Z.includes("multipart/form-data")){let W=await $.clone().formData(),X={},Y={};W.forEach((J,G)=>{if(J instanceof File)if(Y[G])if(Array.isArray(Y[G]))Y[G].push(J);else Y[G]=[Y[G],J];else Y[G]=J;else X[G]=J}),Reflect.set($,"formBody",X),Reflect.set($,"files",Y)}}catch(W){if(typeof(W?.status??W?.statusCode)==="number")throw W;A.debug("[stacks-router] Body parsing failed:",W)}}function E$($={}){let Z=new P1({verbose:$.verbose??!1}),W="",X=[],Y=!1;function J(z,Q,B){let U=W+Q,j=`${z}:${U}`;if(A.debug(`[router] ${z} ${U} \u2192 ${typeof B==="string"?B:"function"}`),X.length>0)J5.set(j,[...X]);if(Y)K$.add(j);if(typeof B==="string")Z9.set(j,B);return{fullPath:U,routeKey:j}}let G={bunRouter:Z,get routes(){return Z.routes},get(z,Q){let{fullPath:B,routeKey:U}=J("GET",z,Q);return Z.get(B,W5(U,Q)),X5(U)},post(z,Q){let{fullPath:B,routeKey:U}=J("POST",z,Q);return Z.post(B,W5(U,Q)),X5(U)},put(z,Q){let{fullPath:B,routeKey:U}=J("PUT",z,Q);return Z.put(B,W5(U,Q)),X5(U)},patch(z,Q){let{fullPath:B,routeKey:U}=J("PATCH",z,Q);return Z.patch(B,W5(U,Q)),X5(U)},delete(z,Q){let{fullPath:B,routeKey:U}=J("DELETE",z,Q);return Z.delete(B,W5(U,Q)),X5(U)},options(z,Q){let{fullPath:B,routeKey:U}=J("OPTIONS",z,Q);return Z.options(B,W5(U,Q)),X5(U)},group(z,Q){let B=W,U=[...X],j=Y;if(z.prefix)W=B+z.prefix;let H=z.middleware?Array.isArray(z.middleware)?z.middleware:[z.middleware]:void 0;if(H)X=[...X,...H];if(z.apiResponse===!0)Y=!0;A.debug(`[router] Entering group: prefix=${z.prefix||"/"} middleware=[${H?.join(", ")||""}]${Y?" apiResponse=true":""}`);let L=Q();if(L instanceof Promise)return L.then(()=>{return W=B,X=U,Y=j,G}).catch((F)=>{throw W=B,X=U,Y=j,F});return W=B,X=U,Y=j,G},resource(z,Q,B){let U=["index","store","show","update","destroy"],j=B?.only?U.filter((F)=>B.only.includes(F)):B?.except?U.filter((F)=>!B.except.includes(F)):U,H=Q.replace(/Action$/,"");A.debug(`[router] Resource: /${z} \u2192 ${Q} [${j.join(", ")}]`);let L=()=>{for(let F of j)switch(F){case"index":G.get(`/${z}`,`${H}IndexAction`);break;case"store":G.post(`/${z}`,`${H}StoreAction`);break;case"show":G.get(`/${z}/:id`,`${H}ShowAction`);break;case"update":G.put(`/${z}/:id`,`${H}UpdateAction`);break;case"destroy":G.delete(`/${z}/:id`,`${H}DestroyAction`);break}};if(B?.middleware)G.group({middleware:B.middleware},L);else L();return G},match(z,Q,B){A.debug(`[router] Match: [${z.join(", ")}] ${Q} \u2192 ${typeof B==="string"?B:"function"}`);for(let U of z){let j=U.toUpperCase(),{fullPath:H,routeKey:L}=J(j,Q,B),F=W5(L,B);switch(j){case"GET":Z.get(H,F);break;case"POST":Z.post(H,F);break;case"PUT":Z.put(H,F);break;case"PATCH":Z.patch(H,F);break;case"DELETE":Z.delete(H,F);break;case"OPTIONS":Z.options(H,F);break}}return X5(`${z[0]}:${W}${Q}`)},health(){return Z.get("/api/health",async()=>{let z={},Q=async(j,H)=>{let L=Date.now();try{let F=new AbortController,I=setTimeout(()=>F.abort(),1500);await Promise.race([H(),new Promise((f,q)=>F.signal.addEventListener("abort",()=>q(Error("timeout"))))]),clearTimeout(I),z[j]={ok:!0,ms:Date.now()-L}}catch(F){z[j]={ok:!1,ms:Date.now()-L,message:F instanceof Error?F.message:String(F)}}};await Promise.all([Q("database",async()=>{let{db:j}=await import("@stacksjs/database");await j.unsafe?.("SELECT 1")}),Q("cache",async()=>{let{cache:j}=await import("@stacksjs/cache"),H=`__health__:${Date.now()}`;await j.set(H,1,5),await j.del(H)})]);let B=Object.values(z).every((j)=>j.ok),U={status:B?"healthy":"degraded",checks:z,timestamp:Date.now()};return Response.json(U,{status:B?200:503})}),Z.get("/__routes",(z)=>{if(!Q$(z))return Response.json({error:"disabled"},{status:404});return Response.json(_$())}),Z.get("/__storage/:path",async(z)=>{let Q=new URL(z.url),B=Q.searchParams.get("token"),U=z.params,j=U?.path?decodeURIComponent(U.path):decodeURIComponent(Q.pathname.replace(/^\/__storage\//,""));if(!B||typeof j!=="string"||j.length===0)return new Response("Forbidden",{status:403});let{verifySignedStorageToken:H,Storage:L}=await import("@stacksjs/storage");if(!H(B,j).valid)return new Response("Forbidden",{status:403});try{let I=L.disk();if(!await I.fileExists(j))return new Response("Not Found",{status:404});let q=await I.readToBuffer(j),O=await I.mimeType(j).catch(()=>"application/octet-stream");return new Response(q,{status:200,headers:{"Content-Type":O,"Cache-Control":"private, max-age=60","X-Content-Type-Options":"nosniff"}})}catch(I){return A.error("[storage] signed-url fetch failed:",I),new Response("Internal Error",{status:500})}}),Z.get("/__openapi.json",async(z)=>{if(!Q$(z))return Response.json({error:"disabled"},{status:404});try{let{generateOpenApi:Q}=await import("@stacksjs/api"),B=await Q();return Response.json(B)}catch(Q){return Response.json({error:"OpenAPI generation failed",message:Q instanceof Error?Q.message:String(Q)},{status:500})}}),G},use(z){let Q=c1(z);return Z.globalMiddleware.push(Q),G},async serve(z={}){return Z.serve(z)},async handleRequest(z){return Z.handleRequest(z)},getAllowedMethods(z,Q){return Z.getAllowedMethods(z,Q)},async register(z,Q){A.debug(`[router] Register: ${z} prefix=${Q?.prefix||"none"}`);let B=async()=>{await import(z)};if(Q?.prefix||Q?.middleware)await G.group({prefix:Q.prefix,middleware:Q.middleware},B);else await B();return G},async importRoutes(){A.debug("[router] Loading user routes from registry...");try{let{loadRoutes:B}=await Promise.resolve().then(() => (i8(),G$)),{appPath:U}=await import("@stacksjs/path"),j=(await import(U("Routes.ts"))).default;await B(j)}catch(B){throw A.error("Failed to load route registry:",B),B}A.debug("[router] Loading ORM routes...");let z=[w.frameworkPath("orm/routes.ts"),w.frameworkPath("core/orm/routes.ts")],Q=!1;for(let B of z)try{if(await Bun.file(B).exists()){await import(B),Q=!0;break}}catch(U){A.warn(`[router] ORM routes candidate failed to load, falling back to next: ${B}
|
|
50
|
+
`,U)}if(!Q)A.warn("[router] No ORM routes candidate loaded \u2014 model useApi endpoints are unavailable.");A.debug("[router] Loading discovered package routes...");try{await G.loadDiscoveredRoutes()}catch(B){A.debug("Package route discovery skipped:",B)}await S$()},async loadDiscoveredRoutes(){try{let z=w.storagePath("framework/discovered-packages.json"),Q=Bun.file(z);if(!await Q.exists())return;let U=(await Q.json())?.packages;if(!U)return;let j=w.projectPath("pantry");for(let[H,L]of Object.entries(U)){let F=L?.routes;if(!F)continue;let I=Array.isArray(F)?F:[F],f=`${j}/${H}`;for(let q of I){A.debug(`[router] Discovered route: ${H} \u2192 ${q}`);let O=q.startsWith("/")?q:`${f}/${q}`,G5=L?.routePrefix,f5=L?.routeMiddleware;try{await G.register(O,{prefix:G5,middleware:f5})}catch(g5){A.warn(`Failed to load routes from package '${H}': ${g5}`)}}}}catch{}}};return G}async function W6($,Z){if(!U8)A.debug("[router] Loading routes for first time..."),U8=D5.importRoutes().catch((X)=>{throw U8=null,X});await U8;let W=await D5.handleRequest($);if(W.status===404&&W.headers.get("content-type")?.includes("json"))try{let X=await W.clone().json();if(X?.message==="Not Found"||X?.error==="Not Found"){let J=new URL($.url),G={...X,path:J.pathname,method:$.method};return new Response(JSON.stringify(G),{status:404,headers:W.headers})}}catch{}return W}async function X6($={}){return D5.serve($)}var P5,t8,a8,A$,V$=5000,$9,Z9,B$,v5,I$=10,U$,Y5,k5=null,u1,j$,J5,K$,H$,o8,$6,D5,U8=null;var O5=u(()=>{N5();p5();n5();n8();X$();t8=new Set,a8=new Set,A$=new Map;$9=new e8(V$),Z9=new e8(V$),B$=new Set(["POST","PUT","PATCH","DELETE"]),v5=new Map;U$=new Set;Y5=new Map;u1=/[-_\s]+/,j$=new Map;J5=new Map,K$=new Set;H$=new Map;o8=new Map;$6={get($,Z){let X=b(this)[$];return X!==void 0?X:Z},input($,Z){let X=b(this)[$];return X!==void 0?X:Z},all(){return b(this)},only($){let Z=b(this),W={};for(let X of $)if(X in Z)W[X]=Z[X];return W},except($){let W={...b(this)};for(let X of $)delete W[X];return W},has($){let Z=b(this);if(Array.isArray($))return $.every((W)=>(W in Z)&&Z[W]!==void 0);return $ in Z&&Z[$]!==void 0},hasAny($){let Z=b(this);return $.some((W)=>(W in Z)&&Z[W]!==void 0)},filled($){let Z=b(this),W=(X)=>{let Y=Z[X];return Y!==void 0&&Y!==null&&Y!==""&&!(Array.isArray(Y)&&Y.length===0)};if(Array.isArray($))return $.every(W);return W($)},missing($){let Z=b(this);if(Array.isArray($))return $.every((W)=>!(W in Z)||Z[W]===void 0);return!($ in Z)||Z[$]===void 0},string($,Z=""){let X=b(this)[$];return X!==void 0&&X!==null?String(X):Z},integer($,Z=0){let X=b(this)[$];if(X===void 0||X===null||X==="")return Z;if(typeof X==="number")return Number.isFinite(X)?Math.trunc(X):Z;let Y=String(X).trim();if(!/^-?\d+$/.test(Y))return Z;let J=Number.parseInt(Y,10);return Number.isFinite(J)?J:Z},float($,Z=0){let X=b(this)[$];if(X===void 0||X===null||X==="")return Z;if(typeof X==="number")return Number.isFinite(X)?X:Z;let Y=String(X).trim();if(!/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(Y))return Z;let J=Number.parseFloat(Y);return Number.isFinite(J)?J:Z},boolean($,Z=!1){let X=b(this)[$];if(X===void 0||X===null)return Z;if(typeof X==="boolean")return X;if(X==="true"||X==="1"||X===1)return!0;if(X==="false"||X==="0"||X===0)return!1;return Z},array($){let W=b(this)[$];if(Array.isArray(W))return W;return W!==void 0&&W!==null?[W]:[]},file($){let W=(this.files||{})[$];if(!W)return null;let X=Array.isArray(W)?W[0]:W;return X?new Q8(X):null},getFiles($){let W=(this.files||{})[$];if(!W)return[];return(Array.isArray(W)?W:[W]).map((Y)=>new Q8(Y))},hasFile($){let Z=this.files||{};return $ in Z&&Z[$]!==void 0},allFiles(){let $=this.files||{},Z={};for(let[W,X]of Object.entries($))if(Array.isArray(X))Z[W]=X.map((Y)=>new Q8(Y));else Z[W]=new Q8(X);return Z},async user(){return this._authenticatedUser},async userToken(){return this._currentAccessToken},async tokenCan($){if(typeof $!=="string"||$.length===0)return!1;let Z=this._currentAccessToken;if(!Z||typeof Z!=="object")return!1;if(!Array.isArray(Z.abilities))return!1;if(Z.abilities.includes("*"))return!0;return Z.abilities.includes($)},async tokenCant($){return!await this.tokenCan($)},async can($,...Z){if(typeof $!=="string"||$.length===0)return!1;let{Gate:W}=await import("@stacksjs/auth"),X=this._authenticatedUser??null;return W.allows($,X,...Z)},async cannot($,...Z){return!await this.can($,...Z)},async authorize($,...Z){let{Gate:W}=await import("@stacksjs/auth"),X=this._authenticatedUser??null;await W.authorize($,X,...Z)}};D5=E$()});O5();N5();i8();n5();O5();p5();n8();export*from"@stacksjs/bun-router";class g extends Error{reason;constructor($,Z,W){let X=W?` in ${W}`:"";super(`[router] Refusing to use ${JSON.stringify(Z)} as a path parameter${X} \u2014 ${$}`);this.name="PathParamError",this.reason=$}}var Y6=/[\u0000-\u001F\u007F]/;function R$($,Z={}){if(typeof $!=="string")throw new g("not-string",$,Z.context);if($.length===0)throw new g("empty",$,Z.context);let W=Z.maxLength??255;if($.length>W)throw new g("too-long",$,Z.context);if($.includes("\x00"))throw new g("null-byte",$,Z.context);if(Y6.test($))throw new g("control-char",$,Z.context);if($.startsWith("/")||/^[A-Z]:[\\/]/i.test($))throw new g("absolute-path",$,Z.context);if(/(^|[\\/])\.\.([\\/]|$)/.test($))throw new g("traversal",$,Z.context);if(!Z.allowSlashes&&/[\\/]/.test($))throw new g("traversal",$,Z.context);return $}function J6($,Z={}){try{return R$($,Z)}catch{return null}}O5();O5();import{timingSafeEqual as G6}from"crypto";import{Buffer as q$}from"buffer";import j8 from"process";var Y9="signature",X9="expires";function w$(){let $=j8.env.APP_KEY||j8.env.STACKS_SIGNED_URL_SECRET;if(!$||$.length<16)throw Error("[router] signed URLs require APP_KEY (\u2265 16 chars) or STACKS_SIGNED_URL_SECRET. "+"Run `./buddy key:generate` or set the env var.");return $}function P$($,Z){return new Bun.CryptoHasher("sha256",Z).update($).digest("hex")}function z6($,Z){let W=q$.from($.toLowerCase(),"hex"),X=q$.from(Z.toLowerCase(),"hex");if(W.length!==X.length)return!1;return G6(W,X)}function Q6($){let Z=new URL($.toString());return Z.searchParams.delete(Y9),Z}function k$($){let Z=Q6($);return Z.searchParams.sort(),Z.toString()}function v$($,Z={}){let W=w$(),X=$.startsWith("http")?new URL($):new URL($.startsWith("/")?$:`/${$}`,j8.env.APP_URL||"https://localhost");if(Z.ttl!==void 0&&Z.expiresAt!==void 0)B6("dual-expiry","[router] signUrl: both `ttl` and `expiresAt` provided \u2014 using `ttl`.");if(Z.ttl!==void 0)X.searchParams.set(X9,String(Math.floor(Date.now()/1000)+Z.ttl));else if(Z.expiresAt!==void 0)X.searchParams.set(X9,String(Math.floor(Z.expiresAt)));let Y=k$(X);return X.searchParams.set(Y9,P$(Y,W)),X.toString()}var b$=new Set;function B6($,Z){if(b$.has($))return;b$.add($),console.warn(Z)}function U6($,Z={},W={}){return v$(W9($,Z),W)}function y$($){let Z=typeof $==="string"?new URL($,j8.env.APP_URL||"https://localhost"):$,W=Z.searchParams.get(Y9);if(!W)return{valid:!1,reason:"missing-signature"};let X=Z.searchParams.get(X9);if(X!==null){let Y=Number.parseInt(X,10);if(!Number.isFinite(Y)||Date.now()/1000>Y)return{valid:!1,reason:"expired"}}try{let Y=P$(k$(Z),w$());return z6(W,Y)?{valid:!0}:{valid:!1,reason:"invalid-signature"}}catch{return{valid:!1,reason:"invalid-signature"}}}async function j6($){let Z=y$($.url);if(Z.valid)return;let W=Z.reason==="expired"?410:401;throw Response.json({error:Z.reason},{status:W})}import{decrypt as H6,encrypt as L6}from"@stacksjs/security";class H8{inner;opts;constructor($,Z={}){this.inner=$;this.opts=Z}async set($,Z,W){let X=await this.wrap($,Z);await this.inner.set($,X,W)}async touch($,Z,W){let X=await this.wrap($,Z);if(this.inner.touch)await this.inner.touch($,X,W);else await this.inner.set($,X,W)}async get($){let Z=await this.inner.get($);if(!Z)return null;return this.unwrap(Z)}destroy($){return this.inner.destroy($)}async all(){let $=await this.inner.all?.()??{},Z={};for(let[W,X]of Object.entries($)){let Y=await this.unwrap(X);if(Y)Z[W]=Y}return Z}async length(){if(this.inner.length)return this.inner.length();return Object.keys(await this.all()).length}async clear(){if(this.inner.clear)return this.inner.clear();let $=await this.inner.all?.()??{};await Promise.all(Object.keys($).map((Z)=>this.inner.destroy(Z)))}async wrap($,Z){let{id:W,...X}=Z,Y=await L6(JSON.stringify(X),this.opts.appKey);return{_enc:!0,id:W??$,data:Y}}async unwrap($){if(!$||typeof $!=="object")return null;let Z=$;if(Z._enc===!0&&typeof Z.data==="string")try{let W=await H6(Z.data,this.opts.appKey),X=JSON.parse(W);if(Z.id!==void 0)X.id=Z.id;return X}catch{return null}return Z}}import y5 from"process";import{createSessionStore as F6}from"@stacksjs/bun-router";import{DatabaseSessionStore as _6,FileSessionStore as I6,MemorySessionStore as D6,RedisSessionStore as O6,createSessionStore as K6}from"@stacksjs/bun-router";function A6($){let Z=F6($);if(!V6($.encrypt))return Z;let X=$.appKey??y5.env.APP_KEY;if(!X||X.length<16)throw Error("[session] createStacksSessionStore: encryption requested but APP_KEY is missing or too short "+"(need \u226516 chars). Either set APP_KEY in env, pass `appKey` in config, or set `encrypt: false` to opt out.");return new H8(Z,{appKey:X})}function V6($){if($===!0)return!0;if($===!1)return!1;return(y5.env.APP_ENV??y5.env.NODE_ENV??"").toLowerCase()==="production"}import("@stacksjs/database").then(({setQueryTracker:$})=>{if(typeof $==="function"){let{trackQuery:Z}=(n5(),p$(_9));$(Z)}}).catch(()=>{});export{i$ as withTraceId,j6 as verifySignedUrlMiddleware,y$ as verifySignedUrl,W9 as url,L9 as trackQuery,e1 as stream,U6 as signedUrl,v$ as signUrl,t$ as setCurrentRequest,W6 as serverResponse,X6 as serve,R$ as sanitizePathParam,J6 as safePathParam,_8 as runWithRequest,m1 as routeParams,D5 as route,a$ as request,D1 as rateLimitStatus,l8 as rateLimit,J$ as loadRoutes,_$ as listRegisteredRoutes,a as isApiRequest,i1 as installMiddlewareHotReload,n$ as getTraceId,F9 as getQueryShapeCounts,t as getCurrentRequest,M$ as findUnresolvableRouteMiddleware,A9 as createValidationErrorResponse,A6 as createStacksSessionStore,E$ as createStacksRouter,K6 as createSessionStore,V9 as createNotFoundResponse,j5 as createMiddlewareErrorResponse,l as createErrorResponse,l5 as clearTrackedQueries,O1 as clearRateLimit,O$ as clearMiddlewareCache,o$ as cacheRequestQuery,S$ as assertRouteMiddlewareResolvable,O6 as RedisSessionStore,g as PathParamError,h5 as Middleware,D6 as MemorySessionStore,m5 as JSON_CONTENT_TYPE,I6 as FileSessionStore,H8 as EncryptedSessionStore,_6 as DatabaseSessionStore};
|
|
@@ -63,5 +63,9 @@ export declare interface StacksRequestMacros {
|
|
|
63
63
|
*/
|
|
64
64
|
export type StacksRequestExtensions = StacksRequestMarkers & StacksRequestMacros;
|
|
65
65
|
declare module '@stacksjs/bun-router' {
|
|
66
|
-
interface EnhancedRequestextends
|
|
66
|
+
interface EnhancedRequestextends StacksRequestMarkers {
|
|
67
|
+
allFiles?: StacksRequestMacros['allFiles']
|
|
68
|
+
tokenCan?: StacksRequestMacros['tokenCan']
|
|
69
|
+
can?: StacksRequestMacros['can']
|
|
70
|
+
}
|
|
67
71
|
}
|
package/dist/stacks-router.d.ts
CHANGED
|
@@ -172,7 +172,7 @@ export declare interface StacksRouterInstance {
|
|
|
172
172
|
resource: (name: string, handler: string, options?: ResourceRouteOptions) => StacksRouterInstance
|
|
173
173
|
match: (methods: string[], path: string, handler: StacksHandler) => ChainableRoute
|
|
174
174
|
health: () => StacksRouterInstance
|
|
175
|
-
use: (middleware: ActionHandler) => StacksRouterInstance
|
|
175
|
+
use: (middleware: ActionHandler | ((req: EnhancedRequest, next: () => Promise<Response>) => Response | Promise<Response>)) => StacksRouterInstance
|
|
176
176
|
register: (routePath: string, options?: { prefix?: string, middleware?: string | string[] }) => Promise<StacksRouterInstance>
|
|
177
177
|
serve: (options?: ServerOptions) => Promise<Server<unknown>>
|
|
178
178
|
handleRequest: (req: Request) => Promise<Response>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/router",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.70.
|
|
4
|
+
"version": "0.70.74",
|
|
5
5
|
"description": "The Stacks framework router.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": [
|
|
@@ -56,15 +56,15 @@
|
|
|
56
56
|
"@stacksjs/bun-router": "0.0.17"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@stacksjs/actions": "0.70.
|
|
60
|
-
"@stacksjs/config": "0.70.
|
|
61
|
-
"better-dx": "^0.2.
|
|
62
|
-
"@stacksjs/error-handling": "0.70.
|
|
63
|
-
"@stacksjs/logging": "0.70.
|
|
64
|
-
"@stacksjs/orm": "0.70.
|
|
65
|
-
"@stacksjs/path": "0.70.
|
|
66
|
-
"@stacksjs/storage": "0.70.
|
|
67
|
-
"@stacksjs/types": "0.70.
|
|
68
|
-
"@stacksjs/validation": "0.70.
|
|
59
|
+
"@stacksjs/actions": "0.70.74",
|
|
60
|
+
"@stacksjs/config": "0.70.74",
|
|
61
|
+
"better-dx": "^0.2.16",
|
|
62
|
+
"@stacksjs/error-handling": "0.70.74",
|
|
63
|
+
"@stacksjs/logging": "0.70.74",
|
|
64
|
+
"@stacksjs/orm": "0.70.74",
|
|
65
|
+
"@stacksjs/path": "0.70.74",
|
|
66
|
+
"@stacksjs/storage": "0.70.74",
|
|
67
|
+
"@stacksjs/types": "0.70.74",
|
|
68
|
+
"@stacksjs/validation": "0.70.74"
|
|
69
69
|
}
|
|
70
70
|
}
|