diff --git a/src/treaty2/index.ts b/src/treaty2/index.ts index 65b866d..c99e1e0 100644 --- a/src/treaty2/index.ts +++ b/src/treaty2/index.ts @@ -204,6 +204,46 @@ const createProxy = ( ): any => new Proxy(() => {}, { get(_, param: string): any { + if (param === 'url') { + return (options?: { query?: Record }) => { + 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, @@ -638,4 +678,4 @@ export const treaty = < return createProxy('http://e.ly', config, [], domain) } -export type { Treaty } +export type { Treaty } \ No newline at end of file diff --git a/src/treaty2/types.ts b/src/treaty2/types.ts index c4f2a2f..9c292cf 100644 --- a/src/treaty2/types.ts +++ b/src/treaty2/types.ts @@ -95,86 +95,96 @@ export namespace Treaty { : 'Please install Elysia before using Eden' export type Sign> = { - [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 & - MaybeEmptyObject< - SerializeQueryParams, - 'query' - > extends infer Param - ? (options?: Param) => EdenWS - : never - : Route[K] extends { - body: infer Body - headers: infer Headers - params: any - query: infer Query - response: infer Res extends Record - } - ? MaybeEmptyObject & - MaybeEmptyObject, 'query'> extends infer Param - ? {} extends Param - ? undefined extends Body - ? K extends 'get' | 'head' - ? ( - options?: Prettify - ) => Promise< - TreatyResponse< - ReplaceGeneratorWithAsyncGenerator + : K]: K extends 'url' + ? (options?: { query?: Record }) => string + : K extends keyof Route + ? K extends 'subscribe' // ? Websocket route + ? (MaybeEmptyObject & + MaybeEmptyObject< + SerializeQueryParams, + 'query' + > extends infer Param + ? (options?: Param) => EdenWS + : never) & { + url: (options?: { + query?: SerializeQueryParams + }) => string + } + : Route[K] extends { + body: infer Body + headers: infer Headers + params: any + query: infer Query + response: infer Res extends Record + } + ? (MaybeEmptyObject & + MaybeEmptyObject, 'query'> extends infer Param + ? {} extends Param + ? undefined extends Body + ? K extends 'get' | 'head' + ? ( + options?: Prettify + ) => Promise< + TreatyResponse< + ReplaceGeneratorWithAsyncGenerator + > + > + : ( + body?: RelaxFileArrays, + options?: Prettify + ) => Promise< + TreatyResponse< + ReplaceGeneratorWithAsyncGenerator + > + > + : K extends 'get' | 'head' + ? ( + options?: Prettify + ) => Promise< + TreatyResponse< + ReplaceGeneratorWithAsyncGenerator + > + > + : {} extends Body + ? ( + body?: RelaxFileArrays, + options?: Prettify + ) => Promise< + TreatyResponse< + ReplaceGeneratorWithAsyncGenerator + > > - > - : ( - body?: RelaxFileArrays, - options?: Prettify - ) => Promise< - TreatyResponse< - ReplaceGeneratorWithAsyncGenerator + : ( + body: RelaxFileArrays, + options?: Prettify + ) => Promise< + TreatyResponse< + ReplaceGeneratorWithAsyncGenerator + > > - > : K extends 'get' | 'head' ? ( - options?: Prettify + options: Prettify ) => Promise< TreatyResponse< ReplaceGeneratorWithAsyncGenerator > > - : {} extends Body - ? ( - body?: RelaxFileArrays, - options?: Prettify - ) => Promise< - TreatyResponse< - ReplaceGeneratorWithAsyncGenerator - > - > - : ( - body: RelaxFileArrays, - options?: Prettify - ) => Promise< - TreatyResponse< - ReplaceGeneratorWithAsyncGenerator - > - > - : K extends 'get' | 'head' - ? ( - options: Prettify - ) => Promise< - TreatyResponse< - ReplaceGeneratorWithAsyncGenerator - > - > - : ( - body: RelaxFileArrays, - options: Prettify - ) => Promise< - TreatyResponse< - ReplaceGeneratorWithAsyncGenerator + : ( + body: RelaxFileArrays, + options: Prettify + ) => Promise< + TreatyResponse< + ReplaceGeneratorWithAsyncGenerator + > > - > - : never - : CreateParams + : never) & { + url: (options?: { query?: SerializeQueryParams }) => string + } + : CreateParams + : never } type CreateParams> = @@ -276,4 +286,4 @@ export namespace Treaty { export type Error< Response extends MaybeFunction>> > = NonNullable>['error']> -} +} \ No newline at end of file diff --git a/test/treaty2.test.ts b/test/treaty2.test.ts index fa31d11..7aab8e8 100644 --- a/test/treaty2.test.ts +++ b/test/treaty2.test.ts @@ -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') + }) +}) \ No newline at end of file