@onmax/nuxt-better-auth 0.0.2-alpha.26 → 0.0.2-alpha.28

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.
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onmax/nuxt-better-auth",
3
- "version": "0.0.2-alpha.26",
3
+ "version": "0.0.2-alpha.28",
4
4
  "configKey": "auth",
5
5
  "compatibility": {
6
6
  "nuxt": ">=4.0.0"
package/dist/module.mjs CHANGED
@@ -10,7 +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.26";
13
+ const version = "0.0.2-alpha.28";
14
14
 
15
15
  function resolveDatabaseProvider(input) {
16
16
  const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
@@ -122,26 +122,32 @@ function getHubCasing(hub) {
122
122
  return hub.db.casing;
123
123
  }
124
124
 
125
- function resolveSecondaryStorageEnabled(input) {
126
- const { options, clientOnly, hasNuxtHub, hub, consola } = input;
127
- let secondaryStorageEnabled = options.secondaryStorage ?? false;
125
+ function resolveSecondaryStorage(input) {
126
+ const { options, clientOnly, hasNuxtHub, hub } = input;
127
+ const opt = options.hubSecondaryStorage ?? false;
128
+ const useHubKV = opt === true;
129
+ const secondaryStorageEnabled = opt === true || opt === "custom";
128
130
  if (secondaryStorageEnabled && clientOnly) {
129
- consola.warn("secondaryStorage is not available in clientOnly mode. Disabling.");
130
- secondaryStorageEnabled = false;
131
- } else if (secondaryStorageEnabled && (!hasNuxtHub || !hub?.kv)) {
132
- consola.warn("secondaryStorage requires @nuxthub/core with hub.kv: true. Disabling.");
133
- secondaryStorageEnabled = false;
131
+ throw new Error("[nuxt-better-auth] hubSecondaryStorage is not available in clientOnly mode. Either disable clientOnly or remove auth.hubSecondaryStorage.");
134
132
  }
135
- return secondaryStorageEnabled;
133
+ if (useHubKV && (!hasNuxtHub || !hub?.kv)) {
134
+ 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.");
135
+ }
136
+ return { useHubKV, secondaryStorageEnabled };
136
137
  }
137
138
  function setupRuntimeConfig(input) {
138
139
  const { nuxt, options, clientOnly, databaseProvider, consola } = input;
139
- const secondaryStorageEnabled = resolveSecondaryStorageEnabled(input);
140
+ const { useHubKV, secondaryStorageEnabled } = resolveSecondaryStorage(input);
140
141
  nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
141
142
  const configuredSiteUrl = nuxt.options.runtimeConfig.public.siteUrl;
142
143
  if (!configuredSiteUrl && process.env.NUXT_PUBLIC_SITE_URL)
143
144
  nuxt.options.runtimeConfig.public.siteUrl = process.env.NUXT_PUBLIC_SITE_URL;
144
145
  nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
146
+ redirects: {
147
+ login: options.redirects?.login ?? "/login",
148
+ guest: options.redirects?.guest ?? "/",
149
+ logout: options.redirects?.logout
150
+ },
145
151
  preserveRedirect: options.preserveRedirect ?? true,
146
152
  redirectQueryKey: options.redirectQueryKey ?? "redirect",
147
153
  useDatabase: databaseProvider !== "none",
@@ -156,7 +162,7 @@ function setupRuntimeConfig(input) {
156
162
  if (!siteUrl)
157
163
  consola.warn("clientOnly mode: set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) to your frontend URL");
158
164
  consola.info("clientOnly mode enabled - server utilities (serverAuth, getAppSession, getUserSession, requireUserSession) are not available");
159
- return { secondaryStorageEnabled };
165
+ return { useHubKV, secondaryStorageEnabled };
160
166
  }
161
167
  const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
162
168
  nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.BETTER_AUTH_SECRET || "";
@@ -168,9 +174,9 @@ function setupRuntimeConfig(input) {
168
174
  throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET must be at least 32 characters for security");
169
175
  }
170
176
  nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
171
- secondaryStorage: secondaryStorageEnabled
177
+ hubSecondaryStorage: options.hubSecondaryStorage ?? false
172
178
  });
173
- return { secondaryStorageEnabled };
179
+ return { useHubKV, secondaryStorageEnabled };
174
180
  }
175
181
 
176
182
  function dialectToProvider(dialect) {
@@ -236,6 +242,18 @@ async function loadUserAuthConfig(configPath, throwOnError = false) {
236
242
  }
237
243
  }
238
244
 
245
+ function resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, isProduction) {
246
+ if (hubSecondaryStorage === true)
247
+ return { inject: true };
248
+ if (hubSecondaryStorage !== "custom")
249
+ return { inject: false };
250
+ if (userHasSecondaryStorage)
251
+ return { inject: true };
252
+ const message = '[nuxt-better-auth] hubSecondaryStorage: "custom" requires secondaryStorage in defineServerAuth() to omit the session table from the generated schema.';
253
+ if (isProduction)
254
+ return { inject: false, error: message };
255
+ return { inject: false, warn: message };
256
+ }
239
257
  function isInsideNodeModules(path) {
240
258
  return path.split(/[\\/]/).includes("node_modules");
241
259
  }
