@onmax/nuxt-better-auth 0.0.2-alpha.31 → 0.0.2-alpha.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +60 -17
  2. package/dist/module.json +2 -2
  3. package/dist/module.mjs +580 -261
  4. package/dist/runtime/app/components/BetterAuthState.d.vue.ts +4 -4
  5. package/dist/runtime/app/components/BetterAuthState.vue +1 -1
  6. package/dist/runtime/app/components/BetterAuthState.vue.d.ts +4 -4
  7. package/dist/runtime/app/composables/useAuthClient.d.ts +9 -0
  8. package/dist/runtime/app/composables/useAuthClient.js +34 -0
  9. package/dist/runtime/app/composables/useAuthClientAction.d.ts +1 -3
  10. package/dist/runtime/app/composables/useAuthClientAction.js +2 -2
  11. package/dist/runtime/app/composables/useAuthRequestFetch.d.ts +1 -1
  12. package/dist/runtime/app/composables/useSignIn.js +2 -2
  13. package/dist/runtime/app/composables/useSignUp.js +2 -2
  14. package/dist/runtime/app/composables/useUserSession.d.ts +5 -4
  15. package/dist/runtime/app/composables/useUserSession.js +62 -69
  16. package/dist/runtime/app/composables/useUserSessionState.d.ts +3 -0
  17. package/dist/runtime/app/composables/useUserSessionState.js +4 -0
  18. package/dist/runtime/app/internal/session-fetch.d.ts +1 -1
  19. package/dist/runtime/app/internal/vue-safe-auth-proxy.d.ts +3 -0
  20. package/dist/runtime/app/internal/vue-safe-auth-proxy.js +68 -0
  21. package/dist/runtime/app/middleware/auth.global.js +5 -4
  22. package/dist/runtime/app/plugins/session.client.js +2 -1
  23. package/dist/runtime/composables.d.ts +11 -0
  24. package/dist/runtime/composables.js +9 -0
  25. package/dist/runtime/config.d.ts +4 -2
  26. package/dist/runtime/server/api/_better-auth/_schema.d.ts +1 -5
  27. package/dist/runtime/server/api/_better-auth/accounts.get.d.ts +2 -2
  28. package/dist/runtime/server/api/_better-auth/config.get.js +1 -1
  29. package/dist/runtime/server/api/_better-auth/sessions.get.d.ts +2 -2
  30. package/dist/runtime/server/api/_better-auth/users.get.d.ts +2 -2
  31. package/dist/runtime/server/middleware/route-access.js +1 -1
  32. package/dist/runtime/server/utils/auth.d.ts +13 -2
  33. package/dist/runtime/server/utils/auth.js +42 -16
  34. package/dist/runtime/server/utils/session.d.ts +3 -1
  35. package/dist/runtime/server/utils/session.js +175 -1
  36. package/dist/runtime/server/virtual-modules.d.ts +5 -0
  37. package/dist/runtime/types/augment.d.ts +1 -3
  38. package/dist/runtime/types.d.ts +1 -1
  39. package/package.json +28 -12
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync, writeFileSync, readFileSync } from 'node:fs';
1
+ import { existsSync, statSync, writeFileSync, readFileSync } from 'node:fs';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
3
  import { getLayerDirectories, updateTemplates, addServerImportsDir, addServerImports, addServerScanDir, addServerHandler, addImportsDir, addPlugin, addComponentsDir, hasNuxtModule, installModule, extendPages, addTemplate, addTypeTemplate, defineNuxtModule, createResolver } from '@nuxt/kit';
4
4
  import { consola as consola$1 } from 'consola';
@@ -10,17 +10,7 @@ import { randomBytes } from 'node:crypto';
10
10
  import { isCI, isTest } from 'std-env';
