Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion src/treaty2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,46 @@ const createProxy = (
): any =>
new Proxy(() => {}, {
get(_, param: string): any {
if (param === 'url') {
return (options?: { query?: Record<string, any> }) => {
const methodPaths = [...paths]
if (method.includes(methodPaths.at(-1) as any))
methodPaths.pop()

const path = '/' + methodPaths.join('/')

const query = options?.query

let q = ''
if (query) {
const append = (key: string, value: string) => {
q +=
(q ? '&' : '?') +
`${encodeURIComponent(key)}=${encodeURIComponent(
value
)}`
}

for (const [key, value] of Object.entries(query)) {
if (Array.isArray(value)) {
for (const v of value) append(key, v)
continue
}

if (value === undefined || value === null) continue

if (typeof value === 'object') {
append(key, JSON.stringify(value))
continue
}
append(key, `${value}`)
}
}

return domain + path + q
}
}

return createProxy(
domain,
config,
Expand Down Expand Up @@ -638,4 +678,4 @@ export const treaty = <
return createProxy('http://e.ly', config, [], domain)
}

export type { Treaty }
export type { Treaty }
150 changes: 80 additions & 70 deletions src/treaty2/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,86 +95,96 @@ export namespace Treaty {
: 'Please install Elysia before using Eden'

export type Sign<in out Route extends Record<any, any>> = {
[K in keyof Route as K extends `:${string}`
[K in keyof Route | 'url' as K extends `:${string}`
? never
: K]: K extends 'subscribe' // ? Websocket route
? MaybeEmptyObject<Route['subscribe']['headers'], 'headers'> &
MaybeEmptyObject<
SerializeQueryParams<Route['subscribe']['query']>,
'query'
> extends infer Param
? (options?: Param) => EdenWS<Route['subscribe']>
: never
: Route[K] extends {
body: infer Body
headers: infer Headers
params: any
query: infer Query
response: infer Res extends Record<number, unknown>
}
? MaybeEmptyObject<Headers, 'headers'> &
MaybeEmptyObject<SerializeQueryParams<Query>, 'query'> extends infer Param
? {} extends Param
? undefined extends Body
? K extends 'get' | 'head'
? (
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
: K]: K extends 'url'
? (options?: { query?: Record<string, any> }) => string
: K extends keyof Route
? K extends 'subscribe' // ? Websocket route
? (MaybeEmptyObject<Route['subscribe']['headers'], 'headers'> &
MaybeEmptyObject<
SerializeQueryParams<Route['subscribe']['query']>,
'query'
> extends infer Param
? (options?: Param) => EdenWS<Route['subscribe']>
: never) & {
url: (options?: {
query?: SerializeQueryParams<Route['subscribe']['query']>
}) => string
}
: Route[K] extends {
body: infer Body
headers: infer Headers
params: any
query: infer Query
response: infer Res extends Record<number, unknown>
}
? (MaybeEmptyObject<Headers, 'headers'> &
MaybeEmptyObject<SerializeQueryParams<Query>, 'query'> extends infer Param
? {} extends Param
? undefined extends Body
? K extends 'get' | 'head'
? (
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
: (
body?: RelaxFileArrays<Body>,
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
: K extends 'get' | 'head'
? (
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
: {} extends Body
? (
body?: RelaxFileArrays<Body>,
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
>
: (
body?: RelaxFileArrays<Body>,
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
: (
body: RelaxFileArrays<Body>,
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
>
: K extends 'get' | 'head'
? (
options?: Prettify<Param & TreatyParam>
options: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
: {} extends Body
? (
body?: RelaxFileArrays<Body>,
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
: (
body: RelaxFileArrays<Body>,
options?: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
: K extends 'get' | 'head'
? (
options: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
: (
body: RelaxFileArrays<Body>,
options: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
: (
body: RelaxFileArrays<Body>,
options: Prettify<Param & TreatyParam>
) => Promise<
TreatyResponse<
ReplaceGeneratorWithAsyncGenerator<Res>
>
>
>
: never
: CreateParams<Route[K]>
: never) & {
url: (options?: { query?: SerializeQueryParams<Query> }) => string
}
: CreateParams<Route[K]>
: never
}

type CreateParams<Route extends Record<string, any>> =
Expand Down Expand Up @@ -276,4 +286,4 @@ export namespace Treaty {
export type Error<
Response extends MaybeFunction<MaybePromise<Treaty.TreatyResponse<{}>>>
> = NonNullable<Awaited<UnwrapMaybeFunction<Response>>['error']>
}
}
33 changes: 33 additions & 0 deletions test/treaty2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1222,3 +1222,36 @@ describe('Treaty2 - SSE Chunk Splitting (fast streaming edge cases)', () => {
expect(data).toBe(1)
})
})

describe('Treaty 2 - Using URL Method', () => {
const app = new Elysia()
.get('/ping', () => 'pong')
.get('/user/:id', ({ params: { id } }) => id)
.post('/data', ({ body }) => body, {
query: t.Object({
name: t.String()
})
})

const client = treaty(app)

it('should return base URL', () => {
expect(client.ping.url()).toBe('http://e.ly/ping')
})

it('should return URL with path parameters', () => {
expect(client.user({ id: 1 }).url()).toBe('http://e.ly/user/1')
})

it('should return URL with query parameters', () => {
expect(client.data.url({ query: { name: 'eden' } })).toBe('http://e.ly/data?name=eden')
})

it('should return URL from method proxy', () => {
expect(client.ping.get.url()).toBe('http://e.ly/ping')
})

it('should remove method name from URL when calling from method', () => {
expect(client.user({ id: 2 }).get.url()).toBe('http://e.ly/user/2')
})
})