From 69bc6a38168af9dac5937218f4355cd7bd968222 Mon Sep 17 00:00:00 2001 From: Josh Meads <8870827+joshmeads@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:04:24 -0700 Subject: [PATCH 1/5] fix typescript error for headers.getAll() - https://github.com/oven-sh/bun/issues/9634 --- .gitignore | 1 + test/cookie/response.test.ts | 34 +++++++++++++++++----------------- tsconfig.json | 2 +- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index a05d8b6b..9393e119 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ trace *.tsbuildinfo .wrangler .elysia +.vscode diff --git a/test/cookie/response.test.ts b/test/cookie/response.test.ts index 96f97e4f..8b3a62ac 100644 --- a/test/cookie/response.test.ts +++ b/test/cookie/response.test.ts @@ -20,7 +20,7 @@ const app = new Elysia() (council.value = [ { name: 'Rin', - affilation: 'Administration' + affiliation: 'Administration' } ]), { @@ -29,7 +29,7 @@ const app = new Elysia() t.Array( t.Object({ name: t.String(), - affilation: t.String() + affiliation: t.String() }) ) ) @@ -99,7 +99,7 @@ describe('Cookie Response', () => { const response = await app.handle(req('/council')) expect(getCookies(response)).toEqual([ - 'council=[{"name":"Rin","affilation":"Administration"}]; Path=/' + 'council=[{"name":"Rin","affiliation":"Administration"}]; Path=/' ]) }) @@ -113,7 +113,7 @@ describe('Cookie Response', () => { JSON.stringify([ { name: 'Aoi', - affilation: 'Financial' + affiliation: 'Financial' } ]) ) @@ -122,7 +122,7 @@ describe('Cookie Response', () => { ) expect(getCookies(response)).toEqual([ - 'council=[{"name":"Rin","affilation":"Administration"}]; Path=/' + 'council=[{"name":"Rin","affiliation":"Administration"}]; Path=/' ]) }) @@ -136,7 +136,7 @@ describe('Cookie Response', () => { JSON.stringify([ { name: 'Rin', - affilation: 'Administration' + affiliation: 'Administration' } ]) ) @@ -271,7 +271,7 @@ describe('Cookie Response', () => { cookie: t.Cookie({ council: t.Object({ name: t.String(), - affilation: t.String() + affiliation: t.String() }) }) } @@ -279,7 +279,7 @@ describe('Cookie Response', () => { const expected = { name: 'Rin', - affilation: 'Administration' + affiliation: 'Administration' } const response = await app.handle( @@ -306,7 +306,7 @@ describe('Cookie Response', () => { const expected = { name: 'Rin', - affilation: 'Administration' + affiliation: 'Administration' } const response = await app.handle( @@ -355,7 +355,6 @@ describe('Cookie Response', () => { return 'a' }) - // @ts-expect-error const res = app.handle(req('/')).then((x) => x.headers.toJSON()) // @ts-expect-error @@ -392,13 +391,14 @@ describe('Cookie Response', () => { }) .get('/', () => 'Hello, world!') - const res = await app.handle( - new Request('http://localhost:3000/', { - headers: { - cookie: 'test=Hello, world!' - } - }) - ) + const res = await app + .handle( + new Request('http://localhost:3000/', { + headers: { + cookie: 'test=Hello, world!' + } + }) + ) .then((x) => x.headers) expect(res.getSetCookie()).toEqual([]) diff --git a/tsconfig.json b/tsconfig.json index 99745d91..4b3282cd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ /* Language and Environment */ "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - "lib": ["ESNext"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "lib": ["ESNext", "DOM"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ From 243ba93547636f79c7fe45021d429a063c43f769 Mon Sep 17 00:00:00 2001 From: Josh Meads <8870827+joshmeads@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:14:16 -0700 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=90=9B=20(cookie.ts):=20correct=20spe?= =?UTF-8?q?lling=20of=20'affilation'=20to=20'affiliation'=20=F0=9F=94=A7?= =?UTF-8?q?=20(package.json):=20add=20pretest:node=20script=20to=20ensure?= =?UTF-8?q?=20build=20before=20tests=20=E2=99=BB=EF=B8=8F=20(response.test?= =?UTF-8?q?.ts):=20remove=20unnecessary=20ts-expect-error=20comments=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(elysia.test.ts):=20remove=20unnecessary?= =?UTF-8?q?=20ts-expect-error=20comments=20=E2=99=BB=EF=B8=8F=20(handle-er?= =?UTF-8?q?ror.test.ts):=20remove=20forceErrorEncapsulation=20option=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(modules.test.ts):=20remove=20unused=20esl?= =?UTF-8?q?int-disable=20comment=20=E2=99=BB=EF=B8=8F=20(error.test.ts):?= =?UTF-8?q?=20remove=20unused=20import=20'error'=20=E2=99=BB=EF=B8=8F=20(u?= =?UTF-8?q?tils.ts):=20remove=20unnecessary=20empty=20object=20in=20WebSoc?= =?UTF-8?q?ket=20constructor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/cookie.ts | 4 ++-- package.json | 1 + test/aot/response.test.ts | 30 ++++++++++++++++-------------- test/core/elysia.test.ts | 1 - test/core/handle-error.test.ts | 4 +--- test/core/modules.test.ts | 1 - test/lifecycle/error.test.ts | 9 +-------- test/ws/utils.ts | 2 +- 8 files changed, 22 insertions(+), 30 deletions(-) diff --git a/example/cookie.ts b/example/cookie.ts index be6534a6..9b87e55e 100644 --- a/example/cookie.ts +++ b/example/cookie.ts @@ -12,7 +12,7 @@ const app = new Elysia({ (council.value = [ { name: 'Rin', - affilation: 'Administration' + affiliation: 'Administration' } ]), { @@ -20,7 +20,7 @@ const app = new Elysia({ council: t.Array( t.Object({ name: t.String(), - affilation: t.String() + affiliation: t.String() }) ) }) diff --git a/package.json b/package.json index 5c3ce04e..f8ffcde0 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "test:imports": "bun run ./test/type-system/import.ts", "test:types": "tsc --project tsconfig.test.json", "test:node": "npm install --prefix ./test/node/cjs/ && npm install --prefix ./test/node/esm/ && node ./test/node/cjs/index.js && node ./test/node/esm/index.js && bun dist/bun/index.js", + "pretest:node": "bun run build", "dev": "bun run --watch example/a.ts", "build": "rm -rf dist && bun build.ts", "release": "npm run build && npm run test && npm publish" diff --git a/test/aot/response.test.ts b/test/aot/response.test.ts index 5f8cd936..927a5799 100644 --- a/test/aot/response.test.ts +++ b/test/aot/response.test.ts @@ -6,7 +6,6 @@ import { signCookie } from '../../src/utils' const secrets = 'We long for the seven wailings. We bear the koan of Jericho.' const getCookies = (response: Response) => - // @ts-expect-error response.headers.getAll('Set-Cookie').map((x) => { return decodeURIComponent(x) }) @@ -15,12 +14,12 @@ const app = new Elysia() .get( '/council', ({ cookie: { council } }) => - (council.value = [ + (council.value = JSON.stringify([ { name: 'Rin', - affilation: 'Administration' + affiliation: 'Administration' } - ]) + ])) ) .get('/create', ({ cookie: { name } }) => (name.value = 'Himari')) .get('/multiple', ({ cookie: { name, president } }) => { @@ -64,14 +63,17 @@ describe('Dynamic Cookie Response', () => { it('set multiple cookie', async () => { const response = await app.handle(req('/multiple')) - expect(getCookies(response)).toEqual(['name=Himari; Path=/', 'president=Rio; Path=/']) + expect(getCookies(response)).toEqual([ + 'name=Himari; Path=/', + 'president=Rio; Path=/' + ]) }) it('set JSON cookie', async () => { const response = await app.handle(req('/council')) expect(getCookies(response)).toEqual([ - 'council=[{"name":"Rin","affilation":"Administration"}]; Path=/' + 'council=[{"name":"Rin","affiliation":"Administration"}]; Path=/' ]) }) @@ -85,16 +87,17 @@ describe('Dynamic Cookie Response', () => { JSON.stringify([ { name: 'Aoi', - affilation: 'Financial' + affiliation: 'Financial' } ]) - ) + '; Path=/' + ) + + '; Path=/' } }) ) expect(getCookies(response)).toEqual([ - 'council=[{"name":"Rin","affilation":"Administration"}]; Path=/' + 'council=[{"name":"Rin","affiliation":"Administration"}]; Path=/' ]) }) @@ -108,7 +111,7 @@ describe('Dynamic Cookie Response', () => { JSON.stringify([ { name: 'Rin', - affilation: 'Administration' + affiliation: 'Administration' } ]) ) @@ -201,10 +204,9 @@ describe('Dynamic Cookie Response', () => { const response = await app.handle( req('/update', { headers: { - cookie: `name=${await signCookie( - 'seminar: Himari', - secrets - )}` + '; Path=/' + cookie: + `name=${await signCookie('seminar: Himari', secrets)}` + + '; Path=/' } }) ) diff --git a/test/core/elysia.test.ts b/test/core/elysia.test.ts index ea13d0fc..8c80aaad 100644 --- a/test/core/elysia.test.ts +++ b/test/core/elysia.test.ts @@ -125,7 +125,6 @@ describe('Edge Case', () => { const response = await app .handle(req('/')) - // @ts-expect-error .then((x) => x.headers.toJSON()) expect(response['set-cookie']).toHaveLength(1) diff --git a/test/core/handle-error.test.ts b/test/core/handle-error.test.ts index d988c680..2cb873b0 100644 --- a/test/core/handle-error.test.ts +++ b/test/core/handle-error.test.ts @@ -70,9 +70,7 @@ describe('Handle Error', () => { }) it('inject headers to error', async () => { - const app = new Elysia({ - forceErrorEncapsulation: true - }) + const app = new Elysia() .onRequest(({ set }) => { set.headers['Access-Control-Allow-Origin'] = '*' }) diff --git a/test/core/modules.test.ts b/test/core/modules.test.ts index b3ca3a59..4c3ae330 100644 --- a/test/core/modules.test.ts +++ b/test/core/modules.test.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ import { Elysia } from '../../src' import { describe, expect, it } from 'bun:test' diff --git a/test/lifecycle/error.test.ts b/test/lifecycle/error.test.ts index 80db91c7..91157dac 100644 --- a/test/lifecycle/error.test.ts +++ b/test/lifecycle/error.test.ts @@ -1,12 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { - Elysia, - InternalServerError, - ParseError, - ValidationError, - error, - t -} from '../../src' +import { Elysia, InternalServerError, ParseError, t } from '../../src' import { describe, expect, it } from 'bun:test' import { post, req } from '../utils' diff --git a/test/ws/utils.ts b/test/ws/utils.ts index d1571f97..38bf66ce 100644 --- a/test/ws/utils.ts +++ b/test/ws/utils.ts @@ -1,7 +1,7 @@ import type { Server } from 'bun' export const newWebsocket = (server: Server, path = '/ws') => - new WebSocket(`ws://${server.hostname}:${server.port}${path}`, {}) + new WebSocket(`ws://${server.hostname}:${server.port}${path}`) export const wsOpen = (ws: WebSocket) => new Promise((resolve) => { From 33dd5454ed5043bd3624da6e18403cb914a8da84 Mon Sep 17 00:00:00 2001 From: Josh Meads <8870827+joshmeads@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:56:16 -0700 Subject: [PATCH 3/5] fix ArrayString types + add an extra test for it, fix a few other typing issues with tests --- package.json | 2 +- src/error.ts | 3 +- src/type-system.ts | 105 +++++--------------------- src/utils.ts | 55 +------------- test/lifecycle/error.test.ts | 16 +++- test/macro/macro.test.ts | 1 - test/response/redirect.test.ts | 7 +- test/type-system/array-string.test.ts | 89 +++++++++++----------- test/types/type-system.ts | 1 - 9 files changed, 78 insertions(+), 201 deletions(-) diff --git a/package.json b/package.json index f8ffcde0..54ae9c7b 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "test:imports": "bun run ./test/type-system/import.ts", "test:types": "tsc --project tsconfig.test.json", "test:node": "npm install --prefix ./test/node/cjs/ && npm install --prefix ./test/node/esm/ && node ./test/node/cjs/index.js && node ./test/node/esm/index.js && bun dist/bun/index.js", - "pretest:node": "bun run build", + "pretest:node": "npm run build", "dev": "bun run --watch example/a.ts", "build": "rm -rf dist && bun build.ts", "release": "npm run build && npm run test && npm publish" diff --git a/src/error.ts b/src/error.ts index b401a4ba..7bb5a6ae 100644 --- a/src/error.ts +++ b/src/error.ts @@ -269,8 +269,7 @@ export class ValidationError extends Error { get all() { return 'Errors' in this.validator ? [...this.validator.Errors(this.value)].map(mapValueError) - : // @ts-ignore - [...Value.Errors(this.validator, this.value)].map(mapValueError) + : [...Value.Errors(this.validator, this.value)].map(mapValueError) } static simplifyModel(validator: TSchema | TypeCheck) { diff --git a/src/type-system.ts b/src/type-system.ts index 1cdbed63..5080edc0 100644 --- a/src/type-system.ts +++ b/src/type-system.ts @@ -6,16 +6,16 @@ import { TArray, TDate, TUnsafe, - TypeRegistry + TypeRegistry, + type Static, + type TString, + type TTransform } from '@sinclair/typebox' import { TypeSystem } from '@sinclair/typebox/system' import { Type, type SchemaOptions, - // type TNull, - // type TUnion, type TSchema, - // type TUndefined, TProperties, ObjectOptions, TObject, @@ -98,8 +98,6 @@ const t = Object.assign({}, Type) export namespace ElysiaTypeOptions { export type Numeric = NumberOptions - export type FileUnit = number | `${number}${'k' | 'm'}` - export type StrictFileType = | 'image' | 'image/*' @@ -186,6 +184,8 @@ export namespace ElysiaTypeOptions { */ sign?: Readonly<(keyof T | (string & {}))[]> } + + export type FileUnit = number | `${number}${'k' | 'm'}` } const parseFileUnit = (size: ElysiaTypeOptions.FileUnit) => { @@ -318,8 +318,11 @@ type NonEmptyArray = [T, ...T[]] export type TEnumValue = number | string | null -export interface TUnionEnum | Readonly> = [TEnumValue]> - extends TSchema { +export interface TUnionEnum< + T extends + | NonEmptyArray + | Readonly> = [TEnumValue] +> extends TSchema { type?: 'number' | 'string' | 'null' [Kind]: 'UnionEnum' static: T[number] @@ -542,7 +545,7 @@ export const ElysiaType = { throw new ValidationError('property', schema, value) return JSON.stringify(value) - }) as any as TArray + }) as any as TTransform[]> }, File, Files: (options: ElysiaTypeOptions.Files = {}) => @@ -593,7 +596,11 @@ export const ElysiaType = { return v }, // based on https://github.com/elysiajs/elysia/issues/512#issuecomment-1980134955 - UnionEnum: | Readonly>>( + UnionEnum: < + const T extends + | NonEmptyArray + | Readonly> + >( values: T, options: SchemaOptions = {} ) => { @@ -707,81 +714,3 @@ export { TypeSystemDuplicateTypeKind } from '@sinclair/typebox/system' export { TypeCompiler, TypeCheck } from '@sinclair/typebox/compiler' - -// type Template = -// | string -// | number -// | bigint -// | boolean -// | StringConstructor -// | NumberConstructor -// | undefined - -// type Join = A extends Readonly<[infer First, ...infer Rest]> -// ? ( -// First extends Readonly -// ? First[number] -// : First extends StringConstructor -// ? string -// : First extends NumberConstructor -// ? `${number}` -// : First -// ) extends infer A -// ? Rest extends [] -// ? A extends undefined -// ? NonNullable | '' -// : A -// : // @ts-ignore -// A extends undefined -// ? `${NonNullable}${Join}` | '' -// : // @ts-ignore -// `${A}${Join}` -// : '' -// : '' - -// const template = < -// const T extends Readonly<(Template | Readonly)[]> -// >( -// ...p: T -// ): Join => { -// return a as any -// } - -// const create = -// (t: T): ((t: T) => void) => -// (t) => -// t - -// const optional = < -// const T extends Readonly<(Template | Readonly)[]> -// >( -// ...p: T -// ): T | undefined => { -// return undefined -// } - -// template.optional = optional - -// const hi = create( -// template( -// ['seminar', 'millennium'], -// ':', -// ['Rio', 'Yuuka', 'Noa', 'Koyuki'], -// template.optional(template(',', ['Rio', 'Yuuka', 'Noa', 'Koyuki'])), -// template.optional(template(',', ['Rio', 'Yuuka', 'Noa', 'Koyuki'])), -// template.optional(template(',', ['Rio', 'Yuuka', 'Noa', 'Koyuki'])) -// ) -// ) - -// hi(`seminar:Noa,Koyuki,Yuuka`) - -// const a = TypeCompiler.Compile(t.String()) - -// console.log(v.Decode.toString()) - -// const T = t.Transform(v.schema) -// .Decode((value) => new Date(value)) // required: number to Date -// .Encode((value) => value.getTime()) // required: Date to number - -// const decoded = Value.Decode(T, 0) // const decoded = Date(1970-01-01T00:00:00.000Z) -// const encoded = Value.Encode(T, decoded) diff --git a/src/utils.ts b/src/utils.ts index 4d97c37b..4e9894f3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1428,12 +1428,12 @@ type ElysiaFormData> = FormData & { export const ELYSIA_REQUEST_ID = Symbol('ElysiaRequestId') export type ELYSIA_REQUEST_ID = typeof ELYSIA_REQUEST_ID -export const form = >( +export const form = >( items: T ): ElysiaFormData => { const formData = new FormData() - for (const [key, value] of Object.entries(items)) { + for (const [key, value] of Object.entries(items)) { if (Array.isArray(value)) { for (const v of value) { if (value instanceof File) @@ -1495,54 +1495,3 @@ export const promoteEvent = ( for (const event of events) if ('scope' in event) event.scope = 'global' } - -type PropertyKeys = { - [K in keyof T]: T[K] extends (...args: any[]) => any ? never : K -}[keyof T] - -type PropertiesOnly = Pick> - -// export const classToObject = ( -// instance: T, -// processed: WeakMap = new WeakMap() -// ): T extends object ? PropertiesOnly : T => { -// if (typeof instance !== 'object' || instance === null) -// return instance as any - -// if (Array.isArray(instance)) -// return instance.map((x) => classToObject(x, processed)) as any - -// if (processed.has(instance)) return processed.get(instance) as any - -// const result: Partial = {} - -// for (const key of Object.keys(instance) as Array) { -// const value = instance[key] -// if (typeof value === 'object' && value !== null) -// result[key] = classToObject(value, processed) as T[keyof T] -// else result[key] = value -// } - -// const prototype = Object.getPrototypeOf(instance) -// if (!prototype) return result as any - -// const properties = Object.getOwnPropertyNames(prototype) - -// for (const property of properties) { -// const descriptor = Object.getOwnPropertyDescriptor( -// Object.getPrototypeOf(instance), -// property -// ) - -// if (descriptor && typeof descriptor.get === 'function') { -// // ? Very important to prevent prototype pollution -// if (property === '__proto__') continue - -// ;(result as any)[property as keyof typeof instance] = classToObject( -// instance[property as keyof typeof instance] -// ) -// } -// } - -// return result as any -// } diff --git a/test/lifecycle/error.test.ts b/test/lifecycle/error.test.ts index 91157dac..53d0f0c7 100644 --- a/test/lifecycle/error.test.ts +++ b/test/lifecycle/error.test.ts @@ -53,10 +53,18 @@ describe('error', () => { if (code === 'VALIDATION') { set.status = 400 - return error.all.map((i) => ({ - filed: i.path.slice(1) || 'root', - reason: i.message - })) + return error.all.map((i) => { + if ('path' in i) { + return { + filed: i.path.slice(1) || 'root', + reason: i.message + } + } + return { + filed: 'root', + reason: i.summary + } + }) } }) .post('/login', ({ body }) => body, { diff --git a/test/macro/macro.test.ts b/test/macro/macro.test.ts index 46cb2763..2e198d3d 100644 --- a/test/macro/macro.test.ts +++ b/test/macro/macro.test.ts @@ -484,7 +484,6 @@ describe('Macro', () => { const called = [] const plugin = new Elysia().get('/hello', () => 'hello', { - // @ts-expect-error missing type reference hello: 'nagisa' }) diff --git a/test/response/redirect.test.ts b/test/response/redirect.test.ts index 12d568aa..0bf07fb4 100644 --- a/test/response/redirect.test.ts +++ b/test/response/redirect.test.ts @@ -1,4 +1,4 @@ -import { Elysia } from '../../src' +import { Elysia, t } from '../../src' import { describe, expect, it } from 'bun:test' import { req } from '../utils' @@ -10,7 +10,6 @@ describe('Response Redirect', () => { const { headers, status } = await app.handle(req('/')) expect(status).toBe(302) - // @ts-expect-error expect(headers.toJSON()).toEqual({ location: '/skadi' }) @@ -24,7 +23,6 @@ describe('Response Redirect', () => { const { headers, status } = await app.handle(req('/')) expect(status).toBe(301) - // @ts-expect-error expect(headers.toJSON()).toEqual({ location: '/skadi' }) @@ -40,7 +38,6 @@ describe('Response Redirect', () => { const { headers, status } = await app.handle(req('/')) expect(status).toBe(302) - // @ts-expect-error expect(headers.toJSON()).toEqual({ location: '/skadi', alias: 'Abyssal Hunter' @@ -61,9 +58,9 @@ describe('Response Redirect', () => { const { headers, status } = await app.handle(req('/')) expect(status).toBe(302) - // @ts-expect-error expect(headers.toJSON()).toEqual({ location: '/skadi', + // @ts-expect-error - Unsure where this comes from, set cookie can return an array. Maybe the type is expecting comma separated values? 'set-cookie': ['name=a; Path=/', 'name2=b; Path=/'] }) }) diff --git a/test/type-system/array-string.test.ts b/test/type-system/array-string.test.ts index bd1ba74d..5c79ae37 100644 --- a/test/type-system/array-string.test.ts +++ b/test/type-system/array-string.test.ts @@ -1,15 +1,20 @@ import Elysia, { t } from '../../src' import { describe, expect, it } from 'bun:test' import { Value } from '@sinclair/typebox/value' -import { TBoolean, TString, TypeBoxError } from '@sinclair/typebox' -import { req } from '../utils' describe('TypeSystem - ArrayString', () => { it('Create', () => { - expect(Value.Create(t.ArrayString())).toBe('[]') + const value = Value.Create(t.ArrayString()) + expect(value).toBe('[]') }) - it('Check', () => { + it('Check - String', () => { + const schema = t.ArrayString(t.Number()) + + expect(Value.Check(schema, '[1]')).toBe(true) + }) + + it('Check - Cast', () => { const schema = t.ArrayString(t.Number()) expect(Value.Check(schema, [1])).toBe(true) @@ -18,63 +23,55 @@ describe('TypeSystem - ArrayString', () => { it('Encode', () => { const schema = t.ArrayString(t.Number()) - expect( - Value.Encode(schema, [1]) - ).toBe(JSON.stringify([1])) + expect(Value.Encode(schema, [1])).toBe( + JSON.stringify([1]) + ) - expect( - Value.Encode(schema, [1]) - ).toBe(JSON.stringify([1])) + expect(Value.Encode(schema, [1])).toBe( + JSON.stringify([1]) + ) }) it('Decode', () => { const schema = t.ArrayString(t.Number()) - expect( - Value.Decode( - schema, - '[1]' - ) - ).toEqual([1]) + expect(Value.Decode(schema, '[1]')).toEqual([1]) - expect(() => - Value.Decode( - schema, - '1' - ) - ).toThrow() + expect(() => Value.Decode(schema, '1')).toThrow() }) it('Integrate', async () => { - const app = new Elysia().post( - '/', - ({ body }) => body, - { - body: t.Object({ - id: t.ArrayString(t.Number()) - }) - } - ) + const app = new Elysia().post('/', ({ body }) => body, { + body: t.Object({ + id: t.ArrayString(t.Number()) + }) + }) - const res1 = await app.handle(new Request('http://localhost', { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ id: JSON.stringify([1, 2, 3]) }) - })) + const res1 = await app.handle( + new Request('http://localhost', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id: JSON.stringify([1, 2, 3]) }) + }) + ) expect(res1.status).toBe(200) - const res2 = await app.handle(new Request('http://localhost', { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ id: [1, 2, 3] }) - })) + const res2 = await app.handle( + new Request('http://localhost', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id: [1, 2, 3] }) + }) + ) expect(res2.status).toBe(200) - const res3 = await app.handle(new Request('http://localhost', { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ id: ['a', 2, 3] }) - })) + const res3 = await app.handle( + new Request('http://localhost', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id: ['a', 2, 3] }) + }) + ) expect(res3.status).toBe(422) }) }) diff --git a/test/types/type-system.ts b/test/types/type-system.ts index 6d24da47..13a82436 100644 --- a/test/types/type-system.ts +++ b/test/types/type-system.ts @@ -3,7 +3,6 @@ import { expect } from 'bun:test' import { t, Elysia, RouteSchema, Cookie } from '../../src' import { expectTypeOf } from 'expect-type' -// ? ArrayString { new Elysia().post( '/', From 6fdf5aeb39076e61dc81a22745fd6b3747cc7ae4 Mon Sep 17 00:00:00 2001 From: Josh Meads <8870827+joshmeads@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:29:12 -0700 Subject: [PATCH 4/5] fix remaining typescript errors, DOM and DOM.Iterable are required for headers.keys() and headers.getAll() --- src/handler.ts | 14 +++----------- test/validator/query.test.ts | 1 - tsconfig.json | 2 +- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index fedb8d73..aa0555be 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -6,7 +6,7 @@ import { StatusMap } from './utils' import { Cookie } from './cookies' import type { Context } from './context' -import type { LocalHook } from './types' +import type { HTTPHeaders, LocalHook } from './types' import { ElysiaCustomStatusResponse } from './error' const hasHeaderShorthand = 'toJSON' in new Headers() @@ -112,14 +112,6 @@ export const serializeCookie = (cookies: Context['set']['cookie']) => { return set } -// const concatUint8Array = (a: Uint8Array, b: Uint8Array) => { -// const arr = new Uint8Array(a.length + b.length) -// arr.set(a, 0) -// arr.set(b, a.length) - -// return arr -// } - const handleStream = async ( generator: Generator | AsyncGenerator, set?: Context['set'], @@ -196,8 +188,8 @@ const handleStream = async ( // Manually set transfer-encoding for direct response, eg. app.handle, eden 'transfer-encoding': 'chunked', 'content-type': 'text/event-stream; charset=utf-8', - ...set?.headers - } + ...((set?.headers || {}) as HTTPHeaders) + } as Record | [string, string][] | Headers } ) } diff --git a/test/validator/query.test.ts b/test/validator/query.test.ts index 58fe5461..3617393d 100644 --- a/test/validator/query.test.ts +++ b/test/validator/query.test.ts @@ -281,7 +281,6 @@ describe('Query Validator', () => { check() { const { state } = ctx.query - // @ts-expect-error if (!checker.check(ctx, name, state ?? ctx.query.state)) throw new Error('State mismatch') } diff --git a/tsconfig.json b/tsconfig.json index 4b3282cd..406f6c0b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ /* Language and Environment */ "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - "lib": ["ESNext", "DOM"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "lib": ["ESNext", "DOM", "DOM.Iterable"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ From 8250fe25186fb426eb81da0e42312447a4cf59c9 Mon Sep 17 00:00:00 2001 From: Josh Meads <8870827+joshmeads@users.noreply.github.com> Date: Thu, 24 Oct 2024 20:20:31 -0700 Subject: [PATCH 5/5] fix examples types --- example/custom-response.ts | 14 ++++++++------ example/video.ts | 6 ++---- example/websocket.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/example/custom-response.ts b/example/custom-response.ts index 9add8f89..d01d4533 100644 --- a/example/custom-response.ts +++ b/example/custom-response.ts @@ -1,11 +1,13 @@ import { Elysia } from '../src' -const prettyJson = new Elysia().onAfterHandle(({ response }) => { - if (response instanceof Object) - try { - return JSON.stringify(response, null, 4) - } catch {} -}) +const prettyJson = new Elysia().onAfterHandle( + ({ response }: { response: unknown }) => { + if (response instanceof Object) + try { + return JSON.stringify(response, null, 4) + } catch {} + } +) new Elysia() .use(prettyJson) diff --git a/example/video.ts b/example/video.ts index 90a450bb..bbd1a1fd 100644 --- a/example/video.ts +++ b/example/video.ts @@ -1,5 +1,3 @@ -import { Elysia } from 'elysia' +import { Elysia } from '../src' -new Elysia() - .get('/', Bun.file('test/kyuukurarin.mp4')) - .listen(3000) +new Elysia().get('/', Bun.file('test/kyuukurarin.mp4')).listen(3000) diff --git a/example/websocket.ts b/example/websocket.ts index 1cd09ad9..8c4125e7 100644 --- a/example/websocket.ts +++ b/example/websocket.ts @@ -12,7 +12,7 @@ const app = new Elysia() }, message(ws, message) { ws.publish('asdf', message) - ws.send('asdf', message) + ws.send(message) } }) .get('/publish/:publish', ({ params: { publish: text } }) => {