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

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.d.mts CHANGED
@@ -5,15 +5,6 @@ export { BetterAuthModuleOptions, defineClientAuth, defineServerAuth } from '../
5
5
  import { BetterAuthOptions } from 'better-auth';
6
6
  export { AppSession, Auth, AuthActionError, AuthMeta, AuthMode, AuthRouteRules, AuthSession, AuthSocialProviderId, AuthUser, InferSession, InferUser, RequireSessionOptions, ServerAuthContext, UserMatch } from '../dist/runtime/types.js';
7
7
 
8
- interface RuntimeDefineServerAuthFn {
9
- (...args: unknown[]): unknown;
10
- _count: number;
11
- }
12
- declare global {
13
- var __nuxtBetterAuthDefineServerAuth: RuntimeDefineServerAuthFn | undefined;
14
- var defineServerAuth: RuntimeDefineServerAuthFn | undefined;
15
- }
16
-
17
8
  type DbDialect = 'sqlite' | 'postgresql' | 'mysql';
18
9
 
19
10
  interface BetterAuthDatabaseProviderBuildContext {
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onmax/nuxt-better-auth",
3
- "version": "0.0.2-alpha.30",
3
+ "version": "0.0.2-alpha.31",
4
4
  "configKey": "auth",
5
5
  "compatibility": {
6
6
  "nuxt": ">=4.0.0"
package/dist/module.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { existsSync, writeFileSync, readFileSync } from 'node:fs';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
- import { updateTemplates, addServerImportsDir, addServerImports, addServerScanDir, addServerHandler, addImportsDir, addPlugin, addComponentsDir, hasNuxtModule, installModule, extendPages, addTemplate, addTypeTemplate, defineNuxtModule, createResolver } from '@nuxt/kit';
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';
5
- import { join, dirname } from 'pathe';
5
+ import { isAbsolute, join, relative, dirname } from 'pathe';
6
6
  import { defu } from 'defu';
7
7
  import { toRouteMatcher, createRouter } from 'radix3';
8
8
  import { generateDrizzleSchema as generateDrizzleSchema$1 } from '@better-auth/cli/api';
@@ -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.30";
13
+ const version = "0.0.2-alpha.31";
14
14
 
15
15
  function resolveDatabaseProvider(input) {
16
16
  const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
@@ -22,6 +22,91 @@ function resolveDatabaseProvider(input) {
22
22
  return { id, definition };
23
23
  }
24
24
 
25
+ const CONFIG_EXTENSIONS = [".ts", ".js"];
26
+ const CONFIG_EXTENSION_RE = /\.(?:ts|js)$/;
27
+ const DEFAULT_CONFIG_FILES = {
28
+ server: "server/auth.config",
29
+ client: "app/auth.config"
30
+ };
31
+ const OPTION_KEY_BY_KIND = {
32
+ server: "serverConfig",
33
+ client: "clientConfig"
34
+ };
35
+ function stripConfigExtension(path) {
36
+ return path.replace(CONFIG_EXTENSION_RE, "");
37
+ }
38
+ function configExists(path) {
39
+ return CONFIG_EXTENSIONS.some((ext) => existsSync(`${path}${ext}`));
40
+ }
41
+ function getLayerDirectoriesWithConfigs(nuxt) {
42
+ const directories = getLayerDirectories(nuxt);
43
+ const layers = nuxt.options._layers;
44
+ return directories.map((directory, index) => ({ directory, layer: layers[index] }));
45
+ }
46
+ function getProjectDirectory(nuxt) {
47
+ return getLayerDirectories(nuxt)[0];
48
+ }
49
+ function getDefaultConfigPath(nuxt, kind) {
50
+ const project = getProjectDirectory(nuxt);
51
+ return kind === "server" ? join(project.server, "auth.config") : join(project.app, "auth.config");
52
+ }
53
+ function getLayerDefaultConfigPath(nuxt, kind) {
54
+ for (const { directory } of getLayerDirectoriesWithConfigs(nuxt)) {
55
+ const candidate = kind === "server" ? join(directory.server, "auth.config") : join(directory.app, "auth.config");
56
+ if (configExists(candidate))
57
+ return candidate;
58
+ }
59
+ }
60
+ function resolveDeclaringLayerRoot(nuxt, kind, file) {
61
+ const optionKey = OPTION_KEY_BY_KIND[kind];
62
+ for (const { directory, layer } of getLayerDirectoriesWithConfigs(nuxt)) {
63
+ const declared = layer?.config?.auth?.[optionKey];
64
+ if (typeof declared === "string" && stripConfigExtension(declared) === file)
65
+ return directory.root;
66
+ }
67
+ return getProjectDirectory(nuxt).root;
68
+ }
69
+ function getRelativeConfigFile(nuxt, path) {
70
+ return relative(getProjectDirectory(nuxt).root, path);
71
+ }
72
+ function getEffectiveModuleConfigFile(nuxt, kind) {
73
+ const optionKey = OPTION_KEY_BY_KIND[kind];
74
+ const authOptions = nuxt.options.auth;
75
+ return authOptions?.[optionKey] ?? DEFAULT_CONFIG_FILES[kind];
76
+ }
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)) {
87
+ return {
88
+ file: normalizedFile,
89
+ path: normalizedFile,
90
+ isDefault: false
91
+ };
92
+ }
93
+ if (normalizedFile === DEFAULT_CONFIG_FILES[kind]) {
94
+ const discoveredPath = getLayerDefaultConfigPath(nuxt, kind) ?? getDefaultConfigPath(nuxt, kind);
95
+ return {
96
+ file: getRelativeConfigFile(nuxt, discoveredPath),
97
+ path: discoveredPath,
98
+ isDefault: true
99
+ };
100
+ }
101
+ const baseRoot = resolveDeclaringLayerRoot(nuxt, kind, normalizedFile);
102
+ const path = join(baseRoot, normalizedFile);
103
+ return {
104
+ file: getRelativeConfigFile(nuxt, path),
105
+ path,
106
+ isDefault: false
107
+ };
108
+ }
109
+
25
110
  function setupDevTools(nuxt) {
26
111
  const hookable = nuxt;
27
112
  hookable.hook("devtools:customTabs", (tabs) => {
@@ -167,13 +252,13 @@ function setupRuntimeConfig(input) {
167
252
  return { useHubKV, secondaryStorageEnabled };
168
253
  }
169
254
  const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
170
- nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.BETTER_AUTH_SECRET || "";
255
+ nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || "";
171
256
  const betterAuthSecret = nuxt.options.runtimeConfig.betterAuthSecret;
172
257
  if (!nuxt.options.dev && !nuxt.options._prepare && !betterAuthSecret) {
173
- throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET is required in production. Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET environment variable.");
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.");
174
259
  }
175
260
  if (betterAuthSecret && betterAuthSecret.length < 32) {
176
- throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET must be at least 32 characters for security");
261
+ throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET must be at least 32 characters for security");
177
262
  }
178
263
  nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
179
264
  hubSecondaryStorage: options.hubSecondaryStorage ?? false
@@ -217,14 +302,15 @@ async function loadUserAuthConfig(configPath, throwOnError = false) {
217
302
  const { createJiti } = await import('jiti');
218
303
  const { defineServerAuth: runtimeDefineServerAuth } = await import('../dist/runtime/config.js');
219
304
  const jiti = createJiti(import.meta.url, { interopDefault: true, moduleCache: false });
220
- if (!globalThis.__nuxtBetterAuthDefineServerAuth) {
305
+ const schemaGlobals = globalThis;
306
+ if (!schemaGlobals.__nuxtBetterAuthDefineServerAuth) {
221
307
  runtimeDefineServerAuth._count = 0;
222
- globalThis.__nuxtBetterAuthDefineServerAuth = runtimeDefineServerAuth;
308
+ schemaGlobals.__nuxtBetterAuthDefineServerAuth = runtimeDefineServerAuth;
223
309
  }
224
- if (!globalThis.defineServerAuth) {
225
- globalThis.defineServerAuth = globalThis.__nuxtBetterAuthDefineServerAuth;
310
+ if (!schemaGlobals.defineServerAuth) {
311
+ schemaGlobals.defineServerAuth = schemaGlobals.__nuxtBetterAuthDefineServerAuth;
226
312
  }
227
- globalThis.__nuxtBetterAuthDefineServerAuth._count++;
313
+ schemaGlobals.__nuxtBetterAuthDefineServerAuth._count++;
228
314
  try {
229
315
  const mod = await jiti.import(configPath);
230
316
  const configFn = mod.default;
@@ -243,19 +329,20 @@ async function loadUserAuthConfig(configPath, throwOnError = false) {
243
329
  consola$1.error("[@onmax/nuxt-better-auth] Failed to load auth config for schema generation. Schema may be incomplete:", error);
244
330
  return {};
245
331
  } finally {
246
- const sharedDefineServerAuth = globalThis.__nuxtBetterAuthDefineServerAuth;
332
+ const sharedDefineServerAuth = schemaGlobals.__nuxtBetterAuthDefineServerAuth;
247
333
  if (sharedDefineServerAuth) {
248
334
  sharedDefineServerAuth._count--;
249
335
  if (!sharedDefineServerAuth._count) {
250
- globalThis.__nuxtBetterAuthDefineServerAuth = void 0;
251
- if (globalThis.defineServerAuth === sharedDefineServerAuth) {
252
- globalThis.defineServerAuth = void 0;
336
+ schemaGlobals.__nuxtBetterAuthDefineServerAuth = void 0;
337
+ if (schemaGlobals.defineServerAuth === sharedDefineServerAuth) {
338
+ schemaGlobals.defineServerAuth = void 0;
253
339
  }
254
340
  }
255
341
  }
256
342
  }
257
343
  }
258
344
 
345
+ const NODE_MODULES_SEGMENT_RE = /[\\/]/;
259
346
  function resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, isProduction) {
260
347
  if (hubSecondaryStorage === true)
261
348
  return { inject: false };
@@ -269,7 +356,7 @@ function resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSeco
269
356
  return { inject: false, warn: message };
270
357
  }
271
358
  function isInsideNodeModules(path) {
272
- return path.split(/[\\/]/).includes("node_modules");
359
+ return path.split(NODE_MODULES_SEGMENT_RE).includes("node_modules");
273
360
  }
274
361
  function resolveHubSchemaPath(buildDir, rootDir, dialect, exists = existsSync) {
275
362
  const rootTsPath = join(rootDir, ".nuxt", "better-auth", `schema.${dialect}.ts`);
@@ -348,21 +435,26 @@ async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, h
348
435
  }
349
436
  }
350
437
 
438
+ const DEFAULT_SECRET_ENV = "NUXT_BETTER_AUTH_SECRET";
439
+ const FALLBACK_SECRET_ENV = "BETTER_AUTH_SECRET";
351
440
  const generateSecret = () => randomBytes(32).toString("hex");
352
441
  function readEnvFile(rootDir) {
353
442
  const envPath = join(rootDir, ".env");
354
443
  return existsSync(envPath) ? readFileSync(envPath, "utf-8") : "";
355
444
  }
356
445
  function hasEnvSecret(rootDir) {
357
- const match = readEnvFile(rootDir).match(/^BETTER_AUTH_SECRET=(.+)$/m);
358
- return !!match && !!match[1] && match[1].trim().length > 0;
446
+ const envFile = readEnvFile(rootDir);
447
+ return [DEFAULT_SECRET_ENV, FALLBACK_SECRET_ENV].some((name) => {
448
+ const match = envFile.match(new RegExp(`^${name}=(.+)$`, "m"));
449
+ return !!match && !!match[1] && match[1].trim().length > 0;
450
+ });
359
451
  }
360
452
  function appendSecretToEnv(rootDir, secret) {
361
453
  const envPath = join(rootDir, ".env");
362
454
  let content = readEnvFile(rootDir);
363
455
  if (content.length > 0 && !content.endsWith("\n"))
364
456
  content += "\n";
365
- content += `BETTER_AUTH_SECRET=${secret}
457
+ content += `${DEFAULT_SECRET_ENV}=${secret}
366
458
  `;
367
459
  writeFileSync(envPath, content, "utf-8");
368
460
  }
@@ -370,20 +462,20 @@ async function promptForSecret(rootDir, consola, options = {}) {
370
462
  const configuredSecret = options.configuredSecret?.trim();
371
463
  if (configuredSecret)
372
464
  return void 0;
373
- if (process.env.BETTER_AUTH_SECRET || hasEnvSecret(rootDir))
465
+ if (process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || hasEnvSecret(rootDir))
374
466
  return void 0;
375
467
  const hasTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
376
468
  if (options.prepare || !hasTty) {
377
- consola.warn("[nuxt-better-auth] Skipping BETTER_AUTH_SECRET prompt (non-interactive). Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET.");
469
+ consola.warn("[nuxt-better-auth] Skipping NUXT_BETTER_AUTH_SECRET prompt (non-interactive). Set NUXT_BETTER_AUTH_SECRET or BETTER_AUTH_SECRET.");
378
470
  return void 0;
379
471
  }
380
472
  if (isCI || isTest) {
381
473
  const secret2 = generateSecret();
382
474
  appendSecretToEnv(rootDir, secret2);
383
- consola.info("Generated BETTER_AUTH_SECRET and added to .env (CI/test mode)");
475
+ consola.info("Generated NUXT_BETTER_AUTH_SECRET and added to .env (CI/test mode)");
384
476
  return secret2;
385
477
  }
386
- consola.box("BETTER_AUTH_SECRET is required for authentication.\nThis will be appended to your .env file.");
478
+ consola.box("NUXT_BETTER_AUTH_SECRET is required for authentication.\nThis will be appended to your .env file.\nBETTER_AUTH_SECRET is still supported as a fallback.");
387
479
  const choice = await consola.prompt("How do you want to set it?", {
388
480
  type: "select",
389
481
  options: [
@@ -394,7 +486,7 @@ async function promptForSecret(rootDir, consola, options = {}) {
394
486
  cancel: "null"
395
487
  });
396
488
  if (typeof choice === "symbol" || choice === "skip") {
397
- consola.warn("Skipping BETTER_AUTH_SECRET. Auth will fail without it in production.");
489
+ consola.warn("Skipping NUXT_BETTER_AUTH_SECRET. Auth will fail without it in production.");
398
490
  return void 0;
399
491
  }
400
492
  let secret;
@@ -410,14 +502,14 @@ async function promptForSecret(rootDir, consola, options = {}) {
410
502
  }
411
503
  const preview = `${secret.slice(0, 8)}...${secret.slice(-4)}`;
412
504
  const confirm = await consola.prompt(`Add to .env:
413
- BETTER_AUTH_SECRET=${preview}
505
+ ${DEFAULT_SECRET_ENV}=${preview}
414
506
  Proceed?`, { type: "confirm", initial: true, cancel: "null" });
415
507
  if (typeof confirm === "symbol" || !confirm) {
416
508
  consola.info("Cancelled. Secret not written.");
417
509
  return void 0;
418
510
  }
419
511
  appendSecretToEnv(rootDir, secret);
420
- consola.success("Added BETTER_AUTH_SECRET to .env");
512
+ consola.success("Added NUXT_BETTER_AUTH_SECRET to .env");
421
513
  return secret;
422
514
  }
423
515
 
@@ -778,15 +870,13 @@ declare module '#nuxt-better-auth' {
778
870
  }
779
871
 
780
872
  const consola = consola$1.withTag("nuxt-better-auth");
781
- function resolveDefaultClientConfig(options, rootDir, srcDir) {
782
- if (options.clientConfig !== "app/auth.config")
783
- return;
784
- const srcDirRelative = srcDir.replace(`${rootDir}/`, "");
785
- options.clientConfig = srcDirRelative === srcDir ? "auth.config" : `${srcDirRelative}/auth.config`;
786
- }
787
- async function createDefaultAuthConfigFiles(rootDir, srcDir) {
788
- const serverPath = join(rootDir, "server/auth.config.ts");
789
- const clientPath = join(srcDir, "auth.config.ts");
873
+ 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");
790
880
  const serverTemplate = `import { defineServerAuth } from '@onmax/nuxt-better-auth/config'
791
881
 
792
882
  export default defineServerAuth({
@@ -797,16 +887,15 @@ export default defineServerAuth({
797
887
 
798
888
  export default defineClientAuth({})
799
889
  `;
800
- if (!existsSync(serverPath)) {
890
+ if (shouldCreateDefaultModuleConfig(nuxt, "server", serverConfigFile)) {
801
891
  await mkdir(dirname(serverPath), { recursive: true });
802
892
  await writeFile(serverPath, serverTemplate);
803
- consola.success("Created server/auth.config.ts");
893
+ consola.success(`Created ${relative(rootDir, serverPath)}`);
804
894
  }
805
- if (!existsSync(clientPath)) {
895
+ if (shouldCreateDefaultModuleConfig(nuxt, "client", clientConfigFile)) {
806
896
  await mkdir(dirname(clientPath), { recursive: true });
807
897
  await writeFile(clientPath, clientTemplate);
808
- const relativePath = clientPath.replace(`${rootDir}/`, "");
809
- consola.success(`Created ${relativePath}`);
898
+ consola.success(`Created ${relative(rootDir, clientPath)}`);
810
899
  }
811
900
  }
812
901
  const module$1 = defineNuxtModule({
@@ -824,32 +913,25 @@ const module$1 = defineNuxtModule({
824
913
  const configuredSecret = nuxt.options.runtimeConfig?.betterAuthSecret;
825
914
  const generatedSecret = await promptForSecret(nuxt.options.rootDir, consola, { configuredSecret, prepare: Boolean(nuxt.options._prepare) });
826
915
  if (generatedSecret)
827
- process.env.BETTER_AUTH_SECRET = generatedSecret;
828
- await createDefaultAuthConfigFiles(nuxt.options.rootDir, nuxt.options.srcDir);
916
+ process.env.NUXT_BETTER_AUTH_SECRET = generatedSecret;
917
+ await createDefaultAuthConfigFiles(nuxt);
829
918
  },
830
919
  async setup(options, nuxt) {
831
920
  const resolver = createResolver(import.meta.url);
832
- resolveDefaultClientConfig(options, nuxt.options.rootDir, nuxt.options.srcDir);
833
921
  const clientOnly = options.clientOnly;
834
922
  const serverConfigFile = options.serverConfig;
835
923
  const clientConfigFile = options.clientConfig;
836
- const serverConfigPath = resolver.resolve(nuxt.options.rootDir, serverConfigFile);
837
- const clientConfigPath = resolver.resolve(nuxt.options.rootDir, clientConfigFile);
924
+ const { file: resolvedServerConfigFile, path: serverConfigPath } = resolveModuleConfigPath(nuxt, "server", serverConfigFile);
925
+ const { file: resolvedClientConfigFile, path: clientConfigPath } = resolveModuleConfigPath(nuxt, "client", clientConfigFile);
838
926
  const serverConfigExists = existsSync(`${serverConfigPath}.ts`) || existsSync(`${serverConfigPath}.js`);
839
927
  const clientConfigExists = existsSync(`${clientConfigPath}.ts`) || existsSync(`${clientConfigPath}.js`);
840
928
  if (!clientOnly && !serverConfigExists)
841
- throw new Error(`[nuxt-better-auth] Missing ${serverConfigFile}.ts - export default defineServerAuth(...)`);
929
+ throw new Error(`[nuxt-better-auth] Missing ${resolvedServerConfigFile}.ts - export default defineServerAuth(...)`);
842
930
  if (!clientConfigExists)
843
- throw new Error(`[nuxt-better-auth] Missing ${clientConfigFile}.ts - export default defineClientAuth(...)`);
931
+ throw new Error(`[nuxt-better-auth] Missing ${resolvedClientConfigFile}.ts - export default defineClientAuth(...)`);
844
932
  const hasNuxtHub = hasNuxtModule("@nuxthub/core", nuxt);
845
933
  const hub = hasNuxtHub ? nuxt.options.hub : void 0;
846
934
  const hasHubDbAvailable = !clientOnly && hasNuxtHub && !!hub?.db;
847
- const deprecatedProvider = options.database?.provider;
848
- if (deprecatedProvider) {
849
- throw new Error(
850
- `[nuxt-better-auth] auth.database.provider has been removed. Remove auth.database.provider="${deprecatedProvider}". To configure a database, either set "database" directly in server/auth.config.ts (defineServerAuth) or install a provider module that registers better-auth:database:providers.`
851
- );
852
- }
853
935
  let databaseProvider = "none";
854
936
  let hasHubDb = false;
855
937
  nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
@@ -1,11 +1,13 @@
1
1
  import createAppAuthClient from "#auth/client";
2
- import { computed, navigateTo, nextTick, useNuxtApp, useRequestFetch, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
2
+ import { computed, navigateTo, nextTick, useNuxtApp, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
3
3
  import { normalizeAuthActionError } from "../internal/auth-action-error.js";
4
+ import { resolvePostAuthSuccessRedirect, withFallbackSocialCallbackURL } from "../internal/redirect-helpers.js";
5
+ import { fetchSessionClient, fetchSessionServer, stripToken } from "../internal/session-fetch.js";
6
+ import { isRecord } from "../internal/utils.js";
7
+ import { wrapAuthMethod } from "../internal/wrap-auth-method.js";
4
8
  let _sessionSignalListenerBound = false;
9
+ let _signOutPromise = null;
5
10
  let _client = null;
6
- function isRecord(value) {
7
- return Boolean(value && typeof value === "object");
8
- }
9
11
  function getClient(baseURL) {
10
12
  if (!_client)
11
13
  _client = createAppAuthClient(baseURL);
@@ -88,6 +90,12 @@ export function useUserSession() {
88
90
  session.value = null;
89
91
  user.value = null;
90
92
  }
93
+ async function fetchSession(options = {}) {
94
+ if (runtimeFlags.server)
95
+ return fetchSessionServer(session, user, authReady, options);
96
+ if (client)
97
+ return fetchSessionClient(client, session, user, authReady, options);
98
+ }
91
99
  async function updateUser(updates) {
92
100
  if (!user.value)
93
101
  return;
@@ -122,8 +130,7 @@ export function useUserSession() {
122
130
  if (shouldWaitForPrerenderResolution)
123
131
  return;
124
132
  if (newSession?.data?.session && newSession?.data?.user) {
125
- const { token: _, ...safeSession } = newSession.data.session;
126
- session.value = safeSession;
133
+ session.value = stripToken(newSession.data.session);
127
134
  user.value = newSession.data.user;
128
135
  } else if (!newSession?.isPending && !newSession?.isRefetching) {
129
136
  const isHydrationEmptySnapshot = nuxtApp.isHydrating && nuxtApp.payload.serverRendered && Boolean(session.value && user.value) && !newSession?.data?.session && !newSession?.data?.user;
@@ -163,107 +170,12 @@ export function useUserSession() {
163
170
  }, 5e3);
164
171
  });
165
172
  }
166
- function isSafeLocalRedirect(redirect) {
167
- if (typeof redirect !== "string")
168
- return;
169
- if (!redirect.startsWith("/") || redirect.startsWith("//"))
170
- return;
171
- return redirect;
172
- }
173
- function resolvePostAuthRedirect() {
174
- const authConfig = runtimeConfig.public.auth;
175
- const redirectQueryKey = authConfig?.redirectQueryKey ?? "redirect";
176
- const queryRedirect = requestURL.searchParams?.get(redirectQueryKey);
177
- const safeQueryRedirect = isSafeLocalRedirect(queryRedirect);
178
- if (safeQueryRedirect)
179
- return safeQueryRedirect;
180
- return isSafeLocalRedirect(authConfig?.redirects?.authenticated);
181
- }
182
- function resolvePostAuthSuccessRedirect() {
183
- const target = resolvePostAuthRedirect();
184
- if (!target)
185
- return;
186
- return async () => {
187
- await navigateTo(target);
188
- };
189
- }
190
- function withFallbackSocialCallbackURL(data) {
191
- const callbackURL = resolvePostAuthRedirect();
192
- if (!callbackURL)
193
- return data;
194
- if (!isRecord(data))
195
- return { callbackURL };
196
- if (typeof data.callbackURL === "string")
197
- return data;
198
- return {
199
- ...data,
200
- callbackURL
201
- };
202
- }
203
- function wrapOnSuccess(cb) {
204
- return async (ctx) => {
205
- await fetchSession({ force: true });
206
- if (!loggedIn.value)
207
- await waitForSession();
208
- await nextTick();
209
- await cb(ctx);
210
- };
211
- }
212
- function wrapAuthMethod(method, wrapOptions = {}) {
213
- return (async (...args) => {
214
- const originalData = args[0];
215
- const options = args[1];
216
- const data = wrapOptions.transformData?.(originalData, options) ?? originalData;
217
- const dataRecord = isRecord(data) ? data : void 0;
218
- const optionsRecord = isRecord(options) ? options : void 0;
219
- if (wrapOptions.shouldSkipSessionSync?.(data, options))
220
- return method(data, options);
221
- const fetchOptions = isRecord(dataRecord?.fetchOptions) ? dataRecord.fetchOptions : void 0;
222
- const nestedOnSuccess = fetchOptions?.onSuccess;
223
- const topLevelOnSuccess = optionsRecord?.onSuccess;
224
- const fallbackOnSuccess = resolvePostAuthSuccessRedirect();
225
- const wrappedFallbackOnSuccess = fallbackOnSuccess && wrapOnSuccess(async () => {
226
- if (!loggedIn.value)
227
- return;
228
- await fallbackOnSuccess();
229
- });
230
- if (typeof nestedOnSuccess === "function") {
231
- const nextData = {
232
- ...dataRecord,
233
- fetchOptions: {
234
- ...fetchOptions,
235
- onSuccess: wrapOnSuccess(nestedOnSuccess)
236
- }
237
- };
238
- return method(nextData, options);
239
- }
240
- if (typeof topLevelOnSuccess === "function") {
241
- const nextOptions = {
242
- ...optionsRecord,
243
- onSuccess: wrapOnSuccess(topLevelOnSuccess)
244
- };
245
- return method(data, nextOptions);
246
- }
247
- if (wrappedFallbackOnSuccess) {
248
- if (fetchOptions) {
249
- const nextData = {
250
- ...dataRecord,
251
- fetchOptions: {
252
- ...fetchOptions,
253
- onSuccess: wrappedFallbackOnSuccess
254
- }
255
- };
256
- return method(nextData, options);
257
- }
258
- const nextOptions = {
259
- ...optionsRecord,
260
- onSuccess: wrappedFallbackOnSuccess
261
- };
262
- return method(data, nextOptions);
263
- }
264
- return method(data, options);
265
- });
266
- }
173
+ const wrapDeps = {
174
+ fetchSession,
175
+ loggedIn,
176
+ waitForSession,
177
+ resolvePostAuthSuccessRedirect: () => resolvePostAuthSuccessRedirect(requestURL)
178
+ };
267
179
  const signIn = client?.signIn ? new Proxy(client.signIn, {
268
180
  get(target, prop) {
269
181
  const targetRecord = target;
@@ -274,9 +186,10 @@ export function useUserSession() {
274
186
  const socialData = isRecord(data) ? data : void 0;
275
187
  return socialData?.disableRedirect !== true;
276
188
  } : void 0;
277
- const transformData = prop === "social" ? withFallbackSocialCallbackURL : void 0;
189
+ const transformData = prop === "social" ? (data) => withFallbackSocialCallbackURL(data, requestURL) : void 0;
278
190
  return wrapAuthMethod(
279
191
  (...args) => targetRecord[prop](...args),
192
+ wrapDeps,
280
193
  { shouldSkipSessionSync, transformData }
281
194
  );
282
195
  }
@@ -291,73 +204,40 @@ export function useUserSession() {
291
204
  const method = targetRecord[prop];
292
205
  if (typeof method !== "function")
293
206
  return method;
294
- return wrapAuthMethod((...args) => targetRecord[prop](...args));
207
+ return wrapAuthMethod((...args) => targetRecord[prop](...args), wrapDeps);
295
208
  }
296
209
  }) : new Proxy({}, {
297
210
  get: (_, prop) => {
298
211
  throw new Error(`signUp.${String(prop)}() can only be called on client-side`);
299
212
  }
300
213
  });
301
- async function fetchSession(options = {}) {
302
- if (runtimeFlags.server) {
303
- try {
304
- const headers = options.headers || useRequestHeaders(["cookie"]);
305
- const requestFetch = useRequestFetch();
306
- const data = await requestFetch("/api/auth/get-session", { headers });
307
- if (data?.session && data?.user) {
308
- const { token: _, ...safeSession } = data.session;
309
- session.value = safeSession;
310
- user.value = data.user;
311
- } else {
312
- clearSession();
313
- }
314
- } catch {
315
- clearSession();
316
- } finally {
317
- if (!authReady.value)
318
- authReady.value = true;
319
- }
320
- return;
321
- }
322
- if (client) {
323
- try {
324
- const headers = options.headers || useRequestHeaders(["cookie"]);
325
- const fetchOptions = headers ? { headers } : void 0;
326
- const query = options.force ? { disableCookieCache: true } : void 0;
327
- const result = await client.getSession({ query }, fetchOptions);
328
- const data = result.data;
329
- if (data?.session && data?.user) {
330
- const { token: _, ...safeSession } = data.session;
331
- session.value = safeSession;
332
- user.value = data.user;
333
- } else {
334
- clearSession();
335
- }
336
- } catch (error) {
337
- clearSession();
338
- console.error("[nuxt-better-auth] Failed to fetch session:", error);
339
- } finally {
340
- if (!authReady.value)
341
- authReady.value = true;
342
- }
343
- }
344
- }
345
214
  if (runtimeFlags.client && client && shouldSkipInitialClientSessionFetch.value) {
346
215
  ensureSessionSignalListener(client, () => fetchSession({ force: true }));
347
216
  }
348
217
  async function signOut(options) {
349
218
  if (!client)
350
219
  throw new Error("signOut can only be called on client-side");
351
- await client.signOut();
352
- clearSession();
353
- if (options?.onSuccess) {
354
- await options.onSuccess();
220
+ if (_signOutPromise) {
221
+ await _signOutPromise;
355
222
  return;
356
223
  }
357
- const authConfig = runtimeConfig.public.auth;
358
- const logoutRedirect = authConfig?.redirects?.logout;
359
- if (logoutRedirect)
360
- await navigateTo(logoutRedirect);
224
+ _signOutPromise = (async () => {
225
+ await client.signOut();
226
+ clearSession();
227
+ if (options?.onSuccess) {
228
+ await options.onSuccess();
229
+ return;
230
+ }
231
+ const authConfig = runtimeConfig.public.auth;
232
+ const logoutRedirect = authConfig?.redirects?.logout;
233
+ if (logoutRedirect) {
234
+ await nextTick();
235
+ await navigateTo(logoutRedirect);
236
+ }
237
+ })().finally(() => {
238
+ _signOutPromise = null;
239
+ });
240
+ await _signOutPromise;
361
241
  }
362
242
  return {
363
243
  client,
@@ -1,7 +1,5 @@
1
+ import { isRecord } from "./utils.js";
1
2
  export const DEFAULT_AUTH_ACTION_ERROR_MESSAGE = "Request failed. Please try again.";
2
- function isRecord(value) {
3
- return Boolean(value && typeof value === "object");
4
- }
5
3
  function getMessage(value) {
6
4
  if (value instanceof Error)
7
5
  return value.message;
@@ -1,8 +1,6 @@
1
1
  import { ref } from "#imports";
2
2
  import { normalizeAuthActionError } from "./auth-action-error.js";
3
- function isRecord(value) {
4
- return Boolean(value && typeof value === "object");
5
- }
3
+ import { isRecord } from "./utils.js";
6
4
  function isErrorResult(value) {
7
5
  if (!isRecord(value))
8
6
  return false;
@@ -0,0 +1,4 @@
1
+ export declare function isSafeLocalRedirect(redirect: unknown): string | undefined;
2
+ export declare function resolvePostAuthRedirect(requestURL: URL): string | undefined;
3
+ export declare function resolvePostAuthSuccessRedirect(requestURL: URL): (() => Promise<void>) | undefined;
4
+ export declare function withFallbackSocialCallbackURL(data: unknown, requestURL: URL): unknown;
@@ -0,0 +1,37 @@
1
+ import { navigateTo, useRuntimeConfig } from "#imports";
2
+ import { isRecord } from "./utils.js";
3
+ export function isSafeLocalRedirect(redirect) {
4
+ if (typeof redirect !== "string")
5
+ return;
6
+ if (!redirect.startsWith("/") || redirect.startsWith("//"))
7
+ return;
8
+ return redirect;
9
+ }
10
+ export function resolvePostAuthRedirect(requestURL) {
11
+ const runtimeConfig = useRuntimeConfig();
12
+ const authConfig = runtimeConfig.public.auth;
13
+ const redirectQueryKey = authConfig?.redirectQueryKey ?? "redirect";
14
+ const queryRedirect = requestURL.searchParams?.get(redirectQueryKey);
15
+ const safeQueryRedirect = isSafeLocalRedirect(queryRedirect);
16
+ if (safeQueryRedirect)
17
+ return safeQueryRedirect;
18
+ return isSafeLocalRedirect(authConfig?.redirects?.authenticated);
19
+ }
20
+ export function resolvePostAuthSuccessRedirect(requestURL) {
21
+ const target = resolvePostAuthRedirect(requestURL);
22
+ if (!target)
23
+ return;
24
+ return async () => {
25
+ await navigateTo(target);
26
+ };
27
+ }
28
+ export function withFallbackSocialCallbackURL(data, requestURL) {
29
+ const callbackURL = resolvePostAuthRedirect(requestURL);
30
+ if (!callbackURL)
31
+ return data;
32
+ if (!isRecord(data))
33
+ return { callbackURL };
34
+ if (typeof data.callbackURL === "string")
35
+ return data;
36
+ return { ...data, callbackURL };
37
+ }
@@ -0,0 +1,12 @@
1
+ import type { AppAuthClient, AuthSession, AuthUser } from '#nuxt-better-auth';
2
+ import type { Ref } from 'vue';
3
+ export declare function stripToken(session: AuthSession & {
4
+ token?: string;
5
+ }): AuthSession;
6
+ export declare function fetchSessionServer(session: Ref<AuthSession | null>, user: Ref<AuthUser | null>, authReady: Ref<boolean>, options?: {
7
+ headers?: HeadersInit;
8
+ }): Promise<void>;
9
+ export declare function fetchSessionClient(client: AppAuthClient, session: Ref<AuthSession | null>, user: Ref<AuthUser | null>, authReady: Ref<boolean>, options?: {
10
+ headers?: HeadersInit;
11
+ force?: boolean;
12
+ }): Promise<void>;
@@ -0,0 +1,56 @@
1
+ import { useRequestFetch, useRequestHeaders } from "#imports";
2
+ import { normalizeAuthActionError } from "./auth-action-error.js";
3
+ export function stripToken(session) {
4
+ const { token: _, ...safe } = session;
5
+ return safe;
6
+ }
7
+ function isExpectedSignedOutSessionError(error) {
8
+ const normalizedError = normalizeAuthActionError(error);
9
+ if (normalizedError.status === 401)
10
+ return true;
11
+ return normalizedError.code === "UNAUTHORIZED";
12
+ }
13
+ export async function fetchSessionServer(session, user, authReady, options = {}) {
14
+ try {
15
+ const headers = options.headers || useRequestHeaders(["cookie"]);
16
+ const requestFetch = useRequestFetch();
17
+ const data = await requestFetch("/api/auth/get-session", { headers });
18
+ if (data?.session && data?.user) {
19
+ session.value = stripToken(data.session);
20
+ user.value = data.user;
21
+ } else {
22
+ session.value = null;
23
+ user.value = null;
24
+ }
25
+ } catch {
26
+ session.value = null;
27
+ user.value = null;
28
+ } finally {
29
+ if (!authReady.value)
30
+ authReady.value = true;
31
+ }
32
+ }
33
+ export async function fetchSessionClient(client, session, user, authReady, options = {}) {
34
+ try {
35
+ const headers = options.headers || useRequestHeaders(["cookie"]);
36
+ const fetchOptions = headers ? { headers } : void 0;
37
+ const query = options.force ? { disableCookieCache: true } : void 0;
38
+ const result = await client.getSession({ query }, fetchOptions);
39
+ const data = result.data;
40
+ if (data?.session && data?.user) {
41
+ session.value = stripToken(data.session);
42
+ user.value = data.user;
43
+ } else {
44
+ session.value = null;
45
+ user.value = null;
46
+ }
47
+ } catch (error) {
48
+ session.value = null;
49
+ user.value = null;
50
+ if (!isExpectedSignedOutSessionError(error))
51
+ console.error("[nuxt-better-auth] Failed to fetch session:", error);
52
+ } finally {
53
+ if (!authReady.value)
54
+ authReady.value = true;
55
+ }
56
+ }
@@ -0,0 +1 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -0,0 +1,3 @@
1
+ export function isRecord(value) {
2
+ return Boolean(value && typeof value === "object");
3
+ }
@@ -0,0 +1,15 @@
1
+ import type { ComputedRef } from 'vue';
2
+ export declare function wrapOnSuccess(fetchSession: (options?: {
3
+ force?: boolean;
4
+ }) => Promise<void>, loggedIn: ComputedRef<boolean>, waitForSession: () => Promise<void>, cb: (ctx: unknown) => void | Promise<void>): (ctx: unknown) => Promise<void>;
5
+ export declare function wrapAuthMethod<T extends (...args: unknown[]) => Promise<unknown>>(method: T, deps: {
6
+ fetchSession: (options?: {
7
+ force?: boolean;
8
+ }) => Promise<void>;
9
+ loggedIn: ComputedRef<boolean>;
10
+ waitForSession: () => Promise<void>;
11
+ resolvePostAuthSuccessRedirect: () => (() => Promise<void>) | undefined;
12
+ }, wrapOptions?: {
13
+ shouldSkipSessionSync?: (data: unknown, options: unknown) => boolean;
14
+ transformData?: (data: unknown, options: unknown) => unknown;
15
+ }): T;
@@ -0,0 +1,66 @@
1
+ import { nextTick } from "#imports";
2
+ import { isRecord } from "./utils.js";
3
+ export function wrapOnSuccess(fetchSession, loggedIn, waitForSession, cb) {
4
+ return async (ctx) => {
5
+ await fetchSession({ force: true });
6
+ if (!loggedIn.value)
7
+ await waitForSession();
8
+ await nextTick();
9
+ await cb(ctx);
10
+ };
11
+ }
12
+ export function wrapAuthMethod(method, deps, wrapOptions = {}) {
13
+ return (async (...args) => {
14
+ const originalData = args[0];
15
+ const options = args[1];
16
+ const data = wrapOptions.transformData?.(originalData, options) ?? originalData;
17
+ const dataRecord = isRecord(data) ? data : void 0;
18
+ const optionsRecord = isRecord(options) ? options : void 0;
19
+ if (wrapOptions.shouldSkipSessionSync?.(data, options))
20
+ return method(data, options);
21
+ const fetchOptions = isRecord(dataRecord?.fetchOptions) ? dataRecord.fetchOptions : void 0;
22
+ const nestedOnSuccess = fetchOptions?.onSuccess;
23
+ const topLevelOnSuccess = optionsRecord?.onSuccess;
24
+ const fallbackOnSuccess = deps.resolvePostAuthSuccessRedirect();
25
+ const wrappedFallbackOnSuccess = fallbackOnSuccess && wrapOnSuccess(deps.fetchSession, deps.loggedIn, deps.waitForSession, async () => {
26
+ if (!deps.loggedIn.value)
27
+ return;
28
+ await fallbackOnSuccess();
29
+ });
30
+ if (typeof nestedOnSuccess === "function") {
31
+ const nextData = {
32
+ ...dataRecord,
33
+ fetchOptions: {
34
+ ...fetchOptions,
35
+ onSuccess: wrapOnSuccess(deps.fetchSession, deps.loggedIn, deps.waitForSession, nestedOnSuccess)
36
+ }
37
+ };
38
+ return method(nextData, options);
39
+ }
40
+ if (typeof topLevelOnSuccess === "function") {
41
+ const nextOptions = {
42
+ ...optionsRecord,
43
+ onSuccess: wrapOnSuccess(deps.fetchSession, deps.loggedIn, deps.waitForSession, topLevelOnSuccess)
44
+ };
45
+ return method(data, nextOptions);
46
+ }
47
+ if (wrappedFallbackOnSuccess) {
48
+ if (fetchOptions) {
49
+ const nextData = {
50
+ ...dataRecord,
51
+ fetchOptions: {
52
+ ...fetchOptions,
53
+ onSuccess: wrappedFallbackOnSuccess
54
+ }
55
+ };
56
+ return method(nextData, options);
57
+ }
58
+ const nextOptions = {
59
+ ...optionsRecord,
60
+ onSuccess: wrappedFallbackOnSuccess
61
+ };
62
+ return method(data, nextOptions);
63
+ }
64
+ return method(data, options);
65
+ });
66
+ }
@@ -1,6 +1,6 @@
1
1
  import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth';
2
2
  import type { BetterAuthClientOptions } from 'better-auth/client';
3
- import type { CasingOption } from '../schema-generator.js';
3
+ import type { Casing } from 'drizzle-orm/utils';
4
4
  import type { ServerAuthContext } from './types/augment.js';
5
5
  import { createAuthClient } from 'better-auth/vue';
6
6
  export type { ServerAuthContext };
@@ -20,9 +20,9 @@ export type EffectiveDatabaseProviderId = 'user' | ModuleDatabaseProviderId;
20
20
  export interface BetterAuthModuleOptions {
21
21
  /** Client-only mode - skip server setup for external auth backends */
22
22
  clientOnly?: boolean;
23
- /** Server config path relative to rootDir. Default: 'server/auth.config' */
23
+ /** Server config path. Relative paths resolve from the layer that declares them. Default: 'server/auth.config' */
24
24
  serverConfig?: string;
25
- /** Client config path relative to rootDir. Default: 'app/auth.config' */
25
+ /** Client config path. Relative paths resolve from the layer that declares them. Default: 'app/auth.config' */
26
26
  clientConfig?: string;
27
27
  redirects?: {
28
28
  /** Where to redirect unauthenticated users. Default: '/login' */
@@ -69,7 +69,7 @@ export interface BetterAuthModuleOptions {
69
69
  /** Plural table names: user → users. Default: false */
70
70
  usePlural?: boolean;
71
71
  /** Column/table name casing. Explicit value takes precedence over hub.db.casing. */
72
- casing?: CasingOption;
72
+ casing?: Casing;
73
73
  };
74
74
  }
75
75
  export interface AuthRuntimeConfig {
@@ -6,6 +6,8 @@ export function defineClientAuth(config) {
6
6
  return (baseURL) => {
7
7
  const ctx = { siteUrl: baseURL };
8
8
  const resolved = typeof config === "function" ? config(ctx) : config;
9
- return createAuthClient({ ...resolved, baseURL });
9
+ const { baseURL: configuredBaseURL, ...resolvedOptions } = resolved;
10
+ const clientOptions = { ...resolvedOptions, baseURL: configuredBaseURL ?? baseURL };
11
+ return createAuthClient(clientOptions);
10
12
  };
11
13
  }
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ const SQL_LIKE_ESCAPE_RE = /[%_\\]/g;
2
3
  export const paginationQuerySchema = z.object({
3
4
  page: z.coerce.number().int().min(1).default(1),
4
5
  limit: z.coerce.number().int().min(1).max(100).default(20),
@@ -7,5 +8,5 @@ export const paginationQuerySchema = z.object({
7
8
  export function sanitizeSearchPattern(search) {
8
9
  if (!search)
9
10
  return "";
10
- return `%${search.replace(/[%_\\]/g, "\\$&")}%`;
11
+ return `%${search.replace(SQL_LIKE_ESCAPE_RE, "\\$&")}%`;
11
12
  }
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.30",
4
+ "version": "0.0.2-alpha.31",
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",
@@ -11,14 +11,6 @@
11
11
  "type": "git",
12
12
  "url": "https://github.com/nuxt-modules/better-auth"
13
13
  },
14
- "agents": {
15
- "skills": [
16
- {
17
- "name": "nuxt-better-auth",
18
- "path": "./skills/nuxt-better-auth"
19
- }
20
- ]
21
- },
22
14
  "exports": {
23
15
  ".": {
24
16
  "types": "./dist/types.d.mts",
@@ -41,8 +33,7 @@
41
33
  }
42
34
  },
43
35
  "files": [
44
- "dist",
45
- "skills"
36
+ "dist"
46
37
  ],
47
38
  "scripts": {
48
39
  "prepack": "nuxt-module-build build",
@@ -77,13 +68,13 @@
77
68
  "jiti": "^2.6.1",
78
69
  "pathe": "^2.0.3",
79
70
  "radix3": "^1.1.2",
80
- "std-env": "^3.10.0"
71
+ "std-env": "^4.0.0"
81
72
  },
82
73
  "devDependencies": {
83
74
  "@antfu/eslint-config": "^7.6.1",
84
75
  "@libsql/client": "^0.17.0",
85
76
  "@libsql/linux-x64-gnu": "0.5.22",
86
- "@nuxt/devtools": "^3.2.2",
77
+ "@nuxt/devtools": "^3.2.3",
87
78
  "@nuxt/devtools-kit": "^3.2.2",
88
79
  "@nuxt/module-builder": "^1.0.2",
89
80
  "@nuxt/schema": "^4.3.1",
@@ -91,14 +82,14 @@
91
82
  "@nuxthub/core": "^0.10.6",
92
83
  "@types/better-sqlite3": "^7.6.13",
93
84
  "@types/node": "latest",
94
- "better-auth": "1.5.0",
85
+ "better-auth": "1.5.5",
95
86
  "better-sqlite3": "^12.6.2",
96
- "bumpp": "^10.4.1",
87
+ "bumpp": "^11.0.0",
97
88
  "changelogen": "^0.6.2",
98
89
  "consola": "^3.4.2",
99
90
  "drizzle-kit": "^0.31.9",
100
91
  "drizzle-orm": "^0.45.1",
101
- "eslint": "^10.0.2",
92
+ "eslint": "^10.0.3",
102
93
  "npm-agentskills": "https://pkg.pr.new/onmax/npm-agentskills@394499e",
103
94
  "nuxt": "^4.3.1",
104
95
  "tinyexec": "^1.0.2",