11
11
  export { defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
12
12
 
13
- const version = "0.0.2-alpha.31";
14
-
15
- function resolveDatabaseProvider(input) {
16
- const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
17
- if (!enabledProviders.length) {
18
- throw new Error("[nuxt-better-auth] No database provider is enabled. Register one with the better-auth:database:providers hook.");
19
- }
20
- enabledProviders.sort((a, b) => (b[1].priority ?? 0) - (a[1].priority ?? 0));
21
- const [id, definition] = enabledProviders[0];
22
- return { id, definition };
23
- }
13
+ const version = "0.0.2-alpha.32";
24
14
 
25
15
  const CONFIG_EXTENSIONS = [".ts", ".js"];
26
16
  const CONFIG_EXTENSION_RE = /\.(?:ts|js)$/;
@@ -35,7 +25,7 @@ const OPTION_KEY_BY_KIND = {
35
25
  function stripConfigExtension(path) {
36
26
  return path.replace(CONFIG_EXTENSION_RE, "");
37
27
  }
38
- function configExists(path) {
28
+ function defaultConfigExists(path) {
39
29
  return CONFIG_EXTENSIONS.some((ext) => existsSync(`${path}${ext}`));
40
30
  }
41
31
  function getLayerDirectoriesWithConfigs(nuxt) {
@@ -50,11 +40,15 @@ function getDefaultConfigPath(nuxt, kind) {
50
40
  const project = getProjectDirectory(nuxt);
51
41
  return kind === "server" ? join(project.server, "auth.config") : join(project.app, "auth.config");
52
42
  }
53
- function getLayerDefaultConfigPath(nuxt, kind) {
43
+ function getLayerDefaultConfigPath(nuxt, kind, configExists) {
54
44
  for (const { directory } of getLayerDirectoriesWithConfigs(nuxt)) {
55
45
  const candidate = kind === "server" ? join(directory.server, "auth.config") : join(directory.app, "auth.config");
56
- if (configExists(candidate))
57
- return candidate;
46
+ if (configExists(candidate)) {
47
+ return {
48
+ path: candidate,
49
+ declaringLayerRoot: directory.root
50
+ };
51
+ }
58
52
  }
59
53
  }
60
54
  function resolveDeclaringLayerRoot(nuxt, kind, file) {
@@ -74,36 +68,61 @@ function getEffectiveModuleConfigFile(nuxt, kind) {
74
68
  const authOptions = nuxt.options.auth;
75
69
  return authOptions?.[optionKey] ?? DEFAULT_CONFIG_FILES[kind];
76
70
  }
77
- function shouldCreateDefaultModuleConfig(nuxt, kind, file = getEffectiveModuleConfigFile(nuxt, kind)) {
78
- const normalizedFile = stripConfigExtension(file);
79
- if (normalizedFile !== DEFAULT_CONFIG_FILES[kind])
80
- return false;
81
- const resolved = resolveModuleConfigPath(nuxt, kind, normalizedFile);
82
- return !configExists(resolved.path);
83
- }
84
- function resolveModuleConfigPath(nuxt, kind, file) {
85
- const normalizedFile = stripConfigExtension(file);
86
- if (isAbsolute(normalizedFile)) {
71
+ function resolveAuthConfigDescriptor(nuxt, kind, file = getEffectiveModuleConfigFile(nuxt, kind), dependencies = {}) {
72
+ const configExists = dependencies.configExists ?? defaultConfigExists;
73
+ const configuredFile = stripConfigExtension(file);
74
+ if (isAbsolute(configuredFile)) {
75
+ const declaringLayerRoot2 = resolveDeclaringLayerRoot(nuxt, kind, configuredFile);
76
+ const exists2 = configExists(configuredFile);
87
77
  return {
88
- file: normalizedFile,
89
- path: normalizedFile,
90
- isDefault: false
78
+ kind,
79
+ configuredFile,
80
+ file: configuredFile,
81
+ path: configuredFile,
82
+ declaringLayerRoot: declaringLayerRoot2,
83
+ isDefault: false,
84
+ isExplicit: true,
85
+ exists: exists2,
86
+ shouldCreateDefaultFile: false
91
87
  };
92
88
  }
93
- if (normalizedFile === DEFAULT_CONFIG_FILES[kind]) {
94
- const discoveredPath = getLayerDefaultConfigPath(nuxt, kind) ?? getDefaultConfigPath(nuxt, kind);
89
+ if (configuredFile === DEFAULT_CONFIG_FILES[kind]) {
90
+ const project = getProjectDirectory(nuxt);
91
+ const discovered = getLayerDefaultConfigPath(nuxt, kind, configExists);
92
+ const path2 = discovered?.path ?? getDefaultConfigPath(nuxt, kind);
93
+ const declaringLayerRoot2 = discovered?.declaringLayerRoot ?? project.root;
94
+ const exists2 = configExists(path2);
95
95
  return {
96
- file: getRelativeConfigFile(nuxt, discoveredPath),
97
- path: discoveredPath,
98
- isDefault: true
96
+ kind,
97
+ configuredFile,
98
+ file: getRelativeConfigFile(nuxt, path2),
99
+ path: path2,
100
+ declaringLayerRoot: declaringLayerRoot2,
101
+ isDefault: true,
102
+ isExplicit: false,
103
+ exists: exists2,
104
+ shouldCreateDefaultFile: !exists2
99
105
  };
100
106
  }
101
- const baseRoot = resolveDeclaringLayerRoot(nuxt, kind, normalizedFile);
102
- const path = join(baseRoot, normalizedFile);
107
+ const declaringLayerRoot = resolveDeclaringLayerRoot(nuxt, kind, configuredFile);
108
+ const path = join(declaringLayerRoot, configuredFile);
109
+ const exists = configExists(path);
103
110
  return {
111
+ kind,
112
+ configuredFile,
104
113
  file: getRelativeConfigFile(nuxt, path),
105
114
  path,
106
- isDefault: false
115
+ declaringLayerRoot,
116
+ isDefault: false,
117
+ isExplicit: true,
118
+ exists,
119
+ shouldCreateDefaultFile: false
120
+ };
121
+ }
122
+ function resolveAuthConfigDescriptors(nuxt, files = {}, dependencies = {}) {
123
+ return {
124
+ server: resolveAuthConfigDescriptor(nuxt, "server", files.server, dependencies),
125
+ client: resolveAuthConfigDescriptor(nuxt, "client", files.client, dependencies)
107
126
  };
108
127
  }
109
128
 
@@ -149,6 +168,57 @@ function registerAuthMiddlewareHook(nuxt, resolve) {
149
168
  app.middleware.push({ name: "auth", path: resolve("./runtime/app/middleware/auth.global"), global: true });
150
169
  });
151
170
  }
171
+ function registerPrepareTypesHook(input) {
172
+ const { nuxt, serverDir, hasHubDb } = input;
173
+ nuxt.hook("prepare:types", ({ nodeTsConfig, nodeReferences, sharedReferences }) => {
174
+ nodeTsConfig.compilerOptions ||= {};
175
+ nodeTsConfig.compilerOptions.paths ||= {};
176
+ const projectReferenceTypePaths = [
177
+ join(nuxt.options.buildDir, "types/nitro-imports.d.ts"),
178
+ join(nuxt.options.buildDir, "types/auth-database.d.ts"),
179
+ join(nuxt.options.buildDir, "types/auth-schema.d.ts"),
180
+ join(nuxt.options.buildDir, "types/auth-secondary-storage.d.ts")
181
+ ];
182
+ if (hasHubDb)
183
+ projectReferenceTypePaths.push(join(nuxt.options.buildDir, "hub/db.d.ts"));
184
+ const exactNodeAliases = {
185
+ "#server": serverDir,
186
+ "#auth/server": nuxt.options.alias["#auth/server"],
187
+ "#auth/client": nuxt.options.alias["#auth/client"],
188
+ "#auth/database": nuxt.options.alias["#auth/database"],
189
+ "#auth/schema": nuxt.options.alias["#auth/schema"],
190
+ "#auth/secondary-storage": nuxt.options.alias["#auth/secondary-storage"],
191
+ "#auth/route-rules": nuxt.options.alias["#auth/route-rules"],
192
+ "#nuxt-better-auth": nuxt.options.alias["#nuxt-better-auth"]
193
+ };
194
+ for (const [key, value] of Object.entries(exactNodeAliases)) {
195
+ if (typeof value === "string")
196
+ nodeTsConfig.compilerOptions.paths[key] = [value];
197
+ }
198
+ for (const [key, value] of Object.entries(nuxt.options.alias)) {
199
+ if (typeof value !== "string" || !isAbsolute(value))
200
+ continue;
201
+ nodeTsConfig.compilerOptions.paths[key] ||= [value];
202
+ if (!key.includes("*") && existsSync(value) && statSync(value).isDirectory())
203
+ nodeTsConfig.compilerOptions.paths[`${key}/*`] ||= [join(value, "*")];
204
+ }
205
+ nodeTsConfig.compilerOptions.paths["#server/*"] = [join(serverDir, "*")];
206
+ for (const path of projectReferenceTypePaths) {
207
+ if (!nodeReferences.some((reference) => "path" in reference && reference.path === path))
208
+ nodeReferences.push({ path });
209
+ if (!sharedReferences.some((reference) => "path" in reference && reference.path === path))
210
+ sharedReferences.push({ path });
211
+ }
212
+ });
213
+ }
214
+ function registerNuxtHubDatabaseExternalHook(nuxt) {
215
+ nuxt.hook("nitro:config", (nitroConfig) => {
216
+ nitroConfig.externals ||= {};
217
+ nitroConfig.externals.external ||= [];
218
+ if (!nitroConfig.externals.external.includes("@nuxthub/db"))
219
+ nitroConfig.externals.external.push("@nuxthub/db");
220
+ });
221
+ }
152
222
  async function registerDevtools(input) {
153
223
  const { nuxt, clientOnly, hasHubDb, resolve } = input;
154
224
  const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
@@ -193,79 +263,6 @@ function registerRouteRulesMetaHook(nuxt) {
193
263
  });
194
264
  }
195
265
 
196
- function getHubDialect(hub) {
197
- if (!hub?.db)
198
- return void 0;
199
- if (typeof hub.db === "string")
200
- return hub.db;
201
- if (typeof hub.db === "object" && hub.db !== null)
202
- return hub.db.dialect;
203
- return void 0;
204
- }
205
- function getHubCasing(hub) {
206
- if (!hub?.db || typeof hub.db !== "object" || hub.db === null)
207
- return void 0;
208
- return hub.db.casing;
209
- }
210
-
211
- function resolveSecondaryStorage(input) {
212
- const { options, clientOnly, hasNuxtHub, hub } = input;
213
- const opt = options.hubSecondaryStorage ?? false;
214
- const useHubKV = opt === true;
215
- const secondaryStorageEnabled = opt === true || opt === "custom";
216
- if (secondaryStorageEnabled && clientOnly) {
217
- throw new Error("[nuxt-better-auth] hubSecondaryStorage is not available in clientOnly mode. Either disable clientOnly or remove auth.hubSecondaryStorage.");
218
- }
219
- if (useHubKV && (!hasNuxtHub || !hub?.kv)) {
220
- throw new Error("[nuxt-better-auth] hubSecondaryStorage: true requires @nuxthub/core with hub.kv: true. Either add hub.kv: true to your nuxt.config or remove auth.hubSecondaryStorage.");
221
- }
222
- return { useHubKV, secondaryStorageEnabled };
223
- }
224
- function setupRuntimeConfig(input) {
225
- const { nuxt, options, clientOnly, databaseProvider, consola } = input;
226
- const { useHubKV, secondaryStorageEnabled } = resolveSecondaryStorage(input);
227
- nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
228
- const configuredSiteUrl = nuxt.options.runtimeConfig.public.siteUrl;
229
- if (!configuredSiteUrl && process.env.NUXT_PUBLIC_SITE_URL)
230
- nuxt.options.runtimeConfig.public.siteUrl = process.env.NUXT_PUBLIC_SITE_URL;
231
- nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
232
- redirects: {
233
- login: options.redirects?.login ?? "/login",
234
- guest: options.redirects?.guest ?? "/",
235
- authenticated: options.redirects?.authenticated,
236
- logout: options.redirects?.logout
237
- },
238
- preserveRedirect: options.preserveRedirect ?? true,
239
- redirectQueryKey: options.redirectQueryKey ?? "redirect",
240
- useDatabase: databaseProvider !== "none",
241
- databaseProvider,
242
- clientOnly,
243
- session: {
244
- skipHydratedSsrGetSession: options.session?.skipHydratedSsrGetSession ?? false
245
- }
246
- });
247
- if (clientOnly) {
248
- const siteUrl = nuxt.options.runtimeConfig.public.siteUrl;
249
- if (!siteUrl)
250
- consola.warn("clientOnly mode: set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) to your frontend URL");
251
- consola.info("clientOnly mode enabled - server utilities (serverAuth, getRequestSession, getUserSession, requireUserSession) are not available");
252
- return { useHubKV, secondaryStorageEnabled };
253
- }
254
- const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
255
- nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || "";
256
- const betterAuthSecret = nuxt.options.runtimeConfig.betterAuthSecret;
257
- if (!nuxt.options.dev && !nuxt.options._prepare && !betterAuthSecret) {
258
- throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET is required in production. Set NUXT_BETTER_AUTH_SECRET or BETTER_AUTH_SECRET environment variable.");
259
- }
260
- if (betterAuthSecret && betterAuthSecret.length < 32) {
261
- throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET must be at least 32 characters for security");
262
- }
263
- nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
264
- hubSecondaryStorage: options.hubSecondaryStorage ?? false
265
- });
266
- return { useHubKV, secondaryStorageEnabled };
267
- }
268
-
269
266
  function dialectToProvider(dialect) {
270
267
  return dialect === "postgresql" ? "pg" : dialect;
271
268
  }
@@ -298,10 +295,10 @@ async function generateDrizzleSchema(authOptions, dialect, schemaOptions) {
298
295
  }
299
296
  return result.code;
300
297
  }
301
- async function loadUserAuthConfig(configPath, throwOnError = false) {
298
+ async function loadUserAuthConfig(configPath, throwOnError = false, alias) {
302
299
  const { createJiti } = await import('jiti');
303
300
  const { defineServerAuth: runtimeDefineServerAuth } = await import('../dist/runtime/config.js');
304
- const jiti = createJiti(import.meta.url, { interopDefault: true, moduleCache: false });
301
+ const jiti = createJiti(import.meta.url, { interopDefault: true, moduleCache: false, alias });
305
302
  const schemaGlobals = globalThis;
306
303
  if (!schemaGlobals.__nuxtBetterAuthDefineServerAuth) {
307
304
  runtimeDefineServerAuth._count = 0;
@@ -342,6 +339,21 @@ async function loadUserAuthConfig(configPath, throwOnError = false) {
342
339
  }
343
340
  }
344
341
 
342
+ function getHubDialect(hub) {
343
+ if (!hub?.db)
344
+ return void 0;
345
+ if (typeof hub.db === "string")
346
+ return hub.db;
347
+ if (typeof hub.db === "object" && hub.db !== null)
348
+ return hub.db.dialect;
349
+ return void 0;
350
+ }
351
+ function getHubCasing(hub) {
352
+ if (!hub?.db || typeof hub.db !== "object" || hub.db === null)
353
+ return void 0;
354
+ return hub.db.casing;
355
+ }
356
+
345
357
  const NODE_MODULES_SEGMENT_RE = /[\\/]/;
346
358
  function resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, isProduction) {
347
359
  if (hubSecondaryStorage === true)
@@ -373,7 +385,10 @@ function resolveHubSchemaPath(buildDir, rootDir, dialect, exists = existsSync) {
373
385
  async function loadAuthOptions(context) {
374
386
  const isProduction = !context.nuxt.options.dev;
375
387
  const configFile = `${context.serverConfigPath}.ts`;
376
- const userConfig = await loadUserAuthConfig(configFile, isProduction);
388
+ const alias = Object.fromEntries(
389
+ Object.entries(context.nuxt.options.alias).filter(([, value]) => typeof value === "string").map(([key, value]) => [key, value])
390
+ );
391
+ const userConfig = await loadUserAuthConfig(configFile, isProduction, alias);
377
392
  const extendedConfig = {};
378
393
  await context.nuxt.callHook("better-auth:config:extend", extendedConfig);
379
394
  const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
@@ -513,6 +528,74 @@ Proceed?`, { type: "confirm", initial: true, cancel: "null" });
513
528
  return secret;
514
529
  }
515
530
 
531
+ function resolveDatabaseProvider(input) {
532
+ const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
533
+ if (!enabledProviders.length) {
534
+ throw new Error("[nuxt-better-auth] No database provider is enabled. Register one with the better-auth:database:providers hook.");
535
+ }
536
+ enabledProviders.sort((a, b) => (b[1].priority ?? 0) - (a[1].priority ?? 0));
537
+ const [id, definition] = enabledProviders[0];
538
+ return { id, definition };
539
+ }
540
+
541
+ function resolveSecondaryStorage(input) {
542
+ const { options, clientOnly, hasNuxtHub, hub } = input;
543
+ const opt = options.hubSecondaryStorage ?? false;
544
+ const useHubKV = opt === true;
545
+ const secondaryStorageEnabled = opt === true || opt === "custom";
546
+ if (secondaryStorageEnabled && clientOnly) {
547
+ throw new Error("[nuxt-better-auth] hubSecondaryStorage is not available in clientOnly mode. Either disable clientOnly or remove auth.hubSecondaryStorage.");
548
+ }
549
+ if (useHubKV && (!hasNuxtHub || !hub?.kv)) {
550
+ throw new Error("[nuxt-better-auth] hubSecondaryStorage: true requires @nuxthub/core with hub.kv: true. Either add hub.kv: true to your nuxt.config or remove auth.hubSecondaryStorage.");
551
+ }
552
+ return { useHubKV, secondaryStorageEnabled };
553
+ }
554
+ function setupRuntimeConfig(input) {
555
+ const { nuxt, options, clientOnly, databaseProvider, consola } = input;
556
+ const { useHubKV, secondaryStorageEnabled } = resolveSecondaryStorage(input);
557
+ nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
558
+ const configuredSiteUrl = nuxt.options.runtimeConfig.public.siteUrl;
559
+ if (!configuredSiteUrl && process.env.NUXT_PUBLIC_SITE_URL)
560
+ nuxt.options.runtimeConfig.public.siteUrl = process.env.NUXT_PUBLIC_SITE_URL;
561
+ nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
562
+ redirects: {
563
+ login: options.redirects?.login ?? "/login",
564
+ guest: options.redirects?.guest ?? "/",
565
+ authenticated: options.redirects?.authenticated,
566
+ logout: options.redirects?.logout
567
+ },
568
+ preserveRedirect: options.preserveRedirect ?? true,
569
+ redirectQueryKey: options.redirectQueryKey ?? "redirect",
570
+ useDatabase: databaseProvider !== "none",
571
+ databaseProvider,
572
+ clientOnly,
573
+ session: {
574
+ skipHydratedSsrGetSession: options.session?.skipHydratedSsrGetSession ?? false
575
+ }
576
+ });
577
+ if (clientOnly) {
578
+ const siteUrl = nuxt.options.runtimeConfig.public.siteUrl;
579
+ if (!siteUrl)
580
+ consola.warn("clientOnly mode: set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) to your frontend URL");
581
+ consola.info("clientOnly mode enabled - server utilities (serverAuth, getRequestSession, getUserSession, requireUserSession) are not available");
582
+ return { useHubKV, secondaryStorageEnabled };
583
+ }
584
+ const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
585
+ nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || "";
586
+ const betterAuthSecret = nuxt.options.runtimeConfig.betterAuthSecret;
587
+ if (!nuxt.options.dev && !nuxt.options._prepare && !betterAuthSecret) {
588
+ throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET is required in production. Set NUXT_BETTER_AUTH_SECRET or BETTER_AUTH_SECRET environment variable.");
589
+ }
590
+ if (betterAuthSecret && betterAuthSecret.length < 32) {
591
+ throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET must be at least 32 characters for security");
592
+ }
593
+ nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
594
+ hubSecondaryStorage: options.hubSecondaryStorage ?? false
595
+ });
596
+ return { useHubKV, secondaryStorageEnabled };
597
+ }
598
+
516
599
  function buildSecondaryStorageCode(useHubKV) {
517
600
  if (!useHubKV)
518
601
  return "export function createSecondaryStorage() { return undefined }";
@@ -527,6 +610,114 @@ export function createSecondaryStorage() {
527
610
  }
528
611
  function buildDatabaseCode(input) {
529
612
  if (input.provider === "nuxthub") {
613
+ if (input.hubDialect === "postgresql") {
614
+ return `import { db } from '@nuxthub/db'
615
+ import * as schema from './schema.${input.hubDialect}.mjs'
616
+ import { drizzleAdapter } from 'better-auth/adapters/drizzle'
617
+ import { drizzle } from 'drizzle-orm/postgres-js'
618
+ import postgres from 'postgres'
619
+
620
+ const dialect = 'pg'
621
+ const requestDatabaseKey = Symbol.for('nuxt-better-auth.requestDatabase')
622
+ const fallbackRequestDatabaseContext = new WeakMap()
623
+
624
+ function getRequestDatabaseContext(event) {
625
+ const eventWithContext = event
626
+ if (eventWithContext?.context && typeof eventWithContext.context === 'object')
627
+ return eventWithContext.context
628
+
629
+ let context = fallbackRequestDatabaseContext.get(event)
630
+ if (!context) {
631
+ context = {}
632
+ fallbackRequestDatabaseContext.set(event, context)
633
+ }
634
+ return context
635
+ }
636
+
637
+ function createHyperdriveAdapter(client) {
638
+ return drizzleAdapter(drizzle({ client, schema }), { provider: dialect, schema, usePlural: ${input.usePlural}, camelCase: ${input.camelCase} })
639
+ }
640
+
641
+ function getCloudflareContext(event) {
642
+ return event?.context?.cloudflare
643
+ }
644
+
645
+ function resolveHyperdrive(event) {
646
+ const cloudflareEnv = getCloudflareContext(event)?.env
647
+ return cloudflareEnv?.POSTGRES || process.env.POSTGRES || globalThis.__env__?.POSTGRES || globalThis.POSTGRES
648
+ }
649
+
650
+ function scheduleCleanup(event, cleanup) {
651
+ const cloudflareContext = getCloudflareContext(event)
652
+ if (typeof cloudflareContext?.context?.waitUntil === 'function') {
653
+ cloudflareContext.context.waitUntil(cleanup)
654
+ return
655
+ }
656
+
657
+ if (typeof event?.context?.waitUntil === 'function') {
658
+ event.context.waitUntil(cleanup)
659
+ return
660
+ }
661
+
662
+ const waitUntil = event?.waitUntil || event?.req?.waitUntil || event?.node?.req?.waitUntil
663
+ if (typeof waitUntil === 'function')
664
+ waitUntil.call(event?.req || event?.node?.req || event, cleanup)
665
+ else
666
+ void cleanup
667
+ }
668
+
669
+ function registerClientCleanup(event, client) {
670
+ const response = event?.node?.res
671
+ if (!response || typeof response.once !== 'function')
672
+ return
673
+
674
+ let closed = false
675
+
676
+ const cleanup = () => {
677
+ if (closed)
678
+ return
679
+
680
+ closed = true
681
+ const close = client.end({ timeout: 0 }).catch(() => {})
682
+ scheduleCleanup(event, close)
683
+ }
684
+
685
+ response.once('finish', cleanup)
686
+ response.once('close', cleanup)
687
+ }
688
+
689
+ export function createDatabase(event) {
690
+ const hyperdrive = resolveHyperdrive(event)
691
+ if (!hyperdrive?.connectionString)
692
+ return drizzleAdapter(db, { provider: dialect, schema, usePlural: ${input.usePlural}, camelCase: ${input.camelCase} })
693
+
694
+ if (event) {
695
+ const context = getRequestDatabaseContext(event)
696
+ const cached = context[requestDatabaseKey]
697
+ if (cached)
698
+ return cached
699
+
700
+ const client = postgres(hyperdrive.connectionString, {
701
+ prepare: false,
702
+ onnotice: () => {},
703
+ max: 1,
704
+ })
705
+ const database = createHyperdriveAdapter(client)
706
+
707
+ context[requestDatabaseKey] = database
708
+ registerClientCleanup(event, client)
709
+ return database
710
+ }
711
+ const client = postgres(hyperdrive.connectionString, {
712
+ prepare: false,
713
+ onnotice: () => {},
714
+ max: 1,
715
+ })
716
+
717
+ return createHyperdriveAdapter(client)
718
+ }
719
+ export { db }`;
720
+ }
530
721
  return `import { db } from '@nuxthub/db'
531
722
  import * as schema from './schema.${input.hubDialect}.mjs'
532
723
  import { drizzleAdapter } from 'better-auth/adapters/drizzle'
@@ -538,9 +729,153 @@ export { db }`;
538
729
  return `export function createDatabase() { return undefined }
539
730
  export const db = undefined`;
540
731
  }
732
+ function buildSchemaExportCode(hasHubDb, hubDialect) {
733
+ if (!hasHubDb)
734
+ return "export const schema = undefined\n";
735
+ return `export * from './schema.${hubDialect}.mjs'
736
+ import * as schema from './schema.${hubDialect}.mjs'
737
+ export { schema }
738
+ `;
739
+ }
740
+ function buildAuthRouteRulesCode(authRouteRules) {
741
+ return `export const authRouteRules = ${JSON.stringify(authRouteRules, null, 2)}
742
+ `;
743
+ }
744
+
745
+ function assertConfigPresence(configs, clientOnly) {
746
+ if (!clientOnly && !configs.server.exists)
747
+ throw new Error(`[nuxt-better-auth] Missing ${configs.server.file}.ts - export default defineServerAuth(...)`);
748
+ if (!configs.client.exists)
749
+ throw new Error(`[nuxt-better-auth] Missing ${configs.client.file}.ts - export default defineClientAuth(...)`);
750
+ }
751
+ function createDefaultDatabaseProviders(buildContext) {
752
+ return {
753
+ nuxthub: {
754
+ priority: 100,
755
+ isEnabled: ({ hasHubDbAvailable: enabled }) => enabled,
756
+ buildDatabaseCode: () => buildDatabaseCode({
757
+ provider: "nuxthub",
758
+ ...buildContext
759
+ })
760
+ },
761
+ none: {
762
+ priority: 0,
763
+ buildDatabaseCode: () => buildDatabaseCode({
764
+ provider: "none",
765
+ ...buildContext
766
+ })
767
+ }
768
+ };
769
+ }
770
+ function collectAuthRouteRules(nuxt) {
771
+ const runtimeRouteRulesSource = nuxt.options.nitro?.routeRules || nuxt.options.routeRules || {};
772
+ return Object.fromEntries(
773
+ Object.entries(runtimeRouteRulesSource).flatMap(([path, rule]) => {
774
+ if (!rule || typeof rule !== "object" || !("auth" in rule))
775
+ return [];
776
+ return [[path, { auth: rule.auth }]];
777
+ })
778
+ );
779
+ }
780
+ async function resolveAuthModuleSetup(input, dependencies = {}) {
781
+ const { nuxt, options, runtimeTypesAugmentPath, consola } = input;
782
+ const hasNuxtModuleFn = dependencies.hasNuxtModule ?? hasNuxtModule;
783
+ const clientOnly = options.clientOnly ?? false;
784
+ const configs = resolveAuthConfigDescriptors(nuxt, {
785
+ server: options.serverConfig,
786
+ client: options.clientConfig
787
+ }, {
788
+ configExists: dependencies.configExists
789
+ });
790
+ assertConfigPresence(configs, clientOnly);
791
+ const aliases = {
792
+ "#nuxt-better-auth": runtimeTypesAugmentPath,
793
+ "#auth/server": clientOnly ? void 0 : configs.server.path,
794
+ "#auth/client": configs.client.path
795
+ };
796
+ nuxt.options.alias["#nuxt-better-auth"] = aliases["#nuxt-better-auth"];
797
+ if (aliases["#auth/server"])
798
+ nuxt.options.alias["#auth/server"] = aliases["#auth/server"];
799
+ nuxt.options.alias["#auth/client"] = aliases["#auth/client"];
800
+ const hasNuxtHub = hasNuxtModuleFn("@nuxthub/core", nuxt);
801
+ const hub = hasNuxtHub ? nuxt.options.hub : void 0;
802
+ const hasHubDbAvailable = !clientOnly && hasNuxtHub && !!hub?.db;
803
+ const hubDialect = getHubDialect(hub) ?? "sqlite";
804
+ const usePlural = options.schema?.usePlural ?? false;
805
+ const camelCase = (options.schema?.casing ?? getHubCasing(hub)) !== "snake_case";
806
+ let providerId = "none";
807
+ let providerDefinition;
808
+ if (!clientOnly) {
809
+ const buildContext = { hubDialect, usePlural, camelCase };
810
+ const providers = createDefaultDatabaseProviders(buildContext);
811
+ const enabledContext = {
812
+ nuxt,
813
+ options,
814
+ clientOnly,
815
+ hasHubDbAvailable
816
+ };
817
+ await nuxt.callHook("better-auth:database:providers", providers);
818
+ const resolvedProvider = resolveDatabaseProvider({
819
+ providers,
820
+ context: enabledContext
821
+ });
822
+ providerId = resolvedProvider.id;
823
+ providerDefinition = resolvedProvider.definition;
824
+ }
825
+ const runtime = setupRuntimeConfig({
826
+ nuxt,
827
+ options,
828
+ clientOnly,
829
+ databaseProvider: providerId,
830
+ hasNuxtHub,
831
+ hub,
832
+ consola
833
+ });
834
+ if (runtime.useHubKV && !nuxt.options.alias["hub:kv"]) {
835
+ throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
836
+ }
837
+ const hasHubDb = providerId === "nuxthub";
838
+ if (hasHubDb && !nuxt.options.alias["hub:db"]) {
839
+ throw new Error("[nuxt-better-auth] hub:db not found. Ensure @nuxthub/core is loaded before this module and hub.db is configured.");
840
+ }
841
+ return {
842
+ clientOnly,
843
+ configs,
844
+ aliases,
845
+ hub: {
846
+ hasNuxtHub,
847
+ options: hub,
848
+ hasHubDbAvailable
849
+ },
850
+ database: {
851
+ providerId,
852
+ hasHubDb,
853
+ providerDefinition,
854
+ buildContext: clientOnly ? void 0 : { hubDialect, usePlural, camelCase }
855
+ },
856
+ runtime,
857
+ prepareTypes: clientOnly ? void 0 : {
858
+ serverDir: dirname(configs.server.path),
859
+ hasHubDb
860
+ },
861
+ serverTypes: clientOnly ? void 0 : {
862
+ serverConfigPath: configs.server.path,
863
+ hasHubDb
864
+ },
865
+ sharedTypes: {
866
+ clientConfigPath: configs.client.path
867
+ },
868
+ schemaGeneration: hasHubDb ? {
869
+ serverConfigPath: configs.server.path,
870
+ hubSecondaryStorage: options.hubSecondaryStorage ?? false,
871
+ externalizeNuxtHubDatabase: true
872
+ } : void 0
873
+ };
874
+ }
541
875
 
542
876
  function registerServerTypeTemplates(input) {
543
- const { serverConfigPath, hasHubDb, runtimeTypesPath } = input;
877
+ const { serverConfigPath, hasHubDb, runtimeTypesPath, sharedServerConfigSafe } = input;
878
+ const serverConfigTypeTemplateOptions = sharedServerConfigSafe ? { nuxt: true, nitro: true, node: true, shared: true } : { nuxt: true, nitro: true, node: true };
544
879
  addTypeTemplate({
545
880
  filename: "types/auth-secondary-storage.d.ts",
546
881
  getContents: () => `
@@ -553,17 +888,17 @@ declare module '#auth/secondary-storage' {
553
888
  export function createSecondaryStorage(): SecondaryStorage | undefined
554
889
  }
555
890
  `
556
- }, { nitro: true, node: true });
891
+ }, { nitro: true });
557
892
  addTypeTemplate({
558
893
  filename: "types/auth-database.d.ts",
559
894
  getContents: () => `
560
895
  declare module '#auth/database' {
561
896
  import type { BetterAuthOptions } from 'better-auth'
562
- export function createDatabase(): BetterAuthOptions['database']
897
+ export function createDatabase(event?: import('h3').H3Event): BetterAuthOptions['database']
563
898
  export const db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
564
899
  }
565
900
  `
566
- }, { nitro: true, node: true });
901
+ }, { nitro: true });
567
902
  addTypeTemplate({
568
903
  filename: "types/auth-schema.d.ts",
569
904
  getContents: () => `
@@ -581,13 +916,39 @@ declare module '#auth/schema' {
581
916
  } | undefined
582
917
  }
583
918
  `
584
- }, { nitro: true, node: true });
919
+ }, { nitro: true });
920
+ addTypeTemplate({
921
+ filename: "types/nuxt-better-auth-server-context.d.ts",
922
+ getContents: () => `
923
+ /// <reference path="./nitro-imports.d.ts" />
924
+ /// <reference path="./auth-database.d.ts" />
925
+ /// <reference path="./auth-schema.d.ts" />
926
+ /// <reference path="./auth-secondary-storage.d.ts" />
927
+ ${hasHubDb ? '/// <reference path="../hub/db.d.ts" />' : ""}
928
+
929
+ export {}
930
+ `
931
+ }, { node: true });
932
+ addTypeTemplate({
933
+ filename: "types/nuxt-better-auth-config-context.d.ts",
934
+ getContents: () => `
935
+ import type { RuntimeConfig } from 'nuxt/schema'
936
+
937
+ declare module '@onmax/nuxt-better-auth/config' {
938
+ interface ServerAuthContextExtension {
939
+ runtimeConfig: RuntimeConfig
940
+ db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
941
+ requestOrigin?: string
942
+ }
943
+ }
944
+
945
+ `
946
+ }, { nuxt: true, nitro: true, node: true, shared: true });
585
947
  addTypeTemplate({
586
948
  filename: "types/nuxt-better-auth-infer.d.ts",
587
949
  getContents: () => `
588
950
  import type { BetterAuthOptions, BetterAuthPlugin, InferPluginTypes, UnionToIntersection } from 'better-auth'
589
951
  import type { InferFieldsOutput } from 'better-auth/db'
590
- import type { RuntimeConfig } from 'nuxt/schema'
591
952
  import type createServerAuth from '${serverConfigPath}'
592
953
 
593
954
  type _RawConfig = ReturnType<typeof createServerAuth>
@@ -617,28 +978,10 @@ type _SessionFallback = _InferModelFieldsFromPlugins<_RawPlugins, 'session'> & _
617
978
  declare module '#nuxt-better-auth' {
618
979
  interface AuthUser extends _UserFallback {}
619
980
  interface AuthSession extends _SessionFallback {}
620
- interface ServerAuthContext {
621
- runtimeConfig: RuntimeConfig
622
- db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
623
- }
624
981
  type PluginTypes = InferPluginTypes<_Config>
625
982
  }
626
-
627
- interface _AugmentedServerAuthContext {
628
- runtimeConfig: RuntimeConfig
629
- db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
630
- }
631
-
632
- declare module '@onmax/nuxt-better-auth/config' {
633
- import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth'
634
- type ServerAuthConfig = Omit<BetterAuthOptions, 'secret' | 'baseURL'> & {
635
- plugins?: readonly BetterAuthPlugin[]
636
- }
637
- export function defineServerAuth<const R>(config: (ctx: _AugmentedServerAuthContext) => R & ServerAuthConfig): (ctx: _AugmentedServerAuthContext) => R
638
- export function defineServerAuth<const R>(config: R & ServerAuthConfig): (ctx: _AugmentedServerAuthContext) => R
639
- }
640
983
  `
641
- }, { nuxt: true, nitro: true, node: true });
984
+ }, serverConfigTypeTemplateOptions);
642
985
  addTypeTemplate({
643
986
  filename: "types/nuxt-better-auth-social-providers.d.ts",
644
987
  getContents: () => `
@@ -654,7 +997,7 @@ declare module '#nuxt-better-auth' {
654
997
  }
655
998
  }
656
999
  `
657
- }, { nuxt: true, nitro: true, node: true });
1000
+ }, serverConfigTypeTemplateOptions);
658
1001
  addTypeTemplate({
659
1002
  filename: "types/nuxt-better-auth-nitro.d.ts",
660
1003
  getContents: () => `
@@ -761,6 +1104,7 @@ declare module 'nuxt/dist/app/composables/fetch' {
761
1104
  PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
762
1105
  DefaultT = DataT,
763
1106
  >(request: import('vue').Ref<Path> | Path | (() => Path), opts?: import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
1107
+ export function useFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
764
1108
 
765
1109
  export function useLazyFetch<
766
1110
  ErrorT = FetchError,
@@ -780,6 +1124,7 @@ declare module 'nuxt/dist/app/composables/fetch' {
780
1124
  PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
781
1125
  DefaultT = DataT,
782
1126
  >(request: import('vue').Ref<Path> | Path | (() => Path), opts?: Omit<import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>, 'lazy'>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
1127
+ export function useLazyFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
783
1128
  }
784
1129
 
785
1130
  declare module 'nuxt/app' {
@@ -801,6 +1146,7 @@ declare module 'nuxt/app' {
801
1146
  PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
802
1147
  DefaultT = DataT,
803
1148
  >(request: import('vue').Ref<Path> | Path | (() => Path), opts?: import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
1149
+ export function useFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
804
1150
 
805
1151
  export function useLazyFetch<
806
1152
  ErrorT = FetchError,
@@ -820,6 +1166,7 @@ declare module 'nuxt/app' {
820
1166
  PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
821
1167
  DefaultT = DataT,
822
1168
  >(request: import('vue').Ref<Path> | Path | (() => Path), opts?: Omit<import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>, 'lazy'>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
1169
+ export function useLazyFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
823
1170
  }
824
1171
 
825
1172
  declare module 'nitropack' {
@@ -840,9 +1187,18 @@ declare module 'nitropack/types' {
840
1187
  }
841
1188
  interface InternalApi extends _GeneratedAuthInternalApi {}
842
1189
  }
1190
+ declare module 'nitro/types' {
1191
+ interface NitroRouteRules {
1192
+ auth?: import('${runtimeTypesPath}').AuthMeta
1193
+ }
1194
+ interface NitroRouteConfig {
1195
+ auth?: import('${runtimeTypesPath}').AuthMeta
1196
+ }
1197
+ interface InternalApi extends _GeneratedAuthInternalApi {}
1198
+ }
843
1199
  export {}
844
1200
  `
845
- }, { nuxt: true, nitro: true, node: true });
1201
+ }, { nitro: true, node: true });
846
1202
  }
847
1203
  function registerSharedTypeTemplates(input) {
848
1204
  addTypeTemplate({
@@ -870,13 +1226,30 @@ declare module '#nuxt-better-auth' {
870
1226
  }
871
1227
 
872
1228
  const consola = consola$1.withTag("nuxt-better-auth");
1229
+ const serverAliasImportRE = /from\s+['"]#server/;
1230
+ const layersAliasImportRE = /from\s+['"]#layers\//;
1231
+ const rootAliasImportRE = /from\s+['"]~~/;
1232
+ const workspaceAliasImportRE = /from\s+['"]@@/;
1233
+ const dbIdentifierRE = /\bdb\b/;
1234
+ const sessionHookAfterIdentifierRE = /\bsessionHookAfter\b/;
1235
+ const nuxtHubDbImportRE = /@nuxthub\/db/;
1236
+ function isServerConfigSharedTypeSafe(serverConfigPath) {
1237
+ const resolvedPath = [
1238
+ serverConfigPath,
1239
+ `${serverConfigPath}.ts`,
1240
+ `${serverConfigPath}.mts`,
1241
+ `${serverConfigPath}.cts`,
1242
+ `${serverConfigPath}.js`,
1243
+ `${serverConfigPath}.mjs`,
1244
+ `${serverConfigPath}.cjs`
1245
+ ].find((path) => existsSync(path));
1246
+ if (!resolvedPath)
1247
+ return false;
1248
+ const contents = readFileSync(resolvedPath, "utf8");
1249
+ return !(serverAliasImportRE.test(contents) || layersAliasImportRE.test(contents) || rootAliasImportRE.test(contents) || workspaceAliasImportRE.test(contents) || dbIdentifierRE.test(contents) || sessionHookAfterIdentifierRE.test(contents) || nuxtHubDbImportRE.test(contents));
1250
+ }
873
1251
  async function createDefaultAuthConfigFiles(nuxt) {
874
- const project = getLayerDirectories(nuxt)[0];
875
- const rootDir = project.root;
876
- const serverPath = join(project.server, "auth.config.ts");
877
- const clientPath = join(project.app, "auth.config.ts");
878
- const serverConfigFile = getEffectiveModuleConfigFile(nuxt, "server");
879
- const clientConfigFile = getEffectiveModuleConfigFile(nuxt, "client");
1252
+ const configs = resolveAuthConfigDescriptors(nuxt);
880
1253
  const serverTemplate = `import { defineServerAuth } from '@onmax/nuxt-better-auth/config'
881
1254
 
882
1255
  export default defineServerAuth({
@@ -887,15 +1260,17 @@ export default defineServerAuth({
887
1260
 
888
1261
  export default defineClientAuth({})
889
1262
  `;
890
- if (shouldCreateDefaultModuleConfig(nuxt, "server", serverConfigFile)) {
1263
+ if (configs.server.shouldCreateDefaultFile) {
1264
+ const serverPath = `${configs.server.path}.ts`;
891
1265
  await mkdir(dirname(serverPath), { recursive: true });
892
1266
  await writeFile(serverPath, serverTemplate);
893
- consola.success(`Created ${relative(rootDir, serverPath)}`);
1267
+ consola.success(`Created ${relative(configs.server.declaringLayerRoot, serverPath)}`);
894
1268
  }
895
- if (shouldCreateDefaultModuleConfig(nuxt, "client", clientConfigFile)) {
1269
+ if (configs.client.shouldCreateDefaultFile) {
1270
+ const clientPath = `${configs.client.path}.ts`;
896
1271
  await mkdir(dirname(clientPath), { recursive: true });
897
1272
  await writeFile(clientPath, clientTemplate);
898
- consola.success(`Created ${relative(rootDir, clientPath)}`);
1273
+ consola.success(`Created ${relative(configs.client.declaringLayerRoot, clientPath)}`);
899
1274
  }
900
1275
  }
901
1276
  const module$1 = defineNuxtModule({
@@ -918,141 +1293,85 @@ const module$1 = defineNuxtModule({
918
1293
  },
919
1294
  async setup(options, nuxt) {
920
1295
  const resolver = createResolver(import.meta.url);
921
- const clientOnly = options.clientOnly;
922
- const serverConfigFile = options.serverConfig;
923
- const clientConfigFile = options.clientConfig;
924
- const { file: resolvedServerConfigFile, path: serverConfigPath } = resolveModuleConfigPath(nuxt, "server", serverConfigFile);
925
- const { file: resolvedClientConfigFile, path: clientConfigPath } = resolveModuleConfigPath(nuxt, "client", clientConfigFile);
926
- const serverConfigExists = existsSync(`${serverConfigPath}.ts`) || existsSync(`${serverConfigPath}.js`);
927
- const clientConfigExists = existsSync(`${clientConfigPath}.ts`) || existsSync(`${clientConfigPath}.js`);
928
- if (!clientOnly && !serverConfigExists)
929
- throw new Error(`[nuxt-better-auth] Missing ${resolvedServerConfigFile}.ts - export default defineServerAuth(...)`);
930
- if (!clientConfigExists)
931
- throw new Error(`[nuxt-better-auth] Missing ${resolvedClientConfigFile}.ts - export default defineClientAuth(...)`);
932
- const hasNuxtHub = hasNuxtModule("@nuxthub/core", nuxt);
933
- const hub = hasNuxtHub ? nuxt.options.hub : void 0;
934
- const hasHubDbAvailable = !clientOnly && hasNuxtHub && !!hub?.db;
935
- let databaseProvider = "none";
936
- let hasHubDb = false;
937
- nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
938
- if (!clientOnly)
939
- nuxt.options.alias["#auth/server"] = serverConfigPath;
940
- nuxt.options.alias["#auth/client"] = clientConfigPath;
941
- if (clientOnly) {
942
- setupRuntimeConfig({
943
- nuxt,
944
- options,
945
- clientOnly,
946
- databaseProvider,
947
- hasNuxtHub,
948
- hub,
949
- consola
950
- });
951
- } else {
952
- const hubDialect = getHubDialect(hub) ?? "sqlite";
953
- const usePlural = options.schema?.usePlural ?? false;
954
- const camelCase = (options.schema?.casing ?? getHubCasing(hub)) !== "snake_case";
955
- const providers = {
956
- nuxthub: {
957
- priority: 100,
958
- isEnabled: ({ hasHubDbAvailable: hasHubDbAvailable2 }) => hasHubDbAvailable2,
959
- buildDatabaseCode: () => buildDatabaseCode({
960
- provider: "nuxthub",
961
- hubDialect,
962
- usePlural,
963
- camelCase
964
- })
965
- },
966
- none: {
967
- priority: 0,
968
- buildDatabaseCode: () => buildDatabaseCode({
969
- provider: "none",
970
- hubDialect,
971
- usePlural,
972
- camelCase
973
- })
974
- }
975
- };
976
- const enabledCtx = { nuxt, options, clientOnly, hasHubDbAvailable };
977
- await nuxt.callHook("better-auth:database:providers", providers);
978
- const resolvedProvider = resolveDatabaseProvider({ providers, context: enabledCtx });
979
- databaseProvider = resolvedProvider.id;
980
- hasHubDb = databaseProvider === "nuxthub";
981
- const { useHubKV } = setupRuntimeConfig({
982
- nuxt,
983
- options,
984
- clientOnly,
985
- databaseProvider,
986
- hasNuxtHub,
987
- hub,
988
- consola
989
- });
990
- if (useHubKV && !nuxt.options.alias["hub:kv"]) {
991
- throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
992
- }
1296
+ const setup = await resolveAuthModuleSetup({
1297
+ nuxt,
1298
+ options,
1299
+ runtimeTypesAugmentPath: resolver.resolve("./runtime/types/augment"),
1300
+ consola
1301
+ });
1302
+ nuxt.options.alias["#nuxt-better-auth"] = setup.aliases["#nuxt-better-auth"];
1303
+ if (setup.aliases["#auth/server"])
1304
+ nuxt.options.alias["#auth/server"] = setup.aliases["#auth/server"];
1305
+ nuxt.options.alias["#auth/client"] = setup.aliases["#auth/client"];
1306
+ if (!setup.clientOnly) {
993
1307
  const secondaryStorageTemplate = addTemplate({
994
1308
  filename: "better-auth/secondary-storage.mjs",
995
- getContents: () => buildSecondaryStorageCode(useHubKV),
1309
+ getContents: () => buildSecondaryStorageCode(setup.runtime.useHubKV),
996
1310
  write: true
997
1311
  });
998
1312
  nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
999
- if (hasHubDb && !nuxt.options.alias["hub:db"]) {
1000
- throw new Error("[nuxt-better-auth] hub:db not found. Ensure @nuxthub/core is loaded before this module and hub.db is configured.");
1001
- }
1002
- const setupCtx = { nuxt, options, clientOnly };
1003
- await resolvedProvider.definition.setup?.(setupCtx);
1004
- const buildCtx = { hubDialect, usePlural, camelCase };
1005
1313
  const databaseTemplate = addTemplate({
1006
1314
  filename: "better-auth/database.mjs",
1007
- getContents: () => resolvedProvider.definition.buildDatabaseCode(buildCtx),
1315
+ getContents: () => setup.database.providerDefinition.buildDatabaseCode(setup.database.buildContext),
1008
1316
  write: true
1009
1317
  });
1010
1318
  nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
1011
1319
  const schemaTemplate = addTemplate({
1012
1320
  filename: "better-auth/schema.mjs",
1013
- getContents: () => {
1014
- if (!hasHubDb)
1015
- return "export const schema = undefined\n";
1016
- return `export * from './schema.${hubDialect}.mjs'
1017
- import * as schema from './schema.${hubDialect}.mjs'
1018
- export { schema }
1019
- `;
1020
- },
1321
+ getContents: () => buildSchemaExportCode(setup.database.hasHubDb, setup.database.buildContext?.hubDialect ?? "sqlite"),
1021
1322
  write: true
1022
1323
  });
1023
1324
  nuxt.options.alias["#auth/schema"] = schemaTemplate.dst;
1024
- registerServerTypeTemplates({
1025
- serverConfigPath,
1026
- hasHubDb,
1027
- runtimeTypesPath: resolver.resolve("./runtime/types")
1325
+ }
1326
+ if (setup.prepareTypes) {
1327
+ registerPrepareTypesHook({
1328
+ nuxt,
1329
+ serverDir: setup.prepareTypes.serverDir,
1330
+ hasHubDb: setup.prepareTypes.hasHubDb
1028
1331
  });
1029
- if (hasHubDb)
1030
- await setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, options.hubSecondaryStorage ?? false);
1031
1332
  }
1032
- registerSharedTypeTemplates({
1033
- runtimeTypesAugmentPath: resolver.resolve("./runtime/types/augment"),
1034
- runtimeTypesPath: resolver.resolve("./runtime/types"),
1035
- clientConfigPath
1036
- });
1037
- const runtimeRouteRulesSource = nuxt.options.nitro?.routeRules || nuxt.options.routeRules || {};
1038
- const authRouteRules = Object.fromEntries(
1039
- Object.entries(runtimeRouteRulesSource).flatMap(([path, rule]) => {
1040
- if (!rule || typeof rule !== "object" || !("auth" in rule))
1041
- return [];
1042
- return [[path, { auth: rule.auth }]];
1043
- })
1044
- );
1333
+ if (setup.database.providerDefinition) {
1334
+ const setupCtx = {
1335
+ nuxt,
1336
+ options,
1337
+ clientOnly: setup.clientOnly
1338
+ };
1339
+ await setup.database.providerDefinition.setup?.(setupCtx);
1340
+ }
1045
1341
  const authRouteRulesTemplate = addTemplate({
1046
1342
  filename: "better-auth/route-rules.mjs",
1047
- getContents: () => `export const authRouteRules = ${JSON.stringify(authRouteRules, null, 2)}
1048
- `,
1343
+ getContents: () => buildAuthRouteRulesCode(collectAuthRouteRules(nuxt)),
1049
1344
  write: true
1050
1345
  });
1051
1346
  nuxt.options.alias["#auth/route-rules"] = authRouteRulesTemplate.dst;
1347
+ if (setup.serverTypes) {
1348
+ registerServerTypeTemplates({
1349
+ serverConfigPath: setup.serverTypes.serverConfigPath,
1350
+ hasHubDb: setup.serverTypes.hasHubDb,
1351
+ runtimeTypesPath: resolver.resolve("./runtime/types"),
1352
+ sharedServerConfigSafe: isServerConfigSharedTypeSafe(setup.serverTypes.serverConfigPath)
1353
+ });
1354
+ }
1355
+ if (setup.schemaGeneration) {
1356
+ if (setup.schemaGeneration.externalizeNuxtHubDatabase)
1357
+ registerNuxtHubDatabaseExternalHook(nuxt);
1358
+ await setupBetterAuthSchema(
1359
+ nuxt,
1360
+ setup.schemaGeneration.serverConfigPath,
1361
+ options,
1362
+ consola,
1363
+ setup.schemaGeneration.hubSecondaryStorage
1364
+ );
1365
+ }
1366
+ registerSharedTypeTemplates({
1367
+ runtimeTypesAugmentPath: setup.aliases["#nuxt-better-auth"],
1368
+ runtimeTypesPath: resolver.resolve("./runtime/types"),
1369
+ clientConfigPath: setup.sharedTypes.clientConfigPath
1370
+ });
1052
1371
  registerTemplateHmrHook(nuxt);
1053
- registerServerRuntime({ clientOnly, resolve: resolver.resolve });
1372
+ registerServerRuntime({ clientOnly: setup.clientOnly, resolve: resolver.resolve });
1054
1373
  registerAuthMiddlewareHook(nuxt, resolver.resolve);
1055
- await registerDevtools({ nuxt, clientOnly, hasHubDb, resolve: resolver.resolve });
1374
+ await registerDevtools({ nuxt, clientOnly: setup.clientOnly, hasHubDb: setup.database.hasHubDb, resolve: resolver.resolve });
1056
1375
  registerRouteRulesMetaHook(nuxt);
1057
1376
  }
1058
1377
  });