@onmax/nuxt-better-auth 0.0.2-alpha.1 → 0.0.2-alpha.10

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
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.0.2-alpha.1",
7
+ "version": "0.0.2-alpha.10",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -5,6 +5,7 @@ import { consola as consola$1 } from 'consola';
5
5
  import { defu } from 'defu';
6
6
  import { join } from 'pathe';
7
7
  import { toRouteMatcher, createRouter } from 'radix3';
8
+ import pluralize from 'pluralize';
8
9
  export { defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
9
10
 
10
11
  function setupDevTools(nuxt) {
@@ -22,46 +23,65 @@ function setupDevTools(nuxt) {
22
23
  });
23
24
  }
24
25
 
25
- function generateDrizzleSchema(tables, dialect) {
26
- const imports = getImports(dialect);
27
- const tableDefinitions = Object.entries(tables).map(([tableName, table]) => generateTable(tableName, table, dialect, tables)).join("\n\n");
26
+ function toSnakeCase(str) {
27
+ return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
28
+ }
29
+ function generateDrizzleSchema(tables, dialect, options) {
30
+ const typedTables = tables;
31
+ const imports = getImports(dialect, options);
32
+ const tableDefinitions = Object.entries(typedTables).map(([tableName, table]) => generateTable(tableName, table, dialect, typedTables, options)).join("\n\n");
28
33
  return `${imports}
29
34
 
30
35
  ${tableDefinitions}
31
36
  `;
32
37
  }
33
- function getImports(dialect) {
38
+ function getImports(dialect, options) {
34
39
  switch (dialect) {
35
40
  case "sqlite":
36
41
  return `import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'`;
37
42
  case "postgresql":
38
- return `import { boolean, pgTable, text, timestamp, integer } from 'drizzle-orm/pg-core'`;
43
+ return options?.useUuid ? `import { boolean, integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'` : `import { boolean, integer, pgTable, text, timestamp } from 'drizzle-orm/pg-core'`;
39
44
  case "mysql":
40
45
  return `import { boolean, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'`;
41
46
  }
42
47
  }
43
- function generateTable(tableName, table, dialect, allTables) {
48
+ function generateTable(tableName, table, dialect, allTables, options) {
44
49
  const tableFunc = dialect === "sqlite" ? "sqliteTable" : dialect === "postgresql" ? "pgTable" : "mysqlTable";
45
- const dbTableName = table.modelName || tableName;
46
- const fields = Object.entries(table.fields).map(([fieldName, field]) => generateField(fieldName, field, dialect, allTables)).join(",\n ");
47
- const idField = generateIdField(dialect);
50
+ const hasCustomModelName = table.modelName && table.modelName !== tableName;
51
+ let dbTableName = hasCustomModelName ? table.modelName : tableName;
52
+ if (options?.casing === "snake_case" && !hasCustomModelName)
53
+ dbTableName = toSnakeCase(dbTableName);
54
+ if (options?.usePlural && !hasCustomModelName)
55
+ dbTableName = pluralize(dbTableName);
56
+ const fields = Object.entries(table.fields).map(([fieldName, field]) => generateField(fieldName, field, dialect, allTables, options)).join(",\n ");
57
+ const idField = generateIdField(dialect, options);
48
58
  return `export const ${tableName} = ${tableFunc}('${dbTableName}', {
49
59
  ${idField},
50
60
  ${fields}
51
61
  })`;
52
62
  }
53
- function generateIdField(dialect) {
63
+ function generateIdField(dialect, options) {
54
64
  switch (dialect) {
55
65
  case "sqlite":
56
- case "postgresql":
66
+ if (options?.useUuid)
67
+ consola$1.warn("[@onmax/nuxt-better-auth] useUuid ignored for SQLite (no native uuid type). Using text.");
57
68
  return `id: text('id').primaryKey()`;
69
+ case "postgresql":
70
+ return options?.useUuid ? `id: uuid('id').defaultRandom().primaryKey()` : `id: text('id').primaryKey()`;
58
71
  case "mysql":
59
72
  return `id: varchar('id', { length: 36 }).primaryKey()`;
60
73
  }
61
74
  }
62
- function generateField(fieldName, field, dialect, allTables) {
63
- const dbFieldName = fieldName;
64
- let fieldDef = getFieldType(field.type, dialect, dbFieldName);
75
+ function generateField(fieldName, field, dialect, allTables, options) {
76
+ const dbFieldName = options?.casing === "snake_case" ? toSnakeCase(fieldName) : fieldName;
77
+ const isFkToId = options?.useUuid && field.references?.field === "id";
78
+ let fieldDef;
79
+ if (isFkToId && dialect === "postgresql")
80
+ fieldDef = `uuid('${dbFieldName}')`;
81
+ else if (isFkToId && dialect === "mysql")
82
+ fieldDef = `varchar('${dbFieldName}', { length: 36 })`;
83
+ else
84
+ fieldDef = getFieldType(field.type, dialect, dbFieldName);
65
85
  if (field.required && field.defaultValue === void 0)
66
86
  fieldDef += ".notNull()";
67
87
  if (field.unique)
@@ -71,11 +91,15 @@ function generateField(fieldName, field, dialect, allTables) {
71
91
  fieldDef += `.default(${field.defaultValue})`;
72
92
  else if (typeof field.defaultValue === "string")
73
93
  fieldDef += `.default('${field.defaultValue}')`;
94
+ else if (typeof field.defaultValue === "function")
95
+ fieldDef += `.$defaultFn(${field.defaultValue})`;
74
96
  else
75
97
  fieldDef += `.default(${field.defaultValue})`;
76
98
  if (field.required)
77
99
  fieldDef += ".notNull()";
78
100
  }
101
+ if (typeof field.onUpdate === "function" && field.type === "date")
102
+ fieldDef += `.$onUpdate(${field.onUpdate})`;
79
103
  if (field.references) {
80
104
  const refTable = field.references.model;
81
105
  if (allTables[refTable])
@@ -136,22 +160,42 @@ function getMysqlType(type, fieldName) {
136
160
  return `text('${fieldName}')`;
137
161
  }
138
162
  }
139
- async function loadUserAuthConfig(configPath) {
163
+ async function loadUserAuthConfig(configPath, throwOnError = false) {
140
164
  const { createJiti } = await import('jiti');
141
165
  const jiti = createJiti(import.meta.url, { interopDefault: true });
142
166
  try {
143
167
  const mod = await jiti.import(configPath);
144
- const configFn = mod.default || mod;
168
+ const configFn = typeof mod === "object" && mod !== null && "default" in mod ? mod.default : mod;
145
169
  if (typeof configFn === "function") {
146
170
  return configFn({ runtimeConfig: {}, db: null });
147
171
  }
172
+ if (throwOnError) {
173
+ throw new Error("auth.config.ts must export default defineServerAuth(...)");
174
+ }
148
175
  return {};
149
176
  } catch (error) {
177
+ if (throwOnError) {
178
+ throw new Error(`Failed to load auth config: ${error instanceof Error ? error.message : error}`);
179
+ }
150
180
  consola$1.error("[@onmax/nuxt-better-auth] Failed to load auth config for schema generation. Schema may be incomplete:", error);
151
181
  return {};
152
182
  }
153
183
  }
154
184
 
185
+ function getHubDialect(hub) {
186
+ if (!hub?.db)
187
+ return void 0;
188
+ if (typeof hub.db === "string")
189
+ return hub.db;
190
+ if (typeof hub.db === "object" && hub.db !== null)
191
+ return hub.db.dialect;
192
+ return void 0;
193
+ }
194
+ function getHubCasing(hub) {
195
+ if (!hub?.db || typeof hub.db !== "object" || hub.db === null)
196
+ return void 0;
197
+ return hub.db.casing;
198
+ }
155
199
  const consola = consola$1.withTag("nuxt-better-auth");
156
200
  const module$1 = defineNuxtModule({
157
201
  meta: { name: "@onmax/nuxt-better-auth", configKey: "auth", compatibility: { nuxt: ">=3.0.0" } },
@@ -186,14 +230,21 @@ const module$1 = defineNuxtModule({
186
230
  redirects: { login: options.redirects?.login ?? "/login", guest: options.redirects?.guest ?? "/" },
187
231
  useDatabase: hasHubDb
188
232
  });
189
- nuxt.options.runtimeConfig.betterAuthSecret ||= process.env.BETTER_AUTH_SECRET || process.env.NUXT_BETTER_AUTH_SECRET || "";
233
+ const betterAuthSecret = process.env.BETTER_AUTH_SECRET || process.env.NUXT_BETTER_AUTH_SECRET || nuxt.options.runtimeConfig.betterAuthSecret || "";
234
+ if (!nuxt.options.dev && !betterAuthSecret) {
235
+ throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET is required in production. Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET environment variable.");
236
+ }
237
+ if (betterAuthSecret && betterAuthSecret.length < 32) {
238
+ throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET must be at least 32 characters for security");
239
+ }
240
+ nuxt.options.runtimeConfig.betterAuthSecret = betterAuthSecret;
190
241
  nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
191
242
  secondaryStorage: secondaryStorageEnabled
192
243
  });
193
244
  nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
194
245
  nuxt.options.alias["#auth/server"] = serverConfigPath;
195
246
  nuxt.options.alias["#auth/client"] = clientConfigPath;
196
- const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from 'hub:kv'
247
+ const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from '../hub/kv.mjs'
197
248
  export function createSecondaryStorage() {
198
249
  return {
199
250
  get: async (key) => kv.get(\`_auth:\${key}\`),
@@ -203,10 +254,10 @@ export function createSecondaryStorage() {
203
254
  }` : `export function createSecondaryStorage() { return undefined }`;
204
255
  const secondaryStorageTemplate = addTemplate({ filename: "better-auth/secondary-storage.mjs", getContents: () => secondaryStorageCode, write: true });
205
256
  nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
206
- const hubDbPath = nuxt.options.alias["hub:db"];
207
- const databaseCode = hasHubDb && hubDbPath ? `import { db, schema } from '${hubDbPath}'
257
+ const hubDialect = getHubDialect(hub) ?? "sqlite";
258
+ const databaseCode = hasHubDb ? `import { db, schema } from '../hub/db.mjs'
208
259
  import { drizzleAdapter } from 'better-auth/adapters/drizzle'
209
- const rawDialect = '${hub?.db?.dialect ?? "sqlite"}'
260
+ const rawDialect = '${hubDialect}'
210
261
  const dialect = rawDialect === 'postgresql' ? 'pg' : rawDialect
211
262
  export function createDatabase() { return drizzleAdapter(db, { provider: dialect, schema }) }
212
263
  export { db }` : `export function createDatabase() { return undefined }
@@ -298,9 +349,10 @@ declare module 'nitropack/types' {
298
349
  app.middleware.push({ name: "auth", path: resolver.resolve("./runtime/app/middleware/auth.global"), global: true });
299
350
  });
300
351
  if (hasHubDb) {
301
- await setupBetterAuthSchema(nuxt, serverConfigPath);
352
+ await setupBetterAuthSchema(nuxt, serverConfigPath, options);
302
353
  }
303
- if (nuxt.options.dev && process.env.NODE_ENV !== "production") {
354
+ const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
355
+ if (!isProduction) {
304
356
  setupDevTools(nuxt);
305
357
  addServerHandler({ route: "/api/_better-auth/config", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/config.get") });
306
358
  if (hasHubDb) {
@@ -333,22 +385,35 @@ declare module 'nitropack/types' {
333
385
  });
334
386
  }
335
387
  });
336
- async function setupBetterAuthSchema(nuxt, serverConfigPath) {
388
+ async function setupBetterAuthSchema(nuxt, serverConfigPath, options) {
337
389
  const hub = nuxt.options.hub;
338
- const dialect = typeof hub.db === "string" ? hub.db : hub.db?.dialect;
390
+ const dialect = getHubDialect(hub);
339
391
  if (!dialect || !["sqlite", "postgresql", "mysql"].includes(dialect)) {
340
392
  consola.warn(`Unsupported database dialect: ${dialect}`);
341
393
  return;
342
394
  }
395
+ const isProduction = !nuxt.options.dev;
343
396
  try {
344
397
  const configFile = `${serverConfigPath}.ts`;
345
- const userConfig = await loadUserAuthConfig(configFile);
398
+ const userConfig = await loadUserAuthConfig(configFile, isProduction);
346
399
  const extendedConfig = {};
347
400
  await nuxt.callHook("better-auth:config:extend", extendedConfig);
348
401
  const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
349
402
  const { getAuthTables } = await import('better-auth/db');
350
- const tables = getAuthTables({ plugins });
351
- const schemaCode = generateDrizzleSchema(tables, dialect);
403
+ const tables = getAuthTables({
404
+ plugins,
405
+ secondaryStorage: options.secondaryStorage ? {
406
+ get: async (_key) => null,
407
+ set: async (_key, _value, _ttl) => {
408
+ },
409
+ delete: async (_key) => {
410
+ }
411
+ } : void 0
412
+ });
413
+ const useUuid = userConfig.advanced?.database?.generateId === "uuid";
414
+ const hubCasing = getHubCasing(hub);
415
+ const schemaOptions = { ...options.schema, useUuid, casing: options.schema?.casing ?? hubCasing };
416
+ const schemaCode = generateDrizzleSchema(tables, dialect, schemaOptions);
352
417
  const schemaDir = join(nuxt.options.buildDir, "better-auth");
353
418
  const schemaPath = join(schemaDir, `schema.${dialect}.ts`);
354
419
  await mkdir(schemaDir, { recursive: true });
@@ -356,12 +421,16 @@ async function setupBetterAuthSchema(nuxt, serverConfigPath) {
356
421
  addTemplate({ filename: `better-auth/schema.${dialect}.ts`, getContents: () => schemaCode, write: true });
357
422
  consola.info(`Generated ${dialect} schema with ${Object.keys(tables).length} tables`);
358
423
  } catch (error) {
424
+ if (isProduction) {
425
+ throw error;
426
+ }
359
427
  consola.error("Failed to generate schema:", error);
360
428
  }
361
- nuxt.hook("hub:db:schema:extend", ({ paths, dialect: hookDialect }) => {
429
+ const nuxtWithHubHooks = nuxt;
430
+ nuxtWithHubHooks.hook("hub:db:schema:extend", ({ paths, dialect: hookDialect }) => {
362
431
  const schemaPath = join(nuxt.options.buildDir, "better-auth", `schema.${hookDialect}.ts`);
363
432
  if (existsSync(schemaPath)) {
364
- paths.push(schemaPath);
433
+ paths.unshift(schemaPath);
365
434
  }
366
435
  });
367
436
  }
@@ -1,20 +1,22 @@
1
- import type { AuthUser } from '#nuxt-better-auth';
1
+ import type { AppAuthClient, AuthSession, AuthUser } from '#nuxt-better-auth';
2
+ import type { ComputedRef, Ref } from 'vue';
2
3
  export interface SignOutOptions {
3
4
  onSuccess?: () => void | Promise<void>;
4
5
  }
5
- export declare function useUserSession(): {
6
- client: any;
7
- session: any;
8
- user: any;
9
- loggedIn: any;
10
- ready: any;
11
- signIn: any;
12
- signUp: any;
13
- signOut: (options?: SignOutOptions) => Promise<any>;
6
+ export interface UseUserSessionReturn {
7
+ client: AppAuthClient | null;
8
+ session: Ref<AuthSession | null>;
9
+ user: Ref<AuthUser | null>;
10
+ loggedIn: ComputedRef<boolean>;
11
+ ready: ComputedRef<boolean>;
12
+ signIn: NonNullable<AppAuthClient>['signIn'];
13
+ signUp: NonNullable<AppAuthClient>['signUp'];
14
+ signOut: (options?: SignOutOptions) => Promise<void>;
14
15
  waitForSession: () => Promise<void>;
15
16
  fetchSession: (options?: {
16
17
  headers?: HeadersInit;
17
18
  force?: boolean;
18
19
  }) => Promise<void>;
19
20
  updateUser: (updates: Partial<AuthUser>) => void;
20
- };
21
+ }
22
+ export declare function useUserSession(): UseUserSessionReturn;
@@ -1,6 +1,5 @@
1
1
  import { createAppAuthClient } from "#auth/client";
2
- import { computed, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
3
- import { consola } from "consola";
2
+ import { computed, nextTick, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
4
3
  let _client = null;
5
4
  function getClient(baseURL) {
6
5
  if (!_client)
@@ -30,7 +29,8 @@ export function useUserSession() {
30
29
  () => clientSession.value,
31
30
  (newSession) => {
32
31
  if (newSession?.data?.session && newSession?.data?.user) {
33
- session.value = newSession.data.session;
32
+ const { token: _, ...safeSession } = newSession.data.session;
33
+ session.value = safeSession;
34
34
  user.value = newSession.data.user;
35
35
  } else if (!newSession?.isPending) {
36
36
  clearSession();
@@ -62,6 +62,9 @@ export function useUserSession() {
62
62
  function wrapOnSuccess(cb) {
63
63
  return async (ctx) => {
64
64
  await fetchSession({ force: true });
65
+ if (!loggedIn.value)
66
+ await waitForSession();
67
+ await nextTick();
65
68
  await cb(ctx);
66
69
  };
67
70
  }
@@ -79,10 +82,11 @@ export function useUserSession() {
79
82
  }
80
83
  const signIn = client?.signIn ? new Proxy(client.signIn, {
81
84
  get(target, prop) {
82
- const method = target[prop];
85
+ const targetRecord = target;
86
+ const method = targetRecord[prop];
83
87
  if (typeof method !== "function")
84
88
  return method;
85
- return wrapAuthMethod((...args) => target[prop](...args));
89
+ return wrapAuthMethod((...args) => targetRecord[prop](...args));
86
90
  }
87
91
  }) : new Proxy({}, {
88
92
  get: (_, prop) => {
@@ -91,10 +95,11 @@ export function useUserSession() {
91
95
  });
92
96
  const signUp = client?.signUp ? new Proxy(client.signUp, {
93
97
  get(target, prop) {
94
- const method = target[prop];
98
+ const targetRecord = target;
99
+ const method = targetRecord[prop];
95
100
  if (typeof method !== "function")
96
101
  return method;
97
- return wrapAuthMethod((...args) => target[prop](...args));
102
+ return wrapAuthMethod((...args) => targetRecord[prop](...args));
98
103
  }
99
104
  }) : new Proxy({}, {
100
105
  get: (_, prop) => {
@@ -115,15 +120,15 @@ export function useUserSession() {
115
120
  const result = await client.getSession({ query }, fetchOptions);
116
121
  const data = result.data;
117
122
  if (data?.session && data?.user) {
118
- session.value = data.session;
123
+ const { token: _, ...safeSession } = data.session;
124
+ session.value = safeSession;
119
125
  user.value = data.user;
120
126
  } else {
121
127
  clearSession();
122
128
  }
123
129
  } catch (error) {
124
130
  clearSession();
125
- if (import.meta.dev)
126
- consola.error("Failed to fetch auth session:", error);
131
+ console.error("[nuxt-better-auth] Failed to fetch session:", error);
127
132
  } finally {
128
133
  if (!authReady.value)
129
134
  authReady.value = true;
@@ -133,11 +138,10 @@ export function useUserSession() {
133
138
  async function signOut(options) {
134
139
  if (!client)
135
140
  throw new Error("signOut can only be called on client-side");
136
- const response = await client.signOut();
141
+ await client.signOut();
137
142
  clearSession();
138
143
  if (options?.onSuccess)
139
144
  await options.onSuccess();
140
- return response;
141
145
  }
142
146
  return {
143
147
  client,
@@ -1,6 +1,12 @@
1
- import { createError, defineNuxtRouteMiddleware, getRouteRules, navigateTo, useRequestHeaders, useRuntimeConfig } from "#imports";
1
+ import { createError, defineNuxtRouteMiddleware, getRouteRules, navigateTo, useNuxtApp, useRequestHeaders, useRuntimeConfig, useUserSession } from "#imports";
2
2
  import { matchesUser } from "../../utils/match-user.js";
3
3
  export default defineNuxtRouteMiddleware(async (to) => {
4
+ const nuxtApp = useNuxtApp();
5
+ if (import.meta.client) {
6
+ const isPrerendered = nuxtApp.payload.prerenderedAt || nuxtApp.payload.isCached;
7
+ if (isPrerendered && nuxtApp.isHydrating)
8
+ return;
9
+ }
4
10
  if (to.meta.auth === void 0) {
5
11
  const rules = await getRouteRules({ path: to.path });
6
12
  if (rules.auth !== void 0)
@@ -10,8 +16,8 @@ export default defineNuxtRouteMiddleware(async (to) => {
10
16
  if (auth === void 0 || auth === false)
11
17
  return;
12
18
  const config = useRuntimeConfig().public.auth;
13
- const { fetchSession, user, loggedIn, ready } = useUserSession();
14
- if (!loggedIn.value && !ready.value) {
19
+ const { fetchSession, user, loggedIn } = useUserSession();
20
+ if (!loggedIn.value) {
15
21
  const headers = import.meta.server ? useRequestHeaders(["cookie"]) : void 0;
16
22
  await fetchSession({ headers });
17
23
  }
@@ -12,7 +12,8 @@ export default defineNuxtPlugin({
12
12
  const headers = useRequestHeaders(["cookie"]);
13
13
  const data = await $fetch("/api/auth/get-session", { headers });
14
14
  if (data?.session && data?.user) {
15
- session.value = data.session;
15
+ const { token: _, ...safeSession } = data.session;
16
+ session.value = safeSession;
16
17
  user.value = data.user;
17
18
  }
18
19
  } catch {
@@ -1,5 +1,6 @@
1
1
  import type { BetterAuthOptions } from 'better-auth';
2
2
  import type { ClientOptions } from 'better-auth/client';
3
+ import type { CasingOption } from '../schema-generator.js';
3
4
  import type { ServerAuthContext } from './types/augment.js';
4
5
  export type { ServerAuthContext };
5
6
  export interface ClientAuthContext {
@@ -22,6 +23,13 @@ export interface BetterAuthModuleOptions {
22
23
  };
23
24
  /** Enable KV secondary storage for sessions. Requires hub.kv: true */
24
25
  secondaryStorage?: boolean;
26
+ /** Schema generation options. Must match drizzleAdapter config. */
27
+ schema?: {
28
+ /** Plural table names: user → users. Default: false */
29
+ usePlural?: boolean;
30
+ /** Column/table name casing. Explicit value takes precedence over hub.db.casing. */
31
+ casing?: CasingOption;
32
+ };
25
33
  }
26
34
  export interface AuthRuntimeConfig {
27
35
  redirects: {
@@ -9,27 +9,27 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
9
9
  useDatabase: boolean;
10
10
  };
11
11
  server: {
12
- baseURL: string | undefined;
13
- basePath: string;
12
+ baseURL: any;
13
+ basePath: any;
14
14
  socialProviders: string[];
15
- plugins: any[];
16
- trustedOrigins: string[] | ((request: Request) => string[] | Promise<string[]>);
15
+ plugins: any;
16
+ trustedOrigins: any;
17
17
  session: {
18
18
  expiresIn: string;
19
19
  updateAge: string;
20
- cookieCache: boolean;
20
+ cookieCache: any;
21
21
  };
22
22
  emailAndPassword: boolean;
23
- rateLimit: boolean;
23
+ rateLimit: any;
24
24
  advanced: {
25
- useSecureCookies: string | boolean;
26
- disableCSRFCheck: boolean;
25
+ useSecureCookies: any;
26
+ disableCSRFCheck: any;
27
27
  };
28
28
  };
29
29
  };
30
30
  error?: undefined;
31
31
  } | {
32
32
  config: null;
33
- error: any;
33
+ error: string;
34
34
  }>>;
35
35
  export default _default;
@@ -41,6 +41,7 @@ export default defineEventHandler(async (event) => {
41
41
  }
42
42
  };
43
43
  } catch (error) {
44
- return { config: null, error: error.message || "Failed to fetch config" };
44
+ console.error("[DevTools] Config fetch failed:", error);
45
+ return { config: null, error: "Failed to fetch configuration" };
45
46
  }
46
47
  });
@@ -26,7 +26,16 @@ export default defineEventHandler(async (event) => {
26
26
  dbQuery.orderBy(desc(schema.session.createdAt)).limit(limit).offset(offset),
27
27
  countQuery
28
28
  ]);
29
- return { sessions, total: totalResult[0]?.count ?? 0, page, limit };
29
+ const safeSessions = sessions.map((s) => ({
30
+ id: s.id,
31
+ userId: s.userId,
32
+ createdAt: s.createdAt,
33
+ updatedAt: s.updatedAt,
34
+ expiresAt: s.expiresAt,
35
+ ipAddress: s.ipAddress,
36
+ userAgent: s.userAgent
37
+ }));
38
+ return { sessions: safeSessions, total: totalResult[0]?.count ?? 0, page, limit };
30
39
  } catch (error) {
31
40
  console.error("[DevTools] Fetch sessions failed:", error);
32
41
  return { sessions: [], total: 0, error: "Failed to fetch sessions" };
@@ -1,6 +1,7 @@
1
+ import type { Auth } from 'better-auth';
1
2
  import type { H3Event } from 'h3';
2
- import { betterAuth } from 'better-auth';
3
- type AuthInstance = ReturnType<typeof betterAuth>;
3
+ import createServerAuth from '#auth/server';
4
+ type AuthInstance = Auth<ReturnType<typeof createServerAuth>>;
4
5
  declare module 'h3' {
5
6
  interface H3EventContext {
6
7
  _betterAuth?: AuthInstance;
@@ -1,5 +1,6 @@
1
1
  import { createError } from "h3";
2
2
  import { matchesUser } from "../../utils/match-user.js";
3
+ import { serverAuth } from "./auth.js";
3
4
  export async function getUserSession(event) {
4
5
  const auth = await serverAuth(event);
5
6
  const session = await auth.api.getSession({ headers: event.headers });
@@ -37,6 +37,6 @@ export interface UserSessionComposable {
37
37
  waitForSession: () => Promise<void>;
38
38
  signOut: (options?: {
39
39
  onSuccess?: () => void | Promise<void>;
40
- }) => Promise<unknown>;
40
+ }) => Promise<void>;
41
41
  updateUser: (updates: Partial<AuthUser>) => void;
42
42
  }
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.1",
4
+ "version": "0.0.2-alpha.10",
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",
@@ -41,7 +41,7 @@
41
41
  "dev:prepare": "nuxt-module-build build --stub && nuxi prepare playground",
42
42
  "dev:docs": "nuxi dev docs",
43
43
  "build:docs": "nuxi build docs",
44
- "release": "bumpp && git push --follow-tags",
44
+ "release": "bumpp --push",
45
45
  "lint": "eslint .",
46
46
  "lint:fix": "eslint . --fix",
47
47
  "typecheck": "vue-tsc --noEmit",
@@ -63,6 +63,7 @@
63
63
  "defu": "^6.1.4",
64
64
  "jiti": "^2.4.2",
65
65
  "pathe": "^2.0.3",
66
+ "pluralize": "^8.0.0",
66
67
  "radix3": "^1.1.2"
67
68
  },
68
69
  "devDependencies": {
@@ -77,6 +78,7 @@
77
78
  "@nuxthub/core": "^0.10.3",
78
79
  "@types/better-sqlite3": "^7.6.13",
79
80
  "@types/node": "latest",
81
+ "@types/pluralize": "^0.0.33",
80
82
  "better-auth": "^1.4.7",
81
83
  "better-sqlite3": "^11.9.1",
82
84
  "bumpp": "^10.3.2",
@@ -95,9 +97,11 @@
95
97
  },
96
98
  "pnpm": {
97
99
  "onlyBuiltDependencies": [
100
+ "@parcel/watcher",
98
101
  "better-sqlite3",
99
102
  "esbuild",
100
- "@parcel/watcher"
103
+ "sharp",
104
+ "workerd"
101
105
  ],
102
106
  "patchedDependencies": {
103
107
  "@peculiar/x509@1.14.2": "patches/@peculiar__x509@1.14.2.patch",