Skip to content

Body types reject values whose toJSON() produces the correct wire shape #269

Open

Description

@Yan-Kotliarov

What version of Elysia is running?

No response

What platform is your computer?

No response

What steps can reproduce the bug?

Eden types every request body as the route's static Body, but the runtime sends JSON.stringify(body), and JSON.stringify replaces any value that has toJSON() with its return value. The type checks the object; the wire carries the toJSON() result.

type check     body  ──────────────────────▶  must match Body
runtime        body  ──▶ body.toJSON() ──▶  JSON.stringify  ──▶  must match Body

What is the expected behavior?

Fix: a shared Serializable<T> that accepts either a plain T with no toJSON of its own, or any object whose toJSON() returns the wire shape, applied per field and stopping at values the client never stringifies (File, Blob, FormData, buffers, streams, Date). Type-only change, no runtime impact.

- body: RelaxFileArrays<Body>
+ body: Serializable<RelaxFileArrays<Body>>

What do you see instead?

The two contracts disagree whenever toJSON is present:

class Money {
    toJSON() { return { amount: 1, currency: 'USD' } }
}

api.pay.post(new Money())            // wire ✓ {"amount":1,"currency":"USD"}   type ✗ TS2345
api.order.post({ at: new Date() })   // wire ✓ {"at":"2026-..."}               type ✗ Date is not string

api.pay.post({ amount: 1, currency: 'USD', toJSON: () => 'x' })
                                     // wire ✗ "x"                              type ✓

The Date case is the everyday form: users write date.toISOString() at call sites only to satisfy the compiler. Query params already have a hand-rolled Date → string | Date widening; bodies have none.

Same defect at every site whose value ends in JSON.stringify:

treaty  .post/.put/.patch/.delete body      src/treaty2/types.ts
treaty  .subscribe().send()                 src/treaty2/ws.ts
edenFetch  { body }                         src/fetch/types.ts
edenTreaty (v1) body and EdenWS.send        src/treaty/types.ts, src/treaty/index.ts

Additional information

PRs: #268 (main), #267 (kiana).

Out of scope: the mirror problem on the response side, where a handler returning a toJSON class types data as the class. That serialization happens in Elysia.

Have you try removing the node_modules and bun.lockb and try again yet?

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions