diff --git a/packages/void/src/plugin-routing.ts b/packages/void/src/plugin-routing.ts index 40858dc3d..7765ae32f 100644 --- a/packages/void/src/plugin-routing.ts +++ b/packages/void/src/plugin-routing.ts @@ -670,7 +670,12 @@ export function routingPlugin(root: string, options: RoutingPluginOptions): Plug const betterAuthSubpaths = ['client', 'react', 'vue', 'svelte', 'solid']; const resolvedAliases = betterAuthSubpaths.flatMap((sub) => { try { - return [{ find: `better-auth/${sub}`, replacement: resolveFile(`better-auth/${sub}`) }]; + return [ + { + find: new RegExp(`^better-auth/${sub}$`), + replacement: resolveFile(`better-auth/${sub}`), + }, + ]; } catch { return []; } diff --git a/packages/void/test/unit/plugin-routing.test.ts b/packages/void/test/unit/plugin-routing.test.ts index 94cd85282..f871f192c 100644 --- a/packages/void/test/unit/plugin-routing.test.ts +++ b/packages/void/test/unit/plugin-routing.test.ts @@ -9,6 +9,7 @@ import { } from 'node:fs'; import { tmpdir } from 'node:os'; import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { createServer, type ConfigEnv, @@ -724,6 +725,35 @@ describe('routingPlugin', () => { expect(hotUpdate.call({ environment: { name: 'void_worker' } })).toBeUndefined(); }); + it('resolves deeper better-auth subpaths past the dev client aliases', async () => { + const root = createTempRoot(); + writeFileSync(join(root, 'routes', 'health.ts'), 'export const GET = () => new Response();'); + const server = await createServer({ + root, + configFile: false, + logLevel: 'silent', + plugins: [createRoutingPlugin(root, { isAuthEnabled: () => true })], + optimizeDeps: { noDiscovery: true }, + server: { middlewareMode: true, ws: false, watch: null, preTransformRequests: false }, + }); + try { + const resolve = async (specifier: string, importer: string) => + (await server.environments.client.pluginContainer.resolveId(specifier, importer))?.id; + const fileOf = (specifier: string) => fileURLToPath(import.meta.resolve(specifier)); + // The app has no better-auth of its own, so these resolve only through the aliases. + const appFile = join(root, 'routes', 'health.ts'); + for (const specifier of ['better-auth/client', 'better-auth/react']) { + expect(await resolve(specifier, appFile)).toBe(fileOf(specifier)); + } + // A deeper subpath passes the aliases and resolves where better-auth is installed. + expect(await resolve('better-auth/client/plugins', fileURLToPath(import.meta.url))).toBe( + fileOf('better-auth/client/plugins'), + ); + } finally { + await server.close(); + } + }); + it('regenerates auth files when the auth config or a file it imports changes', async () => { // Vite's module graph keys files by real path, as the watcher reports them for a real root; // `.native` also expands Windows short names, as Vite does.