From 279ee93cbd269c751aa3db9fae6e1e4d28ae197f Mon Sep 17 00:00:00 2001 From: onmax Date: Tue, 30 Jun 2026 08:02:35 +0200 Subject: [PATCH] fix: load env before auth schema config --- src/module/schema.ts | 2 +- src/schema-generator.ts | 15 +++++++++++++++ test/schema-generator.test.ts | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/module/schema.ts b/src/module/schema.ts index 08c71a3..6ea846b 100644 --- a/src/module/schema.ts +++ b/src/module/schema.ts @@ -73,7 +73,7 @@ async function loadAuthOptions(context: SchemaContext) { .filter(([, value]) => typeof value === 'string') .map(([key, value]) => [key, value as string]), ) - const userConfig = await loadUserAuthConfig(configFile, isProduction, alias, context.nuxt.options.runtimeConfig) + const userConfig = await loadUserAuthConfig(configFile, isProduction, alias, context.nuxt.options.runtimeConfig, context.nuxt.options.rootDir) const extendedConfig: { plugins?: BetterAuthPlugin[] } = {} await context.nuxt.callHook('better-auth:config:extend', extendedConfig) diff --git a/src/schema-generator.ts b/src/schema-generator.ts index 45b1c78..e9ff554 100644 --- a/src/schema-generator.ts +++ b/src/schema-generator.ts @@ -1,7 +1,9 @@ import type { BetterAuthOptions } from 'better-auth' import type { Casing } from 'drizzle-orm/utils' +import { existsSync } from 'node:fs' import { generateDrizzleSchema as _generateDrizzleSchema } from '@better-auth/cli/api' import { consola } from 'consola' +import { join } from 'pathe' export interface SchemaOptions { usePlural?: boolean, useUuid?: boolean, casing?: Casing } @@ -59,6 +61,17 @@ interface SchemaGeneratorGlobals { defineServerAuth?: RuntimeDefineServerAuthFn } +function loadLocalEnv(rootDir?: string): void { + if (!rootDir) + return + + const envPath = join(rootDir, '.env.local') + if (!existsSync(envPath)) + return + + process.loadEnvFile(envPath) +} + declare global { // eslint-disable-next-line vars-on-top var __nuxtBetterAuthDefineServerAuth: RuntimeDefineServerAuthFn | undefined @@ -69,6 +82,7 @@ export async function loadUserAuthConfig( throwOnError = false, alias?: Record, runtimeConfig: unknown = {}, + rootDir?: string, ): Promise> { const { createJiti } = await import('jiti') const { defineServerAuth: runtimeDefineServerAuth } = await import('./runtime/config') @@ -85,6 +99,7 @@ export async function loadUserAuthConfig( schemaGlobals.__nuxtBetterAuthDefineServerAuth!._count++ try { + loadLocalEnv(rootDir) const mod = await jiti.import(configPath) as { default?: unknown } const configFn = mod.default if (typeof configFn === 'function') { diff --git a/test/schema-generator.test.ts b/test/schema-generator.test.ts index 89ef4e5..b1700e6 100644 --- a/test/schema-generator.test.ts +++ b/test/schema-generator.test.ts @@ -160,6 +160,30 @@ describe('loadUserAuthConfig', () => { expect(result).toEqual({ appName: '/auth/sign-up' }) }) + + it('loads .env.local before importing auth config dependencies', async () => { + const envPath = join(TEST_DIR, '.env.local') + const helperPath = join(TEST_DIR, 'env-helper.ts') + const configPath = join(TEST_DIR, 'env-config.ts') + const originalApiKey = process.env.RESEND_API_KEY + delete process.env.RESEND_API_KEY + + try { + writeFileSync(envPath, 'RESEND_API_KEY=re_test_fixture\n') + writeFileSync(helperPath, `if (!process.env.RESEND_API_KEY)\n throw new Error('Missing API key. Pass it to the constructor new Resend("re_123")')\n\nexport function getPlugins() { return [] }\n`) + writeFileSync(configPath, `import { getPlugins } from './env-helper'\nexport default defineServerAuth({ plugins: getPlugins() })`) + + const result = await loadUserAuthConfig(configPath, true, undefined, {}, TEST_DIR) + + expect(result).toEqual({ plugins: [] }) + } + finally { + if (originalApiKey === undefined) + delete process.env.RESEND_API_KEY + else + process.env.RESEND_API_KEY = originalApiKey + } + }) }) describe('defineServerAuth', () => {