@@ -52,10 +52,96 @@ function getErrorHandlerConfig(): ErrorPageConfig {
5252 }
5353}
5454
55+ /**
56+ * Sensitive fields that should be hidden in error pages
57+ */
58+ const SENSITIVE_FIELDS = [
59+ 'password' ,
60+ 'password_confirmation' ,
61+ 'secret' ,
62+ 'token' ,
63+ 'api_key' ,
64+ 'apiKey' ,
65+ 'api_secret' ,
66+ 'apiSecret' ,
67+ 'access_token' ,
68+ 'accessToken' ,
69+ 'refresh_token' ,
70+ 'refreshToken' ,
71+ 'private_key' ,
72+ 'privateKey' ,
73+ 'credit_card' ,
74+ 'creditCard' ,
75+ 'card_number' ,
76+ 'cardNumber' ,
77+ 'cvv' ,
78+ 'ssn' ,
79+ 'authorization' ,
80+ ]
81+
82+ /**
83+ * Sanitize object by hiding sensitive fields
84+ */
85+ function sanitizeData ( data : unknown ) : unknown {
86+ if ( ! data || typeof data !== 'object' ) {
87+ return data
88+ }
89+
90+ if ( Array . isArray ( data ) ) {
91+ return data . map ( sanitizeData )
92+ }
93+
94+ const sanitized : Record < string , unknown > = { }
95+ for ( const [ key , value ] of Object . entries ( data as Record < string , unknown > ) ) {
96+ const lowerKey = key . toLowerCase ( )
97+ if ( SENSITIVE_FIELDS . some ( field => lowerKey . includes ( field . toLowerCase ( ) ) ) ) {
98+ sanitized [ key ] = '********'
99+ }
100+ else if ( typeof value === 'object' && value !== null ) {
101+ sanitized [ key ] = sanitizeData ( value )
102+ }
103+ else {
104+ sanitized [ key ] = value
105+ }
106+ }
107+ return sanitized
108+ }
109+
110+ /**
111+ * Get request body from enhanced request (already parsed)
112+ */
113+ function getRequestBody ( request : Request | EnhancedRequest ) : unknown {
114+ const req = request as any
115+ if ( req . jsonBody ) {
116+ return sanitizeData ( req . jsonBody )
117+ }
118+ if ( req . formBody ) {
119+ return sanitizeData ( req . formBody )
120+ }
121+ return undefined
122+ }
123+
124+ /**
125+ * Get user context from authenticated user on request
126+ */
127+ async function getUserContext ( request : Request | EnhancedRequest ) : Promise < { id ?: string | number ; email ?: string ; name ?: string } | undefined > {
128+ const req = request as any
129+ // Check if user was set by auth middleware
130+ if ( req . _authenticatedUser ) {
131+ const user = req . _authenticatedUser
132+ return {
133+ id : user . id ,
134+ email : user . email ,
135+ name : user . name || user . username ,
136+ }
137+ }
138+ return undefined
139+ }
140+
55141/**
56142 * Create an Ignition-style error response for development
57143 */
58- export function createErrorResponse (
144+ export async function createErrorResponse (
59145 error : Error ,
60146 request : Request | EnhancedRequest ,
61147 options ?: {
@@ -67,7 +153,7 @@ export function createErrorResponse(
67153 middleware ?: string [ ]
68154 }
69155 } ,
70- ) : Response {
156+ ) : Promise < Response > {
71157 const status = options ?. status || 500
72158 const isDevelopment = process . env . APP_ENV !== 'production' && process . env . NODE_ENV !== 'production'
73159
@@ -102,8 +188,27 @@ export function createErrorResponse(
102188 // Set framework info
103189 handler . setFramework ( 'Stacks' , '0.70.0' )
104190
105- // Set request context
106- handler . setRequest ( request )
191+ // Set request context with body
192+ const requestBody = getRequestBody ( request )
193+ if ( requestBody ) {
194+ const url = new URL ( request . url )
195+ handler . setRequest ( {
196+ method : request . method ,
197+ url : request . url ,
198+ headers : Object . fromEntries ( request . headers . entries ( ) ) ,
199+ queryParams : Object . fromEntries ( url . searchParams . entries ( ) ) ,
200+ body : requestBody ,
201+ } )
202+ }
203+ else {
204+ handler . setRequest ( request )
205+ }
206+
207+ // Set user context if authenticated
208+ const userContext = await getUserContext ( request )
209+ if ( userContext ) {
210+ handler . setUser ( userContext )
211+ }
107212
108213 // Set routing context if available
109214 if ( options ?. routingContext ) {
@@ -177,10 +282,10 @@ export function createErrorResponse(
177282/**
178283 * Create a middleware error response (401, 403, etc.)
179284 */
180- export function createMiddlewareErrorResponse (
285+ export async function createMiddlewareErrorResponse (
181286 error : Error & { statusCode ?: number } ,
182287 request : Request | EnhancedRequest ,
183- ) : Response {
288+ ) : Promise < Response > {
184289 const status = error . statusCode || 500
185290 const isDevelopment = process . env . APP_ENV !== 'production' && process . env . NODE_ENV !== 'production'
186291
@@ -200,7 +305,7 @@ export function createMiddlewareErrorResponse(
200305
201306 // For 5xx errors in development, show full error page
202307 if ( isDevelopment ) {
203- return createErrorResponse ( error , request , { status } )
308+ return await createErrorResponse ( error , request , { status } )
204309 }
205310
206311 // Production 5xx
@@ -241,16 +346,16 @@ export function createValidationErrorResponse(
241346/**
242347 * Create a 404 Not Found response
243348 */
244- export function createNotFoundResponse (
349+ export async function createNotFoundResponse (
245350 path : string ,
246351 request : Request | EnhancedRequest ,
247- ) : Response {
352+ ) : Promise < Response > {
248353 const isDevelopment = process . env . APP_ENV !== 'production' && process . env . NODE_ENV !== 'production'
249354
250355 if ( isDevelopment ) {
251356 const error = new Error ( `Route not found: ${ path } ` )
252357 error . name = 'NotFoundError'
253- return createErrorResponse ( error , request , { status : 404 } )
358+ return await createErrorResponse ( error , request , { status : 404 } )
254359 }
255360
256361 return new Response ( renderProductionErrorPage ( 404 ) , {
0 commit comments