From 167506007a3e20ea9b904fabe4d4fbb9716ae7dd Mon Sep 17 00:00:00 2001 From: rafia9005 Date: Fri, 20 Mar 2026 11:32:01 +0700 Subject: [PATCH] fix: mount(handler) with prefix should strip prefix from path When using mount(handler) without an explicit path on an Elysia instance with a prefix (e.g., new Elysia({ prefix: '/api' }).mount(handler)), the mounted handler was receiving the full path including the prefix instead of having the prefix stripped. This caused issues when integrating libraries like Better Auth which expect the path to start from their basePath, not from the full URL path. Fixes #1806 --- src/index.ts | 29 ++++++++++++++++++++++++----- test/core/mount.test.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index 342a47a1..4bb5e0b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -162,7 +162,7 @@ import type { UnknownRouteSchema, MaybeFunction, InlineHandlerNonMacro, - Router, + Router } from './types' import { coercePrimitiveRoot, @@ -4703,7 +4703,12 @@ export default class Elysia< } = hook const hasStandaloneSchema = - body || headers || query || params || cookie || response + body || + headers || + query || + params || + cookie || + response const startIndex = processedUntil processedUntil = instance.router.history.length @@ -4731,11 +4736,13 @@ export default class Elysia< : Array.isArray(localHook.error) ? [ ...(localHook.error ?? []), - ...(sandbox.event.error ?? []) + ...(sandbox.event.error ?? + []) ] : [ localHook.error, - ...(sandbox.event.error ?? []) + ...(sandbox.event.error ?? + []) ], standaloneValidator: !hasStandaloneSchema ? localHook.standaloneValidator @@ -5655,8 +5662,20 @@ export default class Elysia< throw new Error('Invalid handler') })() + const prefix = this.config.prefix + const prefixLength = prefix?.length ?? 0 const handler: Handler = ({ request, path }) => - run(new Request(replaceUrlPath(request.url, path), request)) + run( + new Request( + replaceUrlPath( + request.url, + prefixLength + ? path.slice(prefixLength) || '/' + : path + ), + request + ) + ) this.route('ALL', '/*', handler as any, { parse: 'none', diff --git a/test/core/mount.test.ts b/test/core/mount.test.ts index 00c9b332..7b72bdd7 100644 --- a/test/core/mount.test.ts +++ b/test/core/mount.test.ts @@ -228,4 +228,34 @@ describe('Mount', () => { expect(response.status).toBe(302) expect(response.headers.get('location')).toBe('/redirect') }) + + // https://github.com/elysiajs/elysia/issues/1806 + it('mount(handler) with prefix should strip prefix from path', async () => { + const plugin = new Elysia({ prefix: '/api' }).mount((request) => { + return Response.json({ path: new URL(request.url).pathname }) + }) + + const app = new Elysia().use(plugin) + + const response = await app + .handle(new Request('http://localhost/api/auth/dash/users')) + .then((x) => x.json() as Promise<{ path: string }>) + + expect(response.path).toBe('/auth/dash/users') + }) + + // https://github.com/elysiajs/elysia/issues/1806 + it('mount(handler) with prefix should handle root path', async () => { + const plugin = new Elysia({ prefix: '/api' }).mount((request) => { + return Response.json({ path: new URL(request.url).pathname }) + }) + + const app = new Elysia().use(plugin) + + const response = await app + .handle(new Request('http://localhost/api/')) + .then((x) => x.json() as Promise<{ path: string }>) + + expect(response.path).toBe('/') + }) })