Skip to content
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 1.4.5 - 15 Sep 2025
Improvement:
- soundness for guard, group
- overwrite primitive value if collide (intersectIfObject)

Bug fix:
- standard schema incorrectly validate cookie and coercion
- merge nested guard, group standalone schema properly

Breaking Change:
- no longer coerce type for .model with `t.Ref` by default

# 1.4.4 - 13 Sep 2025
Bug fix:
- merge schema in GET method
Expand Down
25 changes: 13 additions & 12 deletions example/a.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Elysia } from '../src'
import { Elysia, t } from '../src'
import z from 'zod'
import * as v from 'valibot'
import { req } from '../test/utils'

new Elysia()
.guard({
schema: 'standalone',
body: z.object({
id: z.coerce.number()
})
const app = new Elysia()
.macro('guestOrUser', {
resolve: () => {
return {
user: null
}
}
})
.get('/user/:id', ({ body }) => body, {
body: v.object({
name: v.literal('lilith')
})
.macro('user', {
guestOrUser: true,
body: t.String(),
resolve: ({ body, status, user }) => {}
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "elysia",
"description": "Ergonomic Framework for Human",
"version": "1.4.4",
"version": "1.4.5",
"author": {
"name": "saltyAom",
"url": "https://github.com/SaltyAom",
Expand Down
26 changes: 15 additions & 11 deletions src/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,7 @@ export const composeHandler = ({
)

fnLiteral +=
`const cookieValue={}\n` +
`let cookieValue={}\n` +
`for(const [key,value] of Object.entries(c.cookie))` +
`cookieValue[key]=value.value\n`

Expand All @@ -1513,25 +1513,29 @@ export const composeHandler = ({

if (validator.cookie.provider === 'standard') {
fnLiteral +=
`let vac=validator.cookie.Check(c.body)\n` +
`let vac=validator.cookie.Check(cookieValue)\n` +
`if(vac instanceof Promise)vac=await vac\n` +
`if(vac.issues){` +
validation.validate('cookie', undefined, 'vac.issues') +
'}else{c.body=vac.value}\n'
'}else{cookieValue=vac.value}\n'

fnLiteral +=
`for(const k of Object.keys(cookieValue))` +
`c.cookie[k].value=cookieValue[k]\n`
} else if (validator.body?.schema?.noValidate !== true) {
fnLiteral +=
`if(validator.cookie.Check(cookieValue)===false){` +
validation.validate('cookie', 'cookieValue') +
'}'
}

// if (validator.cookie.hasTransform)
// fnLiteral += coerceTransformDecodeError(
// `for(const [key,value] of Object.entries(validator.cookie.Decode(cookieValue))){` +
// `c.cookie[key].value=value` +
// `}`,
// 'cookie'
// )
if (validator.cookie.hasTransform)
fnLiteral += coerceTransformDecodeError(
`for(const [key,value] of Object.entries(validator.cookie.Decode(cookieValue))){` +
`c.cookie[key].value=value` +
`}`,
'cookie'
)
}
Comment on lines +1531 to +1538
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure propagation for non-standard providers without transform; unify assignment.

After a successful non-standard Check(cookieValue), propagate values into c.cookie even when no transform is present. Also prefer the public setter:

- if (validator.cookie.hasTransform)
+ // Always reflect validated values
+ for (const k of Object.keys(cookieValue))
+   c.cookie[k].value = cookieValue[k]
+
+ if (validator.cookie.hasTransform)
   ${coerceTransformDecodeError(
     `for(const [key,value] of Object.entries(validator.cookie.Decode(cookieValue))){` +
-      `c.cookie[key].value=value` +
+      `c.cookie[key].value=value` +
       `}`,
     'cookie'
   )}

If you prefer minimal churn, I can submit a follow-up PR with tests covering the non-standard provider path.


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Search for occurrences of 'validator.cookie' and 'cookieValue'..."
rg -n --hidden "validator\.cookie" -S || true
rg -n --hidden "\bcookieValue\b" -S || true

echo
echo "Show src/compose.ts around the reported lines (1400-1560):"
if [ -f src/compose.ts ]; then
  sed -n '1400,1560p' src/compose.ts || true
else
  echo "src/compose.ts not found"
fi

Length of output: 6862


Propagate validated cookie values for non-standard providers and unify assignment

When validator.cookie.Check succeeds for non-standard providers we must reflect the validated cookieValue into c.cookie for all keys (use the public .value setter), then let Decode override it when hasTransform is true — current code only updates on hasTransform and uses inconsistent properties.

- if (validator.cookie.hasTransform)
+ // Always reflect validated values
+ for (const k of Object.keys(cookieValue))
+   c.cookie[k].value = cookieValue[k]
+
+ if (validator.cookie.hasTransform)
   ${coerceTransformDecodeError(
     `for(const [key,value] of Object.entries(validator.cookie.Decode(cookieValue))){` +
-      `c.cookie[key].value=value` +
+      `c.cookie[key].value=value` +
       `}`,
     'cookie'
   )}

src/compose.ts (around lines ~1523-1536).

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/compose.ts around lines 1531 to 1538, when validator.cookie.Check
succeeds for non-standard providers we must first propagate the validated
cookieValue into c.cookie for every key using the public .value setter (e.g.,
for(const [k,v] of Object.entries(cookieValue)){ c.cookie[k].value = v }), then
if validator.cookie.hasTransform is true call Decode and let its results
override those same keys (again assigning via the .value setter); replace the
current conditional that only updates on hasTransform and ensure all assignments
use the unified .value property and the coerceTransformDecodeError-wrapped
Decode invocation so transforms still run and override validated values.


if (validator.cookie.isOptional) fnLiteral += `}`
}
Expand Down
Loading
Loading