@@ -260,7 +278,7 @@ async function loadAuthOptions(context) {
260
278
  const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
261
279
  return { userConfig, plugins };
262
280
  }
263
- async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola) {
281
+ async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, hubSecondaryStorage) {
264
282
  const hub = nuxt.options.hub;
265
283
  const dialect = getHubDialect(hub);
266
284
  if (!dialect || !["sqlite", "postgresql", "mysql"].includes(dialect)) {
@@ -270,10 +288,16 @@ async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola) {
270
288
  const context = { nuxt, serverConfigPath };
271
289
  try {
272
290
  const { userConfig, plugins } = await loadAuthOptions(context);
291
+ const userHasSecondaryStorage = userConfig.secondaryStorage != null;
292
+ const secondaryStorageResolution = resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, !nuxt.options.dev);
293
+ if (secondaryStorageResolution.error)
294
+ throw new Error(secondaryStorageResolution.error);
295
+ if (secondaryStorageResolution.warn)
296
+ consola.warn(secondaryStorageResolution.warn);
273
297
  const authOptions = {
274
298
  ...userConfig,
275
299
  plugins,
276
- secondaryStorage: options.secondaryStorage ? { get: async (_key) => null, set: async (_key, _value, _ttl) => {
300
+ secondaryStorage: secondaryStorageResolution.inject ? { get: async (_key) => null, set: async (_key, _value, _ttl) => {
277
301
  }, delete: async (_key) => {
278
302
  } } : void 0
279
303
  };
@@ -328,13 +352,21 @@ function appendSecretToEnv(rootDir, secret) {
328
352
  `;
329
353
  writeFileSync(envPath, content, "utf-8");
330
354
  }
331
- async function promptForSecret(rootDir, consola) {
355
+ async function promptForSecret(rootDir, consola, options = {}) {
356
+ const configuredSecret = options.configuredSecret?.trim();
357
+ if (configuredSecret)
358
+ return void 0;
332
359
  if (process.env.BETTER_AUTH_SECRET || hasEnvSecret(rootDir))
333
360
  return void 0;
361
+ const hasTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
362
+ if (options.prepare || !hasTty) {
363
+ consola.warn("[nuxt-better-auth] Skipping BETTER_AUTH_SECRET prompt (non-interactive). Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET.");
364
+ return void 0;
365
+ }
334
366
  if (isCI || isTest) {
335
367
  const secret2 = generateSecret();
336
368
  appendSecretToEnv(rootDir, secret2);
337
- consola.info("Generated BETTER_AUTH_SECRET and added to .env (CI mode)");
369
+ consola.info("Generated BETTER_AUTH_SECRET and added to .env (CI/test mode)");
338
370
  return secret2;
339
371
  }
340
372
  consola.box("BETTER_AUTH_SECRET is required for authentication.\nThis will be appended to your .env file.");
@@ -375,8 +407,8 @@ Proceed?`, { type: "confirm", initial: true, cancel: "null" });
375
407
  return secret;
376
408
  }
377
409
 
378
- function buildSecondaryStorageCode(enabled) {
379
- if (!enabled)
410
+ function buildSecondaryStorageCode(useHubKV) {
411
+ if (!useHubKV)
380
412
  return "export function createSecondaryStorage() { return undefined }";
381
413
  return `import { kv } from '@nuxthub/kv'
382
414
  export function createSecondaryStorage() {
@@ -587,12 +619,14 @@ const module$1 = defineNuxtModule({
587
619
  clientOnly: false,
588
620
  serverConfig: "server/auth.config",
589
621
  clientConfig: "app/auth.config",
622
+ redirects: { login: "/login", guest: "/" },
590
623
  preserveRedirect: true,
591
624
  redirectQueryKey: "redirect",
592
- secondaryStorage: false
625
+ hubSecondaryStorage: false
593
626
  },
594
627
  async onInstall(nuxt) {
595
- const generatedSecret = await promptForSecret(nuxt.options.rootDir, consola);
628
+ const configuredSecret = nuxt.options.runtimeConfig?.betterAuthSecret;
629
+ const generatedSecret = await promptForSecret(nuxt.options.rootDir, consola, { configuredSecret, prepare: Boolean(nuxt.options._prepare) });
596
630
  if (generatedSecret)
597
631
  process.env.BETTER_AUTH_SECRET = generatedSecret;
598
632
  await createDefaultAuthConfigFiles(nuxt.options.rootDir, nuxt.options.srcDir);
@@ -666,7 +700,7 @@ const module$1 = defineNuxtModule({
666
700
  const resolvedProvider = resolveDatabaseProvider({ providers, context: enabledCtx });
667
701
  databaseProvider = resolvedProvider.id;
668
702
  hasHubDb = databaseProvider === "nuxthub";
669
- const { secondaryStorageEnabled } = setupRuntimeConfig({
703
+ const { useHubKV } = setupRuntimeConfig({
670
704
  nuxt,
671
705
  options,
672
706
  clientOnly,
@@ -675,12 +709,12 @@ const module$1 = defineNuxtModule({
675
709
  hub,
676
710
  consola
677
711
  });
678
- if (secondaryStorageEnabled && !nuxt.options.alias["hub:kv"]) {
712
+ if (useHubKV && !nuxt.options.alias["hub:kv"]) {
679
713
  throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
680
714
  }
681
715
  const secondaryStorageTemplate = addTemplate({
682
716
  filename: "better-auth/secondary-storage.mjs",
683
- getContents: () => buildSecondaryStorageCode(secondaryStorageEnabled),
717
+ getContents: () => buildSecondaryStorageCode(useHubKV),
684
718
  write: true
685
719
  });
686
720
  nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
@@ -715,7 +749,7 @@ export { schema }
715
749
  runtimeTypesPath: resolver.resolve("./runtime/types")
716
750
  });
717
751
  if (hasHubDb)
718
- await setupBetterAuthSchema(nuxt, serverConfigPath, options, consola);
752
+ await setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, options.hubSecondaryStorage ?? false);
719
753
  }
720
754
  registerSharedTypeTemplates({
721
755
  runtimeTypesAugmentPath: resolver.resolve("./runtime/types/augment"),
@@ -1,5 +1,5 @@
1
1
  import createAppAuthClient from "#auth/client";
2
- import { computed, nextTick, useNuxtApp, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
2
+ import { computed, navigateTo, nextTick, useNuxtApp, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
3
3
  import { normalizeAuthActionError } from "../internal/auth-action-error.js";
4
4
  let _sessionSignalListenerBound = false;
5
5
  let _client = null;
@@ -229,8 +229,14 @@ export function useUserSession() {
229
229
  throw new Error("signOut can only be called on client-side");
230
230
  await client.signOut();
231
231
  clearSession();
232
- if (options?.onSuccess)
232
+ if (options?.onSuccess) {
233
233
  await options.onSuccess();
234
+ return;
235
+ }
236
+ const authConfig = runtimeConfig.public.auth;
237
+ const logoutRedirect = authConfig?.redirects?.logout;
238
+ if (logoutRedirect)
239
+ await navigateTo(logoutRedirect);
234
240
  }
235
241
  return {
236
242
  client,
@@ -1,3 +1,5 @@
1
1
  import type { AppAuthClient } from '#nuxt-better-auth';
2
- import type { ActionHandleMap } from '../internal/auth-action-handles.js';
3
- export declare function useUserSignIn(): ActionHandleMap<NonNullable<AppAuthClient>['signIn']>;
2
+ import type { ActionHandleFor } from '../internal/auth-action-handles.js';
3
+ type SignIn = NonNullable<AppAuthClient>['signIn'];
4
+ export declare function useUserSignIn<MethodKey extends keyof SignIn>(method: MethodKey): ActionHandleFor<SignIn[MethodKey]>;
5
+ export {};
@@ -1,5 +1,8 @@
1
1
  import { useUserSession } from "#imports";
2
2
  import { createActionHandles } from "../internal/auth-action-handles.js";
3
- export function useUserSignIn() {
4
- return createActionHandles(() => useUserSession().signIn, "signIn");
3
+ export function useUserSignIn(method) {
4
+ if (method === void 0 || method === null)
5
+ throw new TypeError("useUserSignIn(method) requires a sign-in method key");
6
+ const handles = createActionHandles(() => useUserSession().signIn, "signIn");
7
+ return handles[method];
5
8
  }
@@ -1,3 +1,5 @@
1
1
  import type { AppAuthClient } from '#nuxt-better-auth';
2
- import type { ActionHandleMap } from '../internal/auth-action-handles.js';
3
- export declare function useUserSignUp(): ActionHandleMap<NonNullable<AppAuthClient>['signUp']>;
2
+ import type { ActionHandleFor } from '../internal/auth-action-handles.js';
3
+ type SignUp = NonNullable<AppAuthClient>['signUp'];
4
+ export declare function useUserSignUp<MethodKey extends keyof SignUp>(method: MethodKey): ActionHandleFor<SignUp[MethodKey]>;
5
+ export {};
@@ -1,5 +1,8 @@
1
1
  import { useUserSession } from "#imports";
2
2
  import { createActionHandles } from "../internal/auth-action-handles.js";
3
- export function useUserSignUp() {
4
- return createActionHandles(() => useUserSession().signUp, "signUp");
3
+ export function useUserSignUp(method) {
4
+ if (method === void 0 || method === null)
5
+ throw new TypeError("useUserSignUp(method) requires a sign-up method key");
6
+ const handles = createActionHandles(() => useUserSession().signUp, "signUp");
7
+ return handles[method];
5
8
  }
@@ -1,13 +1,11 @@
1
- import type { ComputedRef, Ref } from 'vue';
1
+ import type { Ref } from 'vue';
2
2
  import type { AuthActionError } from '../../types.js';
3
3
  export type UserAuthActionStatus = 'idle' | 'pending' | 'success' | 'error';
4
4
  export interface UserAuthActionHandle<TArgs extends unknown[], TResult> {
5
5
  execute: (...args: TArgs) => Promise<void>;
6
6
  status: Ref<UserAuthActionStatus>;
7
- pending: ComputedRef<boolean>;
8
7
  data: Ref<TResult | null>;
9
8
  error: Ref<AuthActionError | null>;
10
- errorMessage: ComputedRef<string | null>;
11
9
  }
12
10
  export type ActionHandleFor<T> = T extends (...args: infer A) => Promise<infer R> ? UserAuthActionHandle<A, R> : never;
13
11
  export type ActionHandleMap<T> = {
@@ -1,4 +1,4 @@
1
- import { computed, ref } from "#imports";
1
+ import { ref } from "#imports";
2
2
  import { normalizeAuthActionError } from "./auth-action-error.js";
3
3
  function isRecord(value) {
4
4
  return Boolean(value && typeof value === "object");
@@ -14,8 +14,6 @@ function createActionHandle(getMethod) {
14
14
  const status = ref("idle");
15
15
  const data = ref(null);
16
16
  const error = ref(null);
17
- const pending = computed(() => status.value === "pending");
18
- const errorMessage = computed(() => error.value?.message ?? null);
19
17
  let latestCallId = 0;
20
18
  const run = async (...args) => {
21
19
  const callId = ++latestCallId;
@@ -53,10 +51,8 @@ function createActionHandle(getMethod) {
53
51
  return {
54
52
  execute,
55
53
  status,
56
- pending,
57
54
  data,
58
- error,
59
- errorMessage
55
+ error
60
56
  };
61
57
  }
62
58
  export function createActionHandles(getTarget, targetName) {
@@ -25,13 +25,13 @@ export default defineNuxtRouteMiddleware(async (to) => {
25
25
  const redirectTo = typeof auth === "object" ? auth.redirectTo : void 0;
26
26
  if (mode === "guest") {
27
27
  if (loggedIn.value)
28
- return navigateTo(redirectTo ?? "/");
28
+ return navigateTo(redirectTo ?? config?.redirects?.guest ?? "/");
29
29
  return;
30
30
  }
31
31
  if (!loggedIn.value) {
32
32
  const resolved = resolveLoginRedirect({
33
33
  route: to,
34
- loginTarget: redirectTo ?? "/login",
34
+ loginTarget: redirectTo ?? config?.redirects?.login ?? "/login",
35
35
  config
36
36
  });
37
37
  return resolved.external ? navigateTo(resolved.to, { external: true }) : navigateTo(resolved.to);
@@ -379,8 +379,8 @@ function getAccountActions(row) {
379
379
  </UBadge>
380
380
  </div>
381
381
  <div class="config-row">
382
- <span class="config-label">KV</span><UBadge :color="configData.config.module?.secondaryStorage ? 'success' : 'neutral'" variant="subtle" size="sm">
383
- {{ configData.config.module?.secondaryStorage ? "On" : "Off" }}
382
+ <span class="config-label">KV</span><UBadge :color="configData.config.module?.hubSecondaryStorage ? 'success' : 'neutral'" variant="subtle" size="sm">
383
+ {{ configData.config.module?.hubSecondaryStorage ? configData.config.module.hubSecondaryStorage === "custom" ? "Custom" : "On" : "Off" }}
384
384
  </UBadge>
385
385
  </div>
386
386
  </div>
@@ -24,6 +24,14 @@ export interface BetterAuthModuleOptions {
24
24
  serverConfig?: string;
25
25
  /** Client config path relative to rootDir. Default: 'app/auth.config' */
26
26
  clientConfig?: string;
27
+ redirects?: {
28
+ /** Where to redirect unauthenticated users. Default: '/login' */
29
+ login?: string;
30
+ /** Where to redirect authenticated users on guest-only routes. Default: '/' */
31
+ guest?: string;
32
+ /** Where to navigate after logout. Default: no automatic navigation */
33
+ logout?: string;
34
+ };
27
35
  /**
28
36
  * When redirecting unauthenticated users to the login route, append a query param
29
37
  * containing the originally requested path (for safe "return-to" redirects).
@@ -47,8 +55,13 @@ export interface BetterAuthModuleOptions {
47
55
  */
48
56
  skipHydratedSsrGetSession?: boolean;
49
57
  };
50
- /** Enable KV secondary storage for sessions. Requires hub.kv: true */
51
- secondaryStorage?: boolean;
58
+ /**
59
+ * Enable secondary storage for sessions.
60
+ * - `true`: Use NuxtHub KV (requires hub.kv: true)
61
+ * - `'custom'`: User provides own secondaryStorage in defineServerAuth()
62
+ * - `false` (default): No secondary storage from module
63
+ */
64
+ hubSecondaryStorage?: boolean | 'custom';
52
65
  /** Schema generation options. Must match drizzleAdapter config. */
53
66
  schema?: {
54
67
  /** Plural table names: user → users. Default: false */
@@ -58,6 +71,11 @@ export interface BetterAuthModuleOptions {
58
71
  };
59
72
  }
60
73
  export interface AuthRuntimeConfig {
74
+ redirects: {
75
+ login: string;
76
+ guest: string;
77
+ logout?: string;
78
+ };
61
79
  preserveRedirect: boolean;
62
80
  redirectQueryKey: string;
63
81
  useDatabase: boolean;
@@ -68,7 +86,7 @@ export interface AuthRuntimeConfig {
68
86
  };
69
87
  }
70
88
  export interface AuthPrivateRuntimeConfig {
71
- secondaryStorage: boolean;
89
+ hubSecondaryStorage: boolean | 'custom';
72
90
  }
73
91
  export declare function defineServerAuth<const R>(config: (ctx: ServerAuthContext) => R & ServerAuthConfig): (ctx: ServerAuthContext) => R;
74
92
  export declare function defineServerAuth<const R>(config: R & ServerAuthConfig): (ctx: ServerAuthContext) => R;
@@ -1,9 +1,14 @@
1
1
  declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
2
2
  config: {
3
3
  module: {
4
+ redirects: {
5
+ login: string;
6
+ guest: string;
7
+ logout: string | undefined;
8
+ };
4
9
  preserveRedirect: boolean;
5
10
  redirectQueryKey: string;
6
- secondaryStorage: boolean;
11
+ hubSecondaryStorage: boolean | "custom";
7
12
  useDatabase: boolean;
8
13
  databaseProvider: "none" | "nuxthub";
9
14
  };
@@ -18,9 +18,14 @@ export default defineEventHandler(async (event) => {
18
18
  config: {
19
19
  // Module config (nuxt.config.ts)
20
20
  module: {
21
+ redirects: {
22
+ login: publicAuth?.redirects?.login ?? "/login",
23
+ guest: publicAuth?.redirects?.guest ?? "/",
24
+ logout: publicAuth?.redirects?.logout
25
+ },
21
26
  preserveRedirect: publicAuth?.preserveRedirect ?? true,
22
27
  redirectQueryKey: publicAuth?.redirectQueryKey ?? "redirect",
23
- secondaryStorage: privateAuth?.secondaryStorage ?? false,
28
+ hubSecondaryStorage: privateAuth?.hubSecondaryStorage ?? false,
24
29
  useDatabase: publicAuth?.useDatabase ?? false,
25
30
  databaseProvider: publicAuth?.databaseProvider ?? "none"
26
31
  },
@@ -5,8 +5,10 @@ import { betterAuth } from "better-auth";
5
5
  import { getRequestHost, getRequestProtocol } from "h3";
6
6
  import { useRuntimeConfig } from "nitropack/runtime";
7
7
  import { withoutProtocol } from "ufo";
8
+ import { resolveCustomSecondaryStorageRequirement } from "./custom-secondary-storage.js";
8
9
  const _authCache = /* @__PURE__ */ new Map();
9
10
  let _baseURLInferenceLogged = false;
11
+ let _customSecondaryStorageMisconfigWarned = false;
10
12
  function normalizeLoopbackOrigin(origin) {
11
13
  if (!import.meta.dev)
12
14
  return origin;
@@ -189,10 +191,18 @@ export function serverAuth(event) {
189
191
  const database = createDatabase();
190
192
  const userConfig = createServerAuth({ runtimeConfig, db });
191
193
  const trustedOrigins = withDevTrustedOrigins(userConfig.trustedOrigins, Boolean(hasExplicitSiteUrl));
194
+ const hubSecondaryStorage = runtimeConfig.auth?.hubSecondaryStorage;
195
+ const customSecondaryStorage = resolveCustomSecondaryStorageRequirement(hubSecondaryStorage, userConfig.secondaryStorage != null, Boolean(import.meta.dev));
196
+ if (customSecondaryStorage?.shouldThrow)
197
+ throw new Error(customSecondaryStorage.message);
198
+ if (customSecondaryStorage?.shouldWarn && !_customSecondaryStorageMisconfigWarned) {
199
+ _customSecondaryStorageMisconfigWarned = true;
200
+ console.warn(customSecondaryStorage.message);
201
+ }
192
202
  const auth = betterAuth({
193
203
  ...userConfig,
194
204
  ...database && { database },
195
- secondaryStorage: createSecondaryStorage(),
205
+ ...hubSecondaryStorage === true && { secondaryStorage: createSecondaryStorage() },
196
206
  secret: runtimeConfig.betterAuthSecret,
197
207
  baseURL: siteUrl,
198
208
  trustedOrigins
@@ -0,0 +1,6 @@
1
+ export type HubSecondaryStorageMode = boolean | 'custom' | undefined;
2
+ export declare function resolveCustomSecondaryStorageRequirement(hubSecondaryStorage: HubSecondaryStorageMode, userHasSecondaryStorage: boolean, isDev: boolean): {
3
+ shouldThrow: boolean;
4
+ shouldWarn: boolean;
5
+ message: string;
6
+ } | null;
@@ -0,0 +1,8 @@
1
+ export function resolveCustomSecondaryStorageRequirement(hubSecondaryStorage, userHasSecondaryStorage, isDev) {
2
+ if (hubSecondaryStorage !== "custom")
3
+ return null;
4
+ if (userHasSecondaryStorage)
5
+ return null;
6
+ const message = '[nuxt-better-auth] hubSecondaryStorage: "custom" requires secondaryStorage in defineServerAuth().';
7
+ return { shouldThrow: !isDev, shouldWarn: isDev, message };
8
+ }
@@ -1,5 +1,5 @@
1
+ import type { AuthUser, UserMatch } from '#nuxt-better-auth';
1
2
  import type { NitroRouteRules } from 'nitropack/types';
2
- import type { AuthUser, UserMatch } from './types/augment.js';
3
3
  export type { AppSession, AuthSession, AuthUser, RequireSessionOptions, ServerAuthContext, UserMatch, UserSessionComposable } from './types/augment.js';
4
4
  export type { Auth, InferPluginTypes, InferSessionFromClient as InferSession, InferUserFromClient as InferUser } from 'better-auth';
5
5
  export interface AuthActionError {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@onmax/nuxt-better-auth",
3
3
  "type": "module",
4
- "version": "0.0.2-alpha.26",
4
+ "version": "0.0.2-alpha.28",
5
5
  "packageManager": "pnpm@10.15.1",
6
6
  "description": "Nuxt module for Better Auth integration with NuxtHub, route protection, session management, and role-based access",
7
7
  "author": "onmax",