Skip to content

Commit 95f825c

Browse files
committed
🔧 fix: keep mapResponse hooks in the toResponse fast path
1 parent 1c66904 commit 95f825c

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

src/compose.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2529,11 +2529,8 @@ export const composeErrorHandler = (app: AnyElysia) => {
25292529
adapterVariables +
25302530
`}=inject\n`
25312531

2532-
fnLiteral += `return ${
2533-
app.event.error?.find(isAsync) || app.event.mapResponse?.find(isAsync)
2534-
? 'async '
2535-
: ''
2536-
}function(context,error,skipGlobal){`
2532+
// Always make error handler async since toResponse() may return promises
2533+
fnLiteral += `return async function(context,error,skipGlobal){`
25372534

25382535
fnLiteral += ''
25392536

@@ -2598,19 +2595,12 @@ export const composeErrorHandler = (app: AnyElysia) => {
25982595
const saveResponse =
25992596
hasTrace || !!hooks.afterResponse?.length ? 'context.response = ' : ''
26002597

2601-
// Check for toResponse() first to handle errors with custom response methods
2602-
// This takes precedence over onError hooks, as the error defines its own response
2603-
// BUT exclude ValidationError and TransformDecodeError to allow proper validation error handling
26042598
fnLiteral +=
26052599
`if(typeof error?.toResponse==='function'&&error.constructor.name!=="ValidationError"&&error.constructor.name!=="TransformDecodeError"){` +
2606-
`const raw=error.toResponse()\n` +
2607-
`const apply=(resolved)=>{` +
2608-
`if(resolved instanceof Response)set.status=resolved.status\n` +
2609-
afterResponse() +
2610-
`return context.response=context.responseValue=mapResponse(${saveResponse}resolved,set${adapter.mapResponseContext})\n` +
2611-
`}\n` +
2612-
`if(typeof raw?.then==='function')return raw.then(apply)\n` +
2613-
`return apply(raw)\n` +
2600+
`let raw=error.toResponse()\n` +
2601+
`if(typeof raw?.then==='function')raw=await raw\n` +
2602+
`if(raw instanceof Response)set.status=raw.status\n` +
2603+
`context.response=context.responseValue=raw\n` +
26142604
`}\n`
26152605

26162606
if (app.event.error)
@@ -2621,7 +2611,7 @@ export const composeErrorHandler = (app: AnyElysia) => {
26212611
isAsync(handler) ? 'await ' : ''
26222612
}onError[${i}](context)\n`
26232613

2624-
fnLiteral += 'if(skipGlobal!==true){'
2614+
fnLiteral += 'if(skipGlobal!==true&&!context.response){'
26252615

26262616
if (hasReturn(handler)) {
26272617
fnLiteral +=
@@ -2675,7 +2665,7 @@ export const composeErrorHandler = (app: AnyElysia) => {
26752665
`\n}\n`
26762666

26772667
fnLiteral +=
2678-
`if(error instanceof Error){` +
2668+
`if(!context.response&&error instanceof Error){` +
26792669
afterResponse() +
26802670
adapter.unknownError +
26812671
`\n}`

src/dynamic-handle.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,18 @@ export const createDynamicErrorHandler = (app: AnyElysia) => {
684684
const errorContext = Object.assign(context, { error, code: error.code })
685685
errorContext.set = context.set
686686

687-
if (app.event.error)
687+
// @ts-expect-error
688+
if (typeof error?.toResponse === 'function' &&
689+
error.constructor.name !== 'ValidationError' &&
690+
error.constructor.name !== 'TransformDecodeError') {
691+
// @ts-expect-error
692+
let raw = error.toResponse()
693+
if (typeof raw?.then === 'function') raw = await raw
694+
if (raw instanceof Response) context.set.status = raw.status
695+
context.response = raw
696+
}
697+
698+
if (!context.response && app.event.error)
688699
for (let i = 0; i < app.event.error.length; i++) {
689700
const hook = app.event.error[i]
690701
let response = hook.fn(errorContext as any)
@@ -696,6 +707,19 @@ export const createDynamicErrorHandler = (app: AnyElysia) => {
696707
))
697708
}
698709

710+
if (context.response) {
711+
if (app.event.mapResponse)
712+
for (let i = 0; i < app.event.mapResponse.length; i++) {
713+
const hook = app.event.mapResponse[i]
714+
let response = hook.fn(errorContext as any)
715+
if (response instanceof Promise) response = await response
716+
if (response !== undefined && response !== null)
717+
context.response = response
718+
}
719+
720+
return mapResponse(context.response, context.set)
721+
}
722+
699723
return new Response(
700724
typeof error.cause === 'string' ? error.cause : error.message,
701725
{

0 commit comments

Comments
 (0)