From 7f0e781fb9e2b5bdba5c81f29025969cb5dc9598 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 24 Aug 2026 20:43:23 +0000 Subject: [PATCH] feat(core): allow hosts to override the client auth banner --- .../src/node/__tests__/auth-handler.test.ts | 44 +++++++++++++++++++ packages/core/src/node/auth-handler.ts | 5 ++- packages/core/src/node/config.ts | 8 ++++ .../@vitejs/devtools/config.snapshot.d.ts | 1 + 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/node/__tests__/auth-handler.test.ts diff --git a/packages/core/src/node/__tests__/auth-handler.test.ts b/packages/core/src/node/__tests__/auth-handler.test.ts new file mode 100644 index 000000000..2f6867d8b --- /dev/null +++ b/packages/core/src/node/__tests__/auth-handler.test.ts @@ -0,0 +1,44 @@ +import type { ResolvedConfig } from 'vite' +import type { DevToolsConfig } from '../config' +import process from 'node:process' +import { describe, expect, it, vi } from 'vitest' +import { getAuthHandler } from '../auth-handler' +import { createDevToolsContext } from '../context' +import '@vitejs/devtools-kit' + +function createConfig(config?: Partial): ResolvedConfig { + return { + root: process.cwd(), + command: 'serve', + plugins: [], + server: { port: 5173 }, + devtools: config === undefined ? undefined : { config }, + } as unknown as ResolvedConfig +} + +describe('getAuthHandler banner', () => { + it('forwards a configured banner to the interactive auth handler', async () => { + const banner = vi.fn() + const ctx = await createDevToolsContext(createConfig({ banner })) + + getAuthHandler(ctx).printBanner() + + expect(banner).toHaveBeenCalledTimes(1) + const [info] = banner.mock.calls[0]! + expect(info.code).toMatch(/\S/) + expect(info.url).toContain(info.code) + }) + + it('falls back to the default stdout banner when unset', async () => { + const log = vi.spyOn(console, 'log').mockImplementation(() => {}) + const ctx = await createDevToolsContext(createConfig()) + + try { + getAuthHandler(ctx).printBanner() + expect(log).toHaveBeenCalled() + } + finally { + log.mockRestore() + } + }) +}) diff --git a/packages/core/src/node/auth-handler.ts b/packages/core/src/node/auth-handler.ts index 42d8eaee7..c67f1303d 100644 --- a/packages/core/src/node/auth-handler.ts +++ b/packages/core/src/node/auth-handler.ts @@ -1,4 +1,5 @@ import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit' +import type { DevToolsConfig } from './config' import process from 'node:process' import { createInteractiveAuth } from 'devframe/recipes/interactive-auth' @@ -17,8 +18,10 @@ const handlers = new WeakMap() export function getAuthHandler(context: ViteDevToolsNodeContext): DevToolsAuthHandler { let handler = handlers.get(context) if (!handler) { + const config = context.viteConfig.devtools?.config as DevToolsConfig | undefined handler = createInteractiveAuth(context, { - clientAuthTokens: context.viteConfig.devtools?.config?.clientAuthTokens, + clientAuthTokens: config?.clientAuthTokens, + banner: config?.banner, }) handlers.set(context, handler) } diff --git a/packages/core/src/node/config.ts b/packages/core/src/node/config.ts index 721c72eac..bcde84845 100644 --- a/packages/core/src/node/config.ts +++ b/packages/core/src/node/config.ts @@ -1,3 +1,4 @@ +import type { CreateInteractiveAuthOptions } from 'devframe/recipes/interactive-auth' import type { StartOptions } from './cli-commands' export type DevToolsApply = 'serve' | 'build' | 'all' @@ -35,6 +36,13 @@ export interface DevToolsConfig extends Partial { * will be auto-approved without a terminal prompt. */ clientAuthTokens?: string[] + /** + * Print the one-time code and magic-link URL somewhere other than stdout. + * + * The default banner is a boxed `console.log` from inside the dev server. + * Supply this to surface the code in the host's own chrome instead. + */ + banner?: CreateInteractiveAuthOptions['banner'] /** * Origins allowed to open the DevTools WebSocket connection, in addition to the built-in * loopback allowlist (`localhost`, `127.0.0.1`, etc). diff --git a/test/__snapshots__/tsnapi/@vitejs/devtools/config.snapshot.d.ts b/test/__snapshots__/tsnapi/@vitejs/devtools/config.snapshot.d.ts index 07844e34c..58e68b9c3 100644 --- a/test/__snapshots__/tsnapi/@vitejs/devtools/config.snapshot.d.ts +++ b/test/__snapshots__/tsnapi/@vitejs/devtools/config.snapshot.d.ts @@ -8,6 +8,7 @@ export interface DevToolsConfig extends Partial { environments?: string[]; clientAuth?: boolean; clientAuthTokens?: string[]; + banner?: CreateInteractiveAuthOptions['banner']; allowedOrigins?: string[]; } export interface ResolvedDevToolsConfig {