From b1f506dc2d84c24c5e93617b9f3f8f8a5215705d Mon Sep 17 00:00:00 2001 From: Denis Scarabelli <87149177+DenisCDev@users.noreply.github.com> Date: Tue, 10 Mar 2026 16:50:45 -0300 Subject: [PATCH 1/2] :tada: feat: specialize response mapping via AOT compilation for known schema types --- src/adapter/bun/index.ts | 23 +++++++- src/adapter/types.ts | 19 +++++++ src/adapter/web-standard/index.ts | 20 +++++++ src/compose.ts | 93 +++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) diff --git a/src/adapter/bun/index.ts b/src/adapter/bun/index.ts index 6ba8e0f82..7aa71475c 100644 --- a/src/adapter/bun/index.ts +++ b/src/adapter/bun/index.ts @@ -220,7 +220,28 @@ export const BunAdapter: ElysiaAdapter = { ? 'c.headers=c.request.headers.toJSON()\n' : 'c.headers={}\n' + 'for(const [k,v] of c.request.headers.entries())' + - 'c.headers[k]=v\n' + 'c.headers[k]=v\n', + specializedResponse(kind, r, hasSet, saveResponse) { + // Bun's Response.json() is faster than new Response(JSON.stringify()) + switch (kind) { + case 'Object': + case 'Array': + return hasSet + ? `Response.json(${saveResponse}${r},c.set)` + : `Response.json(${saveResponse}${r})` + case 'String': + return hasSet + ? `new Response(${saveResponse}${r},c.set)` + : `new Response(${saveResponse}${r})` + case 'Number': + case 'Boolean': + return hasSet + ? `new Response(${saveResponse}''+${r},c.set)` + : `new Response(${saveResponse}''+${r})` + default: + return undefined + } + } }, listen(app) { return (options, callback) => { diff --git a/src/adapter/types.ts b/src/adapter/types.ts index 364eb5a37..2fa66481d 100644 --- a/src/adapter/types.ts +++ b/src/adapter/types.ts @@ -114,6 +114,25 @@ export interface ElysiaAdapter { declare?: string } > + /** + * Generate specialized inline response code for a known schema type kind. + * + * When the response schema type is known at compile time (e.g. Object, String), + * this generates optimized inline code that bypasses the generic mapResponse + * dispatch chain, eliminating 10+ type checks on the hot path. + * + * @param kind - The TypeBox schema Kind ('Object', 'Array', 'String', 'Number', 'Boolean') + * @param r - Variable name holding the response value + * @param hasSet - Whether set (headers/status/cookie) is active + * @param saveResponse - Code prefix for saving response to context + * @returns Generated fnLiteral string, or undefined to fall back to generic + */ + specializedResponse?: ( + kind: string, + r: string, + hasSet: boolean, + saveResponse: string + ) => string | undefined } composeGeneralHandler: { parameters?: string diff --git a/src/adapter/web-standard/index.ts b/src/adapter/web-standard/index.ts index 43701d0df..8979128f6 100644 --- a/src/adapter/web-standard/index.ts +++ b/src/adapter/web-standard/index.ts @@ -19,6 +19,26 @@ export const WebStandardAdapter: ElysiaAdapter = { composeHandler: { mapResponseContext: 'c.request', preferWebstandardHeaders: true, + specializedResponse(kind, r, hasSet, saveResponse) { + switch (kind) { + case 'Object': + case 'Array': + return hasSet + ? `new Response(JSON.stringify(${saveResponse}${r}),c.set)` + : `new Response(JSON.stringify(${saveResponse}${r}),{headers:{'content-type':'application/json'}})` + case 'String': + return hasSet + ? `new Response(${saveResponse}${r},c.set)` + : `new Response(${saveResponse}${r})` + case 'Number': + case 'Boolean': + return hasSet + ? `new Response(${saveResponse}''+${r},c.set)` + : `new Response(${saveResponse}''+${r})` + default: + return undefined + } + }, // @ts-ignore Bun specific headers: 'c.headers={}\n' + diff --git a/src/compose.ts b/src/compose.ts index 79fec0439..0551baf7c 100644 --- a/src/compose.ts +++ b/src/compose.ts @@ -69,6 +69,50 @@ import { coercePrimitiveRoot } from './replace-schema' const allocateIf = (value: string, condition: unknown) => condition ? value : '' +/** + * Detect the TypeBox schema Kind for single-status-code response schemas. + * + * Used for specialized response code generation during AOT compilation. + * When the response type is known at compile time, we can generate inline + * code that bypasses the generic mapResponse dispatch chain (10+ type checks), + * leveraging: + * - Monomorphic inline caches (V8/JSC optimize single-type call sites) + * - Reduced branch misprediction (fewer conditional branches on hot path) + * - Partial evaluation (specialize code for known input types) + * + * Returns null for unsupported schemas (Union, Intersect, multiple status codes, + * Standard Schema providers), falling back to the generic path. + */ +const getResponseSchemaKind = ( + validator: SchemaValidator +): string | null => { + if (!validator.response) return null + + const keys = Object.keys(validator.response) + if (keys.length !== 1) return null + + const check = validator.response[keys[0]] + if (check.provider === 'standard') return null + + const schema = check.schema + if (!schema?.[Kind]) return null + + switch (schema[Kind]) { + case 'Object': + return 'Object' + case 'String': + return 'String' + case 'Number': + return 'Number' + case 'Boolean': + return 'Boolean' + case 'Array': + return 'Array' + default: + return null + } +} + const defaultParsers = [ 'json', 'text', @@ -880,6 +924,13 @@ export const composeHandler = ({ return (_afterResponse = afterResponse) } + const responseKind = getResponseSchemaKind(validator) + const canSpecialize = + responseKind !== null && + !maybeStream && + !hooks.mapResponse?.length && + adapter.specializedResponse + const mapResponse = (r = 'r') => { const after = afterResponse() // When maybeStream is true, mapResponse may return a Promise (from handleStream) @@ -887,6 +938,48 @@ export const composeHandler = ({ // can properly catch the rejection and route it to error handling. // Only add await if the function is async (maybeAsync), otherwise it would be a syntax error. const awaitStream = maybeStream && maybeAsync ? 'await ' : '' + + if (canSpecialize) { + const fast = adapter.specializedResponse!( + responseKind!, + r, + hasSet, + saveResponse + ) + + if (fast) { + const fallback = `${awaitStream}${hasSet ? 'mapResponse' : 'mapCompactResponse'}(${saveResponse}${r}${hasSet ? ',c.set' : ''}${mapResponseContext})` + + let guard: string + switch (responseKind) { + case 'Object': + guard = `${r}!==null&&${r}!==undefined&&${r}.constructor===Object` + break + case 'Array': + guard = `Array.isArray(${r})` + break + case 'String': + guard = `typeof ${r}==='string'` + break + case 'Number': + guard = `typeof ${r}==='number'` + break + case 'Boolean': + guard = `typeof ${r}==='boolean'` + break + default: + guard = '' + } + + if (guard) { + const response = `(${guard}?${fast}:${fallback})` + + if (!after) return `return ${response}\n` + return `const _res=${response}\n` + after + `return _res` + } + } + } + const response = `${awaitStream}${hasSet ? 'mapResponse' : 'mapCompactResponse'}(${saveResponse}${r}${hasSet ? ',c.set' : ''}${mapResponseContext})\n` if (!after) return `return ${response}` From 0f18be8c4b22267f044c39635c2bff937547af0a Mon Sep 17 00:00:00 2001 From: Denis Scarabelli <87149177+DenisCDev@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:06:10 -0300 Subject: [PATCH 2/2] :wrench: fix: set content-type header on web standard specialized response path --- src/adapter/web-standard/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/adapter/web-standard/index.ts b/src/adapter/web-standard/index.ts index 8979128f6..547cafa44 100644 --- a/src/adapter/web-standard/index.ts +++ b/src/adapter/web-standard/index.ts @@ -24,11 +24,11 @@ export const WebStandardAdapter: ElysiaAdapter = { case 'Object': case 'Array': return hasSet - ? `new Response(JSON.stringify(${saveResponse}${r}),c.set)` + ? `(c.set.headers['content-type']||(c.set.headers['content-type']='application/json'),new Response(JSON.stringify(${saveResponse}${r}),c.set))` : `new Response(JSON.stringify(${saveResponse}${r}),{headers:{'content-type':'application/json'}})` case 'String': return hasSet - ? `new Response(${saveResponse}${r},c.set)` + ? `(c.set.headers['content-type']||(c.set.headers['content-type']='text/plain'),new Response(${saveResponse}${r},c.set))` : `new Response(${saveResponse}${r})` case 'Number': case 'Boolean':