From b4f8b8981d6e6e873200f4821bbdc9b42b06aa50 Mon Sep 17 00:00:00 2001 From: onmax Date: Tue, 24 Mar 2026 21:00:10 +0100 Subject: [PATCH 01/12] fix(auth): rebuild nuxthub postgres adapters per request --- src/module/templates.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/module/templates.ts b/src/module/templates.ts index 85f4104..19b4009 100644 --- a/src/module/templates.ts +++ b/src/module/templates.ts @@ -97,7 +97,6 @@ export function createDatabase(event) { registerClientCleanup(event, client) return database } - const client = postgres(hyperdrive.connectionString, { prepare: false, onnotice: () => {}, From 37b17be5599470d7d9f6341f244e5e4946afdf5a Mon Sep 17 00:00:00 2001 From: onmax Date: Thu, 26 Mar 2026 10:11:38 +0100 Subject: [PATCH 02/12] fix(ci): restore plugin inference fixture --- src/runtime/server/utils/auth.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/server/utils/auth.ts b/src/runtime/server/utils/auth.ts index d51a604..0d3e83f 100644 --- a/src/runtime/server/utils/auth.ts +++ b/src/runtime/server/utils/auth.ts @@ -1,6 +1,8 @@ import type { BetterAuthOptions } from 'better-auth' import type { H3Event } from 'h3' +// @ts-ignore Nuxt generates this virtual module in app builds. import { createDatabase, db } from '#auth/database' +// @ts-ignore Nuxt generates this virtual module in app builds. import { createSecondaryStorage } from '#auth/secondary-storage' import createServerAuth from '#auth/server' import { betterAuth } from 'better-auth' From 36c2c6b6e9305416fc929910fa0ccdb906a9a7f7 Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 27 Mar 2026 08:21:45 +0100 Subject: [PATCH 03/12] fix(auth): use nuxt imports in server runtime --- src/runtime/server/utils/auth.ts | 2 +- test/server-auth-database-cache.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/server/utils/auth.ts b/src/runtime/server/utils/auth.ts index 0d3e83f..0df9a62 100644 --- a/src/runtime/server/utils/auth.ts +++ b/src/runtime/server/utils/auth.ts @@ -1,5 +1,6 @@ import type { BetterAuthOptions } from 'better-auth' import type { H3Event } from 'h3' +import { useRuntimeConfig } from '#imports' // @ts-ignore Nuxt generates this virtual module in app builds. import { createDatabase, db } from '#auth/database' // @ts-ignore Nuxt generates this virtual module in app builds. @@ -7,7 +8,6 @@ import { createSecondaryStorage } from '#auth/secondary-storage' import createServerAuth from '#auth/server' import { betterAuth } from 'better-auth' import { getRequestHost, getRequestProtocol } from 'h3' -import { useRuntimeConfig } from 'nitropack/runtime' import { withoutProtocol } from 'ufo' import { resolveCustomSecondaryStorageRequirement } from './custom-secondary-storage' diff --git a/test/server-auth-database-cache.test.ts b/test/server-auth-database-cache.test.ts index 0745945..511935a 100644 --- a/test/server-auth-database-cache.test.ts +++ b/test/server-auth-database-cache.test.ts @@ -23,7 +23,7 @@ vi.mock('better-auth', () => ({ betterAuth: betterAuthMock, })) -vi.mock('nitropack/runtime', () => ({ +vi.mock('#imports', () => ({ useRuntimeConfig: useRuntimeConfigMock, })) From eb477bad19268a9e5d1da52b20b4d670d681ad5a Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 27 Mar 2026 08:24:22 +0100 Subject: [PATCH 04/12] fix(ci): align auth runtime typing stubs --- src/runtime/server/utils/auth.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/runtime/server/utils/auth.ts b/src/runtime/server/utils/auth.ts index 0df9a62..9de9a28 100644 --- a/src/runtime/server/utils/auth.ts +++ b/src/runtime/server/utils/auth.ts @@ -1,11 +1,9 @@ import type { BetterAuthOptions } from 'better-auth' import type { H3Event } from 'h3' -import { useRuntimeConfig } from '#imports' -// @ts-ignore Nuxt generates this virtual module in app builds. import { createDatabase, db } from '#auth/database' -// @ts-ignore Nuxt generates this virtual module in app builds. import { createSecondaryStorage } from '#auth/secondary-storage' import createServerAuth from '#auth/server' +import { useRuntimeConfig } from '#imports' import { betterAuth } from 'better-auth' import { getRequestHost, getRequestProtocol } from 'h3' import { withoutProtocol } from 'ufo' From bf0fb8a18cdd0da6a2fb377fea6f091234f55990 Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 17 Apr 2026 14:08:03 +0200 Subject: [PATCH 05/12] chore(pr): keep hyperdrive fix focused --- .../tsconfig.type-check.json | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/test/cases/plugins-type-inference/tsconfig.type-check.json b/test/cases/plugins-type-inference/tsconfig.type-check.json index 8df8472..609d8fe 100644 --- a/test/cases/plugins-type-inference/tsconfig.type-check.json +++ b/test/cases/plugins-type-inference/tsconfig.type-check.json @@ -1,11 +1,26 @@ { - "extends": "./.nuxt/tsconfig.json", "compilerOptions": { - "noEmit": true + "target": "ESNext", + "lib": [ + "ESNext", + "DOM" + ], + "baseUrl": ".", + "module": "preserve", + "moduleResolution": "bundler", + "paths": { + "#auth/client": ["./app/auth.config"], + "#auth/server": ["./server/auth.config"], + "#nuxt-better-auth": ["../../../src/runtime/types/augment"] + }, + "types": [], + "strict": true, + "noEmit": true, + "skipLibCheck": true }, - "include": [ - "./.nuxt/nuxt.d.ts", - "./virtual-modules.d.ts", + "files": [ + "./.nuxt/types/nuxt-better-auth-infer.d.ts", + "./.nuxt/types/nuxt-better-auth-nitro.d.ts", "./typecheck-target.ts" ] } From 5033583408dbb285d9e9fb5507a733560a9f423d Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 17 Apr 2026 14:09:33 +0200 Subject: [PATCH 06/12] chore(pr): keep auth runtime import unchanged --- src/runtime/server/utils/auth.ts | 2 +- test/server-auth-database-cache.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/server/utils/auth.ts b/src/runtime/server/utils/auth.ts index 9de9a28..d51a604 100644 --- a/src/runtime/server/utils/auth.ts +++ b/src/runtime/server/utils/auth.ts @@ -3,9 +3,9 @@ import type { H3Event } from 'h3' import { createDatabase, db } from '#auth/database' import { createSecondaryStorage } from '#auth/secondary-storage' import createServerAuth from '#auth/server' -import { useRuntimeConfig } from '#imports' import { betterAuth } from 'better-auth' import { getRequestHost, getRequestProtocol } from 'h3' +import { useRuntimeConfig } from 'nitropack/runtime' import { withoutProtocol } from 'ufo' import { resolveCustomSecondaryStorageRequirement } from './custom-secondary-storage' diff --git a/test/server-auth-database-cache.test.ts b/test/server-auth-database-cache.test.ts index 511935a..0745945 100644 --- a/test/server-auth-database-cache.test.ts +++ b/test/server-auth-database-cache.test.ts @@ -23,7 +23,7 @@ vi.mock('better-auth', () => ({ betterAuth: betterAuthMock, })) -vi.mock('#imports', () => ({ +vi.mock('nitropack/runtime', () => ({ useRuntimeConfig: useRuntimeConfigMock, })) From 35c916c4ca9d32b68ea0d7bbd1754240843c8d9e Mon Sep 17 00:00:00 2001 From: onmax Date: Sun, 26 Apr 2026 09:08:11 +0200 Subject: [PATCH 07/12] fix(auth): resolve server auth aliases for typecheck --- package.json | 2 +- src/module/type-templates.ts | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5974507..d17af6e 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "lint": "eslint .", "lint:fix": "eslint . --fix", "typecheck": "vue-tsc --noEmit", - "typecheck:runtime-server": "tsc --noEmit --pretty false -p src/runtime/server/tsconfig.json", + "typecheck:runtime-server": "cd test/cases/plugins-type-inference && nuxi prepare && vue-tsc --noEmit --pretty false -p .nuxt/tsconfig.server.json", "typecheck:playground": "pnpm -C playground exec nuxi prepare && pnpm -C playground exec vue-tsc --noEmit -p .nuxt/tsconfig.app.json", "test": "vitest run", "test:watch": "vitest watch" diff --git a/src/module/type-templates.ts b/src/module/type-templates.ts index 1215477..f061197 100644 --- a/src/module/type-templates.ts +++ b/src/module/type-templates.ts @@ -53,6 +53,26 @@ declare module '#auth/schema' { `, }, { nitro: true }) + addTypeTemplate({ + filename: 'types/nuxt-better-auth-server-context.d.ts', + getContents: () => ` +/// +/// +/// +/// +${hasHubDb ? '/// ' : ''} + +${hasHubDb + ? `declare module '@nuxthub/db' { + export const db: typeof import('#auth/database')['db'] + export const schema: NonNullable +} +` + : ''} +export {} +`, + }, { node: true, shared: true }) + addTypeTemplate({ filename: 'types/nuxt-better-auth-infer.d.ts', getContents: () => ` From 587f024dd5bef4993ac0bf1238b7f31a73e94550 Mon Sep 17 00:00:00 2001 From: onmax Date: Sun, 26 Apr 2026 10:27:18 +0200 Subject: [PATCH 08/12] fix(auth): keep server auth types out of shared refs --- src/module.ts | 29 +++++++++ src/module/type-templates.ts | 65 +++++++++---------- ...-auth-project-references-typecheck.test.ts | 56 +++++++++++++++- 3 files changed, 114 insertions(+), 36 deletions(-) diff --git a/src/module.ts b/src/module.ts index a3e7a5b..b24c7c9 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,6 +1,7 @@ import type { Nuxt } from '@nuxt/schema' import type { BetterAuthModuleOptions } from './runtime/config' import type { BetterAuthDatabaseProviderSetupContext } from './types/hooks' +import { existsSync, readFileSync } from 'node:fs' import { mkdir, writeFile } from 'node:fs/promises' import { addTemplate, createResolver, defineNuxtModule } from '@nuxt/kit' import { consola as _consola } from 'consola' @@ -18,6 +19,33 @@ import './types/hooks' const consola = _consola.withTag('nuxt-better-auth') +function isServerConfigSharedTypeSafe(serverConfigPath: string): boolean { + const resolvedPath = [ + serverConfigPath, + `${serverConfigPath}.ts`, + `${serverConfigPath}.mts`, + `${serverConfigPath}.cts`, + `${serverConfigPath}.js`, + `${serverConfigPath}.mjs`, + `${serverConfigPath}.cjs`, + ].find(path => existsSync(path)) + + if (!resolvedPath) + return false + + const contents = readFileSync(resolvedPath, 'utf8') + + return !( + /from\s+['"]#server/.test(contents) + || /from\s+['"]#layers\//.test(contents) + || /from\s+['"]~~/.test(contents) + || /from\s+['"]@@/.test(contents) + || /\bdb\b/.test(contents) + || /\bsessionHookAfter\b/.test(contents) + || /@nuxthub\/db/.test(contents) + ) +} + async function createDefaultAuthConfigFiles(nuxt: Nuxt): Promise { const configs = resolveAuthConfigDescriptors(nuxt) @@ -136,6 +164,7 @@ export default defineNuxtModule({ serverConfigPath: setup.serverTypes.serverConfigPath, hasHubDb: setup.serverTypes.hasHubDb, runtimeTypesPath: resolver.resolve('./runtime/types'), + sharedServerConfigSafe: isServerConfigSharedTypeSafe(setup.serverTypes.serverConfigPath), }) } diff --git a/src/module/type-templates.ts b/src/module/type-templates.ts index f061197..8489675 100644 --- a/src/module/type-templates.ts +++ b/src/module/type-templates.ts @@ -4,10 +4,14 @@ interface RegisterServerTypeTemplatesInput { serverConfigPath: string hasHubDb: boolean runtimeTypesPath: string + sharedServerConfigSafe: boolean } export function registerServerTypeTemplates(input: RegisterServerTypeTemplatesInput): void { - const { serverConfigPath, hasHubDb, runtimeTypesPath } = input + const { serverConfigPath, hasHubDb, runtimeTypesPath, sharedServerConfigSafe } = input + const serverConfigTypeTemplateOptions = sharedServerConfigSafe + ? { nitro: true, node: true, shared: true } + : { nitro: true, node: true } addTypeTemplate({ filename: 'types/auth-secondary-storage.d.ts', @@ -62,23 +66,38 @@ declare module '#auth/schema' { /// ${hasHubDb ? '/// ' : ''} -${hasHubDb - ? `declare module '@nuxthub/db' { - export const db: typeof import('#auth/database')['db'] - export const schema: NonNullable -} -` - : ''} export {} `, - }, { node: true, shared: true }) + }, { node: true }) + + addTypeTemplate({ + filename: 'types/nuxt-better-auth-config-context.d.ts', + getContents: () => ` +import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth' +import type { RuntimeConfig } from 'nuxt/schema' + +interface _BetterAuthServerConfigContext { + runtimeConfig: RuntimeConfig + db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : 'undefined'} + requestOrigin?: string +} + +declare module '@onmax/nuxt-better-auth/config' { + type ServerAuthConfig = Omit & { + plugins?: readonly BetterAuthPlugin[] + } + export function defineServerAuth(config: (ctx: _BetterAuthServerConfigContext) => R & ServerAuthConfig): (ctx: _BetterAuthServerConfigContext) => R + export function defineServerAuth(config: R & ServerAuthConfig): (ctx: _BetterAuthServerConfigContext) => R +} + +`, + }, { nuxt: true, nitro: true, node: true }) addTypeTemplate({ filename: 'types/nuxt-better-auth-infer.d.ts', getContents: () => ` import type { BetterAuthOptions, BetterAuthPlugin, InferPluginTypes, UnionToIntersection } from 'better-auth' import type { InferFieldsOutput } from 'better-auth/db' -import type { RuntimeConfig } from 'nuxt/schema' import type createServerAuth from '${serverConfigPath}' type _RawConfig = ReturnType @@ -108,30 +127,10 @@ type _SessionFallback = _InferModelFieldsFromPlugins<_RawPlugins, 'session'> & _ declare module '#nuxt-better-auth' { interface AuthUser extends _UserFallback {} interface AuthSession extends _SessionFallback {} - interface ServerAuthContext { - runtimeConfig: RuntimeConfig - db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : 'undefined'} - requestOrigin?: string - } type PluginTypes = InferPluginTypes<_Config> } - -interface _AugmentedServerAuthContext { - runtimeConfig: RuntimeConfig - db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : 'undefined'} - requestOrigin?: string -} - -declare module '@onmax/nuxt-better-auth/config' { - import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth' - type ServerAuthConfig = Omit & { - plugins?: readonly BetterAuthPlugin[] - } - export function defineServerAuth(config: (ctx: _AugmentedServerAuthContext) => R & ServerAuthConfig): (ctx: _AugmentedServerAuthContext) => R - export function defineServerAuth(config: R & ServerAuthConfig): (ctx: _AugmentedServerAuthContext) => R -} `, - }, { nuxt: true, nitro: true, node: true, shared: true }) + }, serverConfigTypeTemplateOptions) addTypeTemplate({ filename: 'types/nuxt-better-auth-social-providers.d.ts', @@ -148,7 +147,7 @@ declare module '#nuxt-better-auth' { } } `, - }, { nuxt: true, nitro: true, node: true, shared: true }) + }, serverConfigTypeTemplateOptions) addTypeTemplate({ filename: 'types/nuxt-better-auth-nitro.d.ts', @@ -346,7 +345,7 @@ declare module 'nitro/types' { } export {} `, - }, { nuxt: true, nitro: true, node: true }) + }, { nitro: true, node: true }) } interface RegisterSharedTypeTemplatesInput { diff --git a/test/server-auth-project-references-typecheck.test.ts b/test/server-auth-project-references-typecheck.test.ts index d8a7649..26b2b27 100644 --- a/test/server-auth-project-references-typecheck.test.ts +++ b/test/server-auth-project-references-typecheck.test.ts @@ -1,5 +1,5 @@ import { spawnSync } from 'node:child_process' -import { existsSync } from 'node:fs' +import { existsSync, readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { beforeAll, describe, expect, it } from 'vitest' @@ -39,12 +39,62 @@ function runProjectReferenceTypecheck(fixtureDir: string) { expect(typecheck.status, `vue-tsc -b failed:\n${typecheck.stdout}\n${typecheck.stderr}`).toBe(0) } +function readGeneratedJson(fixtureDir: string, filePath: string) { + return JSON.parse(readFileSync(`${fixtureDir}/.nuxt/${filePath}`, 'utf8')) +} + +function generatedReferences(fixtureDir: string, filePath: string) { + return (readGeneratedJson(fixtureDir, filePath).references || []) + .map((reference: { path?: string }) => reference.path) + .filter(Boolean) +} + +function expectSharedTypeReferencesToStayClientSafe(fixtureDir: string) { + const sharedReferences = generatedReferences(fixtureDir, 'tsconfig.shared.json') + const serverOnlyReferences = [ + 'types/nuxt-better-auth-server-context.d.ts', + 'types/nuxt-better-auth-config-context.d.ts', + 'types/nuxt-better-auth-infer.d.ts', + 'types/nuxt-better-auth-social-providers.d.ts', + 'types/nuxt-better-auth-nitro.d.ts', + 'types/nitro-imports.d.ts', + 'types/auth-database.d.ts', + 'types/auth-schema.d.ts', + 'types/auth-secondary-storage.d.ts', + 'hub/db.d.ts', + ] + + for (const reference of serverOnlyReferences) + expect(sharedReferences).not.toContain(reference) +} + +function expectServerContextToAvoidNuxthubAugmentation(fixtureDir: string) { + const contents = readFileSync(`${fixtureDir}/.nuxt/types/nuxt-better-auth-server-context.d.ts`, 'utf8') + expect(contents).not.toContain('declare module \'@nuxthub/db\'') + expect(contents).not.toContain('declare module "@nuxthub/db"') +} + +function expectNuxtTypesToStayClientSafe(fixtureDir: string) { + const contents = readFileSync(`${fixtureDir}/.nuxt/nuxt.d.ts`, 'utf8') + expect(contents).not.toContain('types/nuxt-better-auth-infer.d.ts') + expect(contents).not.toContain('types/nuxt-better-auth-social-providers.d.ts') + expect(contents).not.toContain('types/nuxt-better-auth-nitro.d.ts') +} + describe('server auth config project-reference typecheck regression #309', () => { it('typechecks a layered auth config that uses Nitro auto-imported helpers', () => { - runProjectReferenceTypecheck(fileURLToPath(new URL('./cases/layer-server-auth-typecheck', import.meta.url))) + const fixtureDir = fileURLToPath(new URL('./cases/layer-server-auth-typecheck', import.meta.url)) + runProjectReferenceTypecheck(fixtureDir) + expectSharedTypeReferencesToStayClientSafe(fixtureDir) + expectServerContextToAvoidNuxthubAugmentation(fixtureDir) + expectNuxtTypesToStayClientSafe(fixtureDir) }, 60_000) it('typechecks auth config imports that use the #server alias', () => { - runProjectReferenceTypecheck(fileURLToPath(new URL('./cases/server-auth-alias-typecheck', import.meta.url))) + const fixtureDir = fileURLToPath(new URL('./cases/server-auth-alias-typecheck', import.meta.url)) + runProjectReferenceTypecheck(fixtureDir) + expectSharedTypeReferencesToStayClientSafe(fixtureDir) + expectServerContextToAvoidNuxthubAugmentation(fixtureDir) + expectNuxtTypesToStayClientSafe(fixtureDir) }, 60_000) }) From 147bd29c184837ef6421e221f11fc75602a754f9 Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 1 May 2026 11:16:25 +0200 Subject: [PATCH 09/12] test: cover server auth db context typing --- .../server/auth.config.ts | 26 +++++++++++-------- .../server/auth.config.ts | 26 +++++++++++-------- ...-auth-project-references-typecheck.test.ts | 1 + 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts b/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts index 52bbf3a..7fb4084 100644 --- a/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts +++ b/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts @@ -1,16 +1,20 @@ import { defineServerAuth } from '@onmax/nuxt-better-auth/config' -export default defineServerAuth(() => ({ - emailAndPassword: { - enabled: true, - }, - databaseHooks: { - session: { - create: { - async after() { - await sessionHookAfter() +export default defineServerAuth(({ db }) => { + type _DbSelect = typeof db.select + + return { + emailAndPassword: { + enabled: true, + }, + databaseHooks: { + session: { + create: { + async after() { + await sessionHookAfter() + }, }, }, }, - }, -})) + } +}) diff --git a/test/cases/server-auth-alias-typecheck/server/auth.config.ts b/test/cases/server-auth-alias-typecheck/server/auth.config.ts index dde456f..3154ec6 100644 --- a/test/cases/server-auth-alias-typecheck/server/auth.config.ts +++ b/test/cases/server-auth-alias-typecheck/server/auth.config.ts @@ -1,17 +1,21 @@ import { sessionHookAfter } from '#server/utils/hooks' import { defineServerAuth } from '@onmax/nuxt-better-auth/config' -export default defineServerAuth(() => ({ - emailAndPassword: { - enabled: true, - }, - databaseHooks: { - session: { - create: { - async after() { - await sessionHookAfter() +export default defineServerAuth(({ db }) => { + type _DbSelect = typeof db.select + + return { + emailAndPassword: { + enabled: true, + }, + databaseHooks: { + session: { + create: { + async after() { + await sessionHookAfter() + }, }, }, }, - }, -})) + } +}) diff --git a/test/server-auth-project-references-typecheck.test.ts b/test/server-auth-project-references-typecheck.test.ts index 26b2b27..369234f 100644 --- a/test/server-auth-project-references-typecheck.test.ts +++ b/test/server-auth-project-references-typecheck.test.ts @@ -76,6 +76,7 @@ function expectServerContextToAvoidNuxthubAugmentation(fixtureDir: string) { function expectNuxtTypesToStayClientSafe(fixtureDir: string) { const contents = readFileSync(`${fixtureDir}/.nuxt/nuxt.d.ts`, 'utf8') + expect(contents).toContain('types/nuxt-better-auth-config-context.d.ts') expect(contents).not.toContain('types/nuxt-better-auth-infer.d.ts') expect(contents).not.toContain('types/nuxt-better-auth-social-providers.d.ts') expect(contents).not.toContain('types/nuxt-better-auth-nitro.d.ts') From 0e02206e3bd681f669e847af67f51188acb65dd2 Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 1 May 2026 11:36:38 +0200 Subject: [PATCH 10/12] fix(types): augment server auth config context --- src/module/type-templates.ts | 17 +++++------------ src/runtime/config.ts | 6 +++--- .../tsconfig.type-check.json | 2 ++ ...er-auth-project-references-typecheck.test.ts | 11 ++++++++++- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/module/type-templates.ts b/src/module/type-templates.ts index 8489675..cee9564 100644 --- a/src/module/type-templates.ts +++ b/src/module/type-templates.ts @@ -73,25 +73,18 @@ export {} addTypeTemplate({ filename: 'types/nuxt-better-auth-config-context.d.ts', getContents: () => ` -import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth' import type { RuntimeConfig } from 'nuxt/schema' -interface _BetterAuthServerConfigContext { - runtimeConfig: RuntimeConfig - db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : 'undefined'} - requestOrigin?: string -} - declare module '@onmax/nuxt-better-auth/config' { - type ServerAuthConfig = Omit & { - plugins?: readonly BetterAuthPlugin[] + interface ServerAuthContextExtension { + runtimeConfig: RuntimeConfig + db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : 'undefined'} + requestOrigin?: string } - export function defineServerAuth(config: (ctx: _BetterAuthServerConfigContext) => R & ServerAuthConfig): (ctx: _BetterAuthServerConfigContext) => R - export function defineServerAuth(config: R & ServerAuthConfig): (ctx: _BetterAuthServerConfigContext) => R } `, - }, { nuxt: true, nitro: true, node: true }) + }, { nuxt: true, nitro: true, node: true, shared: true }) addTypeTemplate({ filename: 'types/nuxt-better-auth-infer.d.ts', diff --git a/src/runtime/config.ts b/src/runtime/config.ts index fac08b3..0745e59 100644 --- a/src/runtime/config.ts +++ b/src/runtime/config.ts @@ -1,11 +1,11 @@ import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth' import type { BetterAuthClientOptions } from 'better-auth/client' import type { Casing } from 'drizzle-orm/utils' -import type { ServerAuthContext } from './types/augment' +import type { ServerAuthContext as BaseServerAuthContext } from './types/augment' import { createAuthClient } from 'better-auth/vue' -// Re-export for declaration merging with generated types -export type { ServerAuthContext } +export interface ServerAuthContextExtension {} +export type ServerAuthContext = BaseServerAuthContext & ServerAuthContextExtension export interface ClientAuthContext { siteUrl: string diff --git a/test/cases/plugins-type-inference/tsconfig.type-check.json b/test/cases/plugins-type-inference/tsconfig.type-check.json index 609d8fe..d313d6f 100644 --- a/test/cases/plugins-type-inference/tsconfig.type-check.json +++ b/test/cases/plugins-type-inference/tsconfig.type-check.json @@ -19,7 +19,9 @@ "skipLibCheck": true }, "files": [ + "./virtual-modules.d.ts", "./.nuxt/types/nuxt-better-auth-infer.d.ts", + "./.nuxt/types/nuxt-better-auth-social-providers.d.ts", "./.nuxt/types/nuxt-better-auth-nitro.d.ts", "./typecheck-target.ts" ] diff --git a/test/server-auth-project-references-typecheck.test.ts b/test/server-auth-project-references-typecheck.test.ts index 369234f..6de985f 100644 --- a/test/server-auth-project-references-typecheck.test.ts +++ b/test/server-auth-project-references-typecheck.test.ts @@ -53,7 +53,6 @@ function expectSharedTypeReferencesToStayClientSafe(fixtureDir: string) { const sharedReferences = generatedReferences(fixtureDir, 'tsconfig.shared.json') const serverOnlyReferences = [ 'types/nuxt-better-auth-server-context.d.ts', - 'types/nuxt-better-auth-config-context.d.ts', 'types/nuxt-better-auth-infer.d.ts', 'types/nuxt-better-auth-social-providers.d.ts', 'types/nuxt-better-auth-nitro.d.ts', @@ -82,6 +81,14 @@ function expectNuxtTypesToStayClientSafe(fixtureDir: string) { expect(contents).not.toContain('types/nuxt-better-auth-nitro.d.ts') } +function expectSharedTypesToIncludeOnlySafeConfigContext(fixtureDir: string) { + const contents = readFileSync(`${fixtureDir}/.nuxt/nuxt.shared.d.ts`, 'utf8') + expect(contents).toContain('types/nuxt-better-auth-config-context.d.ts') + expect(contents).not.toContain('types/nuxt-better-auth-infer.d.ts') + expect(contents).not.toContain('types/nuxt-better-auth-social-providers.d.ts') + expect(contents).not.toContain('types/nuxt-better-auth-nitro.d.ts') +} + describe('server auth config project-reference typecheck regression #309', () => { it('typechecks a layered auth config that uses Nitro auto-imported helpers', () => { const fixtureDir = fileURLToPath(new URL('./cases/layer-server-auth-typecheck', import.meta.url)) @@ -89,6 +96,7 @@ describe('server auth config project-reference typecheck regression #309', () => expectSharedTypeReferencesToStayClientSafe(fixtureDir) expectServerContextToAvoidNuxthubAugmentation(fixtureDir) expectNuxtTypesToStayClientSafe(fixtureDir) + expectSharedTypesToIncludeOnlySafeConfigContext(fixtureDir) }, 60_000) it('typechecks auth config imports that use the #server alias', () => { @@ -97,5 +105,6 @@ describe('server auth config project-reference typecheck regression #309', () => expectSharedTypeReferencesToStayClientSafe(fixtureDir) expectServerContextToAvoidNuxthubAugmentation(fixtureDir) expectNuxtTypesToStayClientSafe(fixtureDir) + expectSharedTypesToIncludeOnlySafeConfigContext(fixtureDir) }, 60_000) }) From b1798eb4976ea44f7af3e18ef1ebbdde36521dda Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 1 May 2026 11:42:07 +0200 Subject: [PATCH 11/12] fix(types): restore auth config inference in project builds --- src/module/hooks.ts | 12 +++++++++++- src/module/type-templates.ts | 4 ++-- .../server-auth-project-references-typecheck.test.ts | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/module/hooks.ts b/src/module/hooks.ts index 5961394..2a8e986 100644 --- a/src/module/hooks.ts +++ b/src/module/hooks.ts @@ -1,8 +1,9 @@ import type { Nuxt, NuxtPage } from '@nuxt/schema' import type { AuthRouteRules } from '../runtime/types' +import { existsSync, statSync } from 'node:fs' import { addComponentsDir, addImportsDir, addPlugin, addServerHandler, addServerImports, addServerImportsDir, addServerScanDir, extendPages, hasNuxtModule, installModule, updateTemplates } from '@nuxt/kit' import { defu } from 'defu' -import { join } from 'pathe' +import { isAbsolute, join } from 'pathe' import { createRouter, toRouteMatcher } from 'radix3' import { setupDevTools } from '../devtools' @@ -90,6 +91,15 @@ export function registerPrepareTypesHook(input: RegisterPrepareTypesHookInput): nodeTsConfig.compilerOptions.paths[key] = [value] } + for (const [key, value] of Object.entries(nuxt.options.alias)) { + if (typeof value !== 'string' || !isAbsolute(value)) + continue + + nodeTsConfig.compilerOptions.paths[key] ||= [value] + if (!key.includes('*') && existsSync(value) && statSync(value).isDirectory()) + nodeTsConfig.compilerOptions.paths[`${key}/*`] ||= [join(value, '*')] + } + nodeTsConfig.compilerOptions.paths['#server/*'] = [join(serverDir, '*')] for (const path of projectReferenceTypePaths) { diff --git a/src/module/type-templates.ts b/src/module/type-templates.ts index cee9564..29de1d1 100644 --- a/src/module/type-templates.ts +++ b/src/module/type-templates.ts @@ -10,8 +10,8 @@ interface RegisterServerTypeTemplatesInput { export function registerServerTypeTemplates(input: RegisterServerTypeTemplatesInput): void { const { serverConfigPath, hasHubDb, runtimeTypesPath, sharedServerConfigSafe } = input const serverConfigTypeTemplateOptions = sharedServerConfigSafe - ? { nitro: true, node: true, shared: true } - : { nitro: true, node: true } + ? { nuxt: true, nitro: true, node: true, shared: true } + : { nuxt: true, nitro: true, node: true } addTypeTemplate({ filename: 'types/auth-secondary-storage.d.ts', diff --git a/test/server-auth-project-references-typecheck.test.ts b/test/server-auth-project-references-typecheck.test.ts index 6de985f..118e25f 100644 --- a/test/server-auth-project-references-typecheck.test.ts +++ b/test/server-auth-project-references-typecheck.test.ts @@ -76,8 +76,8 @@ function expectServerContextToAvoidNuxthubAugmentation(fixtureDir: string) { function expectNuxtTypesToStayClientSafe(fixtureDir: string) { const contents = readFileSync(`${fixtureDir}/.nuxt/nuxt.d.ts`, 'utf8') expect(contents).toContain('types/nuxt-better-auth-config-context.d.ts') - expect(contents).not.toContain('types/nuxt-better-auth-infer.d.ts') - expect(contents).not.toContain('types/nuxt-better-auth-social-providers.d.ts') + expect(contents).toContain('types/nuxt-better-auth-infer.d.ts') + expect(contents).toContain('types/nuxt-better-auth-social-providers.d.ts') expect(contents).not.toContain('types/nuxt-better-auth-nitro.d.ts') } From 4cca3eaf8e2930c6230c705cc0cb95d6b3211fe3 Mon Sep 17 00:00:00 2001 From: onmax Date: Fri, 1 May 2026 11:48:00 +0200 Subject: [PATCH 12/12] test: satisfy db context lint rule --- .../layer-server-auth-typecheck-base/server/auth.config.ts | 4 ++-- test/cases/server-auth-alias-typecheck/server/auth.config.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts b/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts index 7fb4084..e158894 100644 --- a/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts +++ b/test/cases/layer-server-auth-typecheck-base/server/auth.config.ts @@ -1,7 +1,7 @@ import { defineServerAuth } from '@onmax/nuxt-better-auth/config' -export default defineServerAuth(({ db }) => { - type _DbSelect = typeof db.select +export default defineServerAuth(({ db: _db }) => { + type _DbSelect = typeof _db.select return { emailAndPassword: { diff --git a/test/cases/server-auth-alias-typecheck/server/auth.config.ts b/test/cases/server-auth-alias-typecheck/server/auth.config.ts index 3154ec6..94f5109 100644 --- a/test/cases/server-auth-alias-typecheck/server/auth.config.ts +++ b/test/cases/server-auth-alias-typecheck/server/auth.config.ts @@ -1,8 +1,8 @@ import { sessionHookAfter } from '#server/utils/hooks' import { defineServerAuth } from '@onmax/nuxt-better-auth/config' -export default defineServerAuth(({ db }) => { - type _DbSelect = typeof db.select +export default defineServerAuth(({ db: _db }) => { + type _DbSelect = typeof _db.select return { emailAndPassword: {