Skip to content

Commit c95af80

Browse files
committed
🧹 chore: setImmediate fallback
1 parent 3143445 commit c95af80

File tree

6 files changed

+919
-907
lines changed

6 files changed

+919
-907
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# 1.4.19 - 9 Dec 2025
22
Improvement
33
- [#1588](https://github.com/elysiajs/elysia/pull/1588), [#1587](https://github.com/elysiajs/elysia/pull/1587) add seen weakset during mergeDeep
4-
- [#1607](https://github.com/elysiajs/elysia/issues/1607), [#1606](https://github.com/elysiajs/elysia/issues/1606), [#1139](https://github.com/elysiajs/elysia/issues/1138) nested form data
4+
- [#1607](https://github.com/elysiajs/elysia/issues/1607), [#1606](https://github.com/elysiajs/elysia/issues/1606), [#1139](https://github.com/elysiajs/elysia/issues/1138) data coercion on nested form data
55

66
Bug fix:
77
- [#1591](https://github.com/elysiajs/elysia/pull/1591), [#1590](https://github.com/elysiajs/elysia/pull/1591) merge set.headers without duplicating Response
8+
- add set immediate fallback
89

910
# 1.4.18 - 4 Dec 2025
1011
Security:

example/a.ts

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11
import { Elysia, t } from '../src'
2-
import * as z from 'zod'
3-
import { post, req } from '../test/utils'
42

5-
const app = new Elysia({
6-
cookie: {
7-
domain: "\\` + console.log(c.q='pwn2') }) //"
8-
}
9-
})
10-
.get('/', ({ cookie: { session } }) => 'awd')
11-
12-
console.log(app.routes[0].compile().toString())
13-
14-
const root = await app.handle(
15-
new Request('http://localhost/', {
16-
headers: {
17-
Cookie: 'session=1234'
18-
}
19-
})
20-
)
21-
22-
console.log(await root.text())
3+
new Elysia({ aot: false })
4+
.guard(
5+
{
6+
afterResponse: () => {
7+
console.log('afterResponse')
8+
}
9+
},
10+
(app) => app.get('/test', () => 'afterResponse')
11+
)
12+
.get('/', () => 'hi')

src/compose.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
import {
2020
ELYSIA_REQUEST_ID,
2121
getLoosePath,
22+
hasSetImmediate,
2223
lifeCycleToFn,
2324
randomId,
2425
redirect,
@@ -444,6 +445,10 @@ const coerceTransformDecodeError = (
444445
`throw error.error ?? new ValidationError('${type}',validator.${type},${value},${allowUnsafeValidationDetails})}` +
445446
`}`
446447

448+
const setImmediateFn = hasSetImmediate
449+
? 'setImmediate'
450+
: 'Promise.resolve().then'
451+
447452
export const composeHandler = ({
448453
app,
449454
path,
@@ -804,7 +809,7 @@ export const composeHandler = ({
804809
let afterResponse = ''
805810

806811
afterResponse +=
807-
`\nsetImmediate(async()=>{` +
812+
`\n${setImmediateFn}(async()=>{` +
808813
`if(c.responseValue){` +
809814
`if(c.responseValue instanceof ElysiaCustomStatusResponse) c.set.status=c.responseValue.code\n` +
810815
(hasStream
@@ -1474,21 +1479,26 @@ export const composeHandler = ({
14741479
if (candidate) {
14751480
const isFirst = fileUnions.length === 0
14761481
// Handle case where schema is wrapped in a Union (e.g., ObjectString coercion)
1477-
let properties = candidate.schema?.properties ?? type.properties
1482+
let properties =
1483+
candidate.schema?.properties ?? type.properties
14781484

14791485
// If no properties but schema is a Union, try to find the Object in anyOf
14801486
if (!properties && candidate.schema?.anyOf) {
1481-
const objectSchema = candidate.schema.anyOf.find((s: any) => s.type === 'object')
1487+
const objectSchema =
1488+
candidate.schema.anyOf.find(
1489+
(s: any) => s.type === 'object'
1490+
)
14821491
if (objectSchema) {
14831492
properties = objectSchema.properties
14841493
}
14851494
}
14861495

14871496
if (!properties) continue
14881497

1489-
const iterator = Object.entries(
1490-
properties
1491-
) as [string, TSchema][]
1498+
const iterator = Object.entries(properties) as [
1499+
string,
1500+
TSchema
1501+
][]
14921502

14931503
let validator = isFirst ? '\n' : ' else '
14941504
validator += `if(fileUnions[${fileUnions.length}].Check(c.body)){`
@@ -1773,7 +1783,7 @@ export const composeHandler = ({
17731783
(hasTrace || hooks.afterResponse?.length
17741784
? `afterHandlerStreamListener=stream[2]\n`
17751785
: '') +
1776-
`setImmediate(async ()=>{` +
1786+
`${setImmediateFn}(async ()=>{` +
17771787
`if(listener)for await(const v of listener){}\n`
17781788
handleReporter.resolve()
17791789
fnLiteral += `})` + (maybeAsync ? '' : `})()`) + `}else{`
@@ -2337,7 +2347,7 @@ export const composeGeneralHandler = (app: AnyElysia) => {
23372347

23382348
const prefix = app.event.afterResponse.some(isAsync) ? 'async' : ''
23392349
afterResponse +=
2340-
`\nsetImmediate(${prefix}()=>{` +
2350+
`\n${setImmediateFn}(${prefix}()=>{` +
23412351
`if(c.responseValue instanceof ElysiaCustomStatusResponse) c.set.status=c.responseValue.code\n`
23422352

23432353
for (let i = 0; i < app.event.afterResponse.length; i++) {
@@ -2571,7 +2581,7 @@ export const composeErrorHandler = (app: AnyElysia) => {
25712581

25722582
let afterResponse = ''
25732583
const prefix = hooks.afterResponse?.some(isAsync) ? 'async' : ''
2574-
afterResponse += `\nsetImmediate(${prefix}()=>{`
2584+
afterResponse += `\n${setImmediateFn}(${prefix}()=>{`
25752585

25762586
const reporter = createReport({
25772587
context: 'context',

src/dynamic-handle.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { parseQuery } from './parse-query'
1313
import type { ElysiaTypeCheck } from './schema'
1414
import type { TypeCheck } from './type-system'
1515
import type { Handler, LifeCycleStore, SchemaValidator } from './types'
16-
import { redirect, StatusMap, signCookie } from './utils'
16+
import { hasSetImmediate, redirect, StatusMap, signCookie } from './utils'
1717

1818
// JIT Handler
1919
export type DynamicHandler = {
@@ -79,6 +79,8 @@ export const createDynamicHandler = (app: AnyElysia) => {
7979
response: unknown
8080
}
8181

82+
let hooks: DynamicHandler['hooks']
83+
8284
try {
8385
if (app.event.request)
8486
for (let i = 0; i < app.event.request.length; i++) {
@@ -109,7 +111,8 @@ export const createDynamicHandler = (app: AnyElysia) => {
109111
throw new NotFoundError()
110112
}
111113

112-
const { handle, hooks, validator, content, route } = handler.store
114+
const { handle, validator, content, route } = handler.store
115+
hooks = handler.store.hooks
113116

114117
let body: string | Record<string, any> | undefined
115118
if (request.method !== 'GET' && request.method !== 'HEAD') {
@@ -661,11 +664,22 @@ export const createDynamicHandler = (app: AnyElysia) => {
661664
// @ts-expect-error private
662665
return app.handleError(context, reportedError)
663666
} finally {
664-
if (app.event.afterResponse)
665-
setImmediate(async () => {
666-
for (const afterResponse of app.event.afterResponse!)
667-
await afterResponse.fn(context as any)
668-
})
667+
const afterResponses = hooks!
668+
? hooks.afterResponse
669+
: app.event.afterResponse
670+
671+
if (afterResponses) {
672+
if (hasSetImmediate)
673+
setImmediate(async () => {
674+
for (const afterResponse of afterResponses)
675+
await afterResponse.fn(context as any)
676+
})
677+
else
678+
Promise.resolve().then(async () => {
679+
for (const afterResponse of afterResponses)
680+
await afterResponse.fn(context as any)
681+
})
682+
}
669683
}
670684
}
671685
}

src/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ export const lifeCycleToArray = (a: LifeCycleStore) => {
399399

400400
const isBun = typeof Bun !== 'undefined'
401401
const hasBunHash = isBun && typeof Bun.hash === 'function'
402+
export const hasSetImmediate = typeof setImmediate === 'function'
402403

403404
// https://stackoverflow.com/a/52171480
404405
export const checksum = (s: string) => {

0 commit comments

Comments
 (0)