Elysia core itself partially WinterCG compatible, but not all the official plugin works with WinterCG, there are some with Bun specific features, and we want to fix that. We don't have a specific date or version for universal runtime supports yet as we will gradually adopting and test until we make sure that it would works without unexpected behavior. You can looks forward for the following runtime to support: - Node - Deno - Cloudflare Worker We also want to support the following: - Vercel Edge Function - Netlify Function - AWS Lambda / LLRT More over, we also support, and test Elysia on the following frameworks that support Server Side Rendering or Edge Function: - Nextjs - Expo - Astro - SvelteKit In the meantime, there's an [Elysia Polyfills](https://github.com/bogeychan/elysia-polyfills) maintained by Bogeychan, one of an active contributor to Elysia. Additionally, we have rewrote [Eden documentation](/eden/overview) to explain more in depth details about Eden and we think you should check it out. We also improve several pages, and remove redundant part of the documentation, You can check the affected pages on [Elysia 1.0 documentation PR](https://github.com/elysiajs/documentation/pull/282/files). And finally, if you have problems with migration and additional questions related to Elysia, feels free to ask one in Elysia's Discord server. ## Notable Improvement ### Improvement: - fine-grained reactive cookie - using single source of truth for cookie - macro support for websocket - add `mapResolve` - add `{ as: 'global' | 'scoped' | 'local' }` to lifecycle event - add ephemeral type - inline `error` to handler - inline `error` has auto-completion and type checking based on status code - handler now check return type of `error` based on status code - utility `Elysia._types` for types inference - [#495](https://github.com/elysiajs/elysia/issues/495) Provide user friendly error for failed parse - handler now infers return type for error status for Treaty - `t.Date` now allow stringified date - improves type test case - add test case for all life-cycle - resolve, mapResolve, derive, mapDerive use ephemeral type to scope down accurately - inference query dynamic variable ### Breaking Change: - [#513](https://github.com/elysiajs/elysia/issues/513) lifecycle is now local first ### Change: - group private API property - move `Elysia.routes` to `Elysia.router.history` - detect possible json before return - unknown response now return as-is instead of JSON.stringify() - change Elysia validation error to JSON instead of string ### Bug fix: - [#466](https://github.com/elysiajs/elysia/issues/466) Async Derive leaks request context to other requests if `aot: true` - [#505](https://github.com/elysiajs/elysia/issues/505) Empty ObjectString missing validation inside query schema - [#503](https://github.com/elysiajs/elysia/issues/503) Beta: undefined class when using decorate and derive - onStop callback called twice when calling .stop - mapDerive now resolve to `Singleton['derive']` instead of `Singleton['store']` - `ValidationError` doesn't return `content-type` as `application/json` - validate `error(status, value)` validate per status - derive/resolve always scoped to Global - duplicated onError call if not handled - [#516](https://github.com/elysiajs/elysia/issues/516) server timing breaks beforeHandle guards - cookie.remove() doesn't set correct cookie path ## Afterword ::: tip The following contains personal feeling, possibly venting, ranting, possibly cringe and unprofessionalism that shouldn't be written in software release note. You may choose to not continue reading as we have stated all the necessary content for the release. ::: 2 years ago, I have a tragic memory. It's easily one of the most painful memory I have, working days and nights to keeps up with unfair tasks that take advantage from loose contract we had with some software house. It took more than 6 months, and I have to work since I woke up until I sleep (15 hours) on repeat, **without doing anything else not even 5 minutes break for a day**, no time for relax, nothing beside coding for almost 2 months, not even a single break day, not even weekdays that I knocked out and almost have to work in hospital bed. I was souless, no purpose in life at all, my only wish is to make it a dream. At the time, there are so many breaking changes, uncountable new features introduced from loop hole of loose requirement and contract. Keeping track of it is almost impossible, and we even got scammed not even getting the pay we deserved because of "not satisfied", and we couldn't do anything with it. It took me a month to recover from a fear of writing code, being unprofessional I couldn't even do my job properly in trauma and consults my manager that I suffered burn out. That's why we hate breaking change so much, and want to design Elysia to handle changes easily with TypeScript soundness even if it's not good but it's all we have. I don't want anyone to ever experienced something like that. We designed a framework to encounter all the flaws that we had from that contract. The technical flaws I saw in there doesn't have any JavaScript based solution that could satisfies me, yet so I experiment with one. I could just move on as I could avoid loose contract like this in the future, and make money and not spending most of my free time creating a framework but I didn't. There's a my favorite part, [a quote in the animated short](https://youtu.be/v1sd5CzR504?t=128) where Mei is against Kiana of the idea that she would sacrifice herself for the world, and Mei replies:Bun was right, the best way to migrate people from Node is to have compatibility layer and offers better DX, and performance on Bun
— SaltyAom (@saltyAom) March 14, 2024
TypeBox | TypeScript |
```typescript t.String() ``` | ```typescript string ``` |
```typescript t.Number() ``` | ```typescript number ``` |
```typescript t.Boolean() ``` | ```typescript boolean ``` |
```typescript t.Array( t.Number() ) ``` | ```typescript number[] ``` |
```typescript t.Object({ x: t.Number() }) ``` | ```typescript { x: number } ``` |
```typescript t.Null() ``` | ```typescript null ``` |
```typescript t.Literal(42) ``` | ```typescript 42 ``` |
TypeBox | TypeScript |
```typescript t.String({ format: 'email' }) ``` | ```typescript saltyaom@elysiajs.com ``` |
```typescript t.Number({ minimum: 10, maximum: 100 }) ``` | ```typescript 10 ``` |
```typescript t.Array( t.Number(), { /** * Minimum number of items */ minItems: 1, /** * Maximum number of items */ maxItems: 5 } ) ``` | ```typescript [1, 2, 3, 4, 5] ``` |
```typescript t.Object( { x: t.Number() }, { /** * @default false * Accept additional properties * that not specified in schema * but still match the type */ additionalProperties: true } ) ``` | ```typescript x: 100 y: 200 ``` |
TypeBox | TypeScript | Value |
```typescript t.Union([ t.String(), t.Number() ]) ``` | ```typescript string | number ``` | ``` Hello 123 ``` |
TypeBox | TypeScript | Value |
```typescript t.Object({ x: t.Number(), y: t.Optional(t.Number()) }) ``` | ```typescript { x: number, y?: number } ``` | ```typescript { x: 123 } ``` |
TypeBox | TypeScript | Value |
```typescript t.Partial( t.Object({ x: t.Number(), y: t.Number() }) ) ``` | ```typescript { x?: number, y?: number } ``` | ```typescript { y: 123 } ``` |
TypeBox | Error |
```typescript t.String({ format: 'email', error: 'Invalid email :(' }) ``` | ``` Invalid Email :( ``` |
```typescript t.Array( t.String(), { error: 'All members must be a string' } ) ``` | ``` All members must be a string ``` |
```typescript t.Object({ x: t.Number() }, { error: 'Invalid object UwU' }) ``` | ``` Invalid object UwU ``` |
```typescript t.Object({ x: t.Number({ error({ errors, type, validation, value }) { return 'Expected x to be a number' } }) }) ``` | ``` Expected x to be a number ``` |
TypeBox | Error |
```typescript t.String({ format: 'email', error: 'Invalid email :(' }) ``` | ``` Invalid Email :( ``` |
```typescript t.Object({ x: t.Number() }, { error: 'Invalid object UwU' }) ``` | ``` Invalid object UwU ``` |
Code | Body | Error |
```typescript t.Object({ x: t.Number({ error() { return 'Expected x to be a number' } }) }) ``` | ```json { x: "hello" } ``` | Expected x to be a number |
```typescript t.Object({ x: t.Number({ error() { return 'Expected x to be a number' } }) }) ``` | ```json "hello" ``` | (default error, `t.Number.error` is not called) |
```typescript t.Object( { x: t.Number({ error() { return 'Expected x to be a number' } }) }, { error() { return 'Expected value to be an object' } } ) ``` | ```json "hello" ``` | Expected value to be an object |