@onmax/nuxt-better-auth 0.0.2-alpha.21 → 0.0.2-alpha.23

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.
@@ -17,6 +17,6 @@ export interface UseUserSessionReturn {
17
17
  headers?: HeadersInit;
18
18
  force?: boolean;
19
19
  }) => Promise<void>;
20
- updateUser: (updates: Partial<AuthUser>) => void;
20
+ updateUser: (updates: Partial<AuthUser>) => Promise<void>;
21
21
  }
22
22
  export declare function useUserSession(): UseUserSessionReturn;
@@ -1,29 +1,89 @@
1
1
  import createAppAuthClient from "#auth/client";
2
- import { computed, nextTick, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
2
+ import { computed, nextTick, useNuxtApp, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
3
+ let _sessionSignalListenerBound = false;
3
4
  let _client = null;
4
5
  function getClient(baseURL) {
5
6
  if (!_client)
6
7
  _client = createAppAuthClient(baseURL);
7
8
  return _client;
8
9
  }
10
+ function getRuntimeFlags() {
11
+ const globalFlags = globalThis.__NUXT_BETTER_AUTH_TEST_FLAGS__;
12
+ if (globalFlags)
13
+ return globalFlags;
14
+ return { client: Boolean(import.meta.client), server: Boolean(import.meta.server) };
15
+ }
16
+ function ensureSessionSignalListener(client, onSignal) {
17
+ if (_sessionSignalListenerBound)
18
+ return;
19
+ const store = client.$store;
20
+ if (!store?.listen)
21
+ return;
22
+ _sessionSignalListenerBound = true;
23
+ store.listen("$sessionSignal", async () => {
24
+ try {
25
+ await onSignal();
26
+ } catch {
27
+ }
28
+ });
29
+ }
9
30
  export function useUserSession() {
31
+ const runtimeFlags = getRuntimeFlags();
10
32
  const runtimeConfig = useRuntimeConfig();
11
33
  const requestURL = useRequestURL();
12
- const client = import.meta.client ? getClient(runtimeConfig.public.siteUrl || requestURL.origin) : null;
34
+ const client = runtimeFlags.client ? getClient(runtimeConfig.public.siteUrl || requestURL.origin) : null;
13
35
  const session = useState("auth:session", () => null);
14
36
  const user = useState("auth:user", () => null);
15
37
  const authReady = useState("auth:ready", () => false);
16
38
  const ready = computed(() => authReady.value);
17
39
  const loggedIn = computed(() => Boolean(session.value && user.value));
40
+ const nuxtApp = useNuxtApp();
41
+ const skipHydratedSsrGetSession = computed(() => {
42
+ const authConfig = runtimeConfig.public.auth;
43
+ return Boolean(authConfig?.session?.skipHydratedSsrGetSession);
44
+ });
45
+ const shouldSkipInitialClientSessionFetch = computed(() => {
46
+ if (!skipHydratedSsrGetSession.value)
47
+ return false;
48
+ if (!runtimeFlags.client)
49
+ return false;
50
+ if (!nuxtApp.payload.serverRendered)
51
+ return false;
52
+ if (nuxtApp.payload.prerenderedAt || nuxtApp.payload.isCached)
53
+ return false;
54
+ return Boolean(session.value && user.value);
55
+ });
56
+ if (shouldSkipInitialClientSessionFetch.value && !authReady.value)
57
+ authReady.value = true;
18
58
  function clearSession() {
19
59
  session.value = null;
20
60
  user.value = null;
21
61
  }
22
- function updateUser(updates) {
23
- if (user.value)
24
- user.value = { ...user.value, ...updates };
62
+ async function updateUser(updates) {
63
+ if (!user.value)
64
+ return;
65
+ const previousUser = user.value;
66
+ user.value = { ...user.value, ...updates };
67
+ if (!client)
68
+ return;
69
+ try {
70
+ const clientWithUpdateUser = client;
71
+ const result = await clientWithUpdateUser.updateUser(updates);
72
+ if (result?.error) {
73
+ if (typeof result.error === "string")
74
+ throw new Error(result.error);
75
+ if (result.error instanceof Error)
76
+ throw result.error;
77
+ if (typeof result.error === "object" && result.error && "message" in result.error && typeof result.error.message === "string")
78
+ throw new Error(result.error.message);
79
+ throw new Error("Failed to update user");
80
+ }
81
+ } catch (error) {
82
+ user.value = previousUser;
83
+ throw error;
84
+ }
25
85
  }
26
- if (import.meta.client && client) {
86
+ if (runtimeFlags.client && client && !shouldSkipInitialClientSessionFetch.value) {
27
87
  const clientSession = client.useSession();
28
88
  watch(
29
89
  () => clientSession.value,
@@ -107,7 +167,7 @@ export function useUserSession() {
107
167
  }
108
168
  });
109
169
  async function fetchSession(options = {}) {
110
- if (import.meta.server) {
170
+ if (runtimeFlags.server) {
111
171
  if (!authReady.value)
112
172
  authReady.value = true;
113
173
  return;
@@ -135,6 +195,9 @@ export function useUserSession() {
135
195
  }
136
196
  }
137
197
  }
198
+ if (runtimeFlags.client && client && shouldSkipInitialClientSessionFetch.value) {
199
+ ensureSessionSignalListener(client, () => fetchSession({ force: true }));
200
+ }
138
201
  async function signOut(options) {
139
202
  if (!client)
140
203
  throw new Error("signOut can only be called on client-side");
@@ -380,8 +380,8 @@ function getAccountActions(row) {
380
380
  <span class="config-label">Guest</span><span class="font-mono">{{ configData.config.module?.redirects?.guest }}</span>
381
381
  </div>
382
382
  <div class="config-row">
383
- <span class="config-label">DB</span><UBadge :color="configData.config.module?.useDatabase ? 'success' : 'neutral'" variant="subtle" size="sm">
384
- {{ configData.config.module?.useDatabase ? "Hub" : "Off" }}
383
+ <span class="config-label">DB</span><UBadge :color="configData.config.module?.databaseProvider === 'none' ? 'neutral' : 'success'" variant="subtle" size="sm">
384
+ {{ configData.config.module?.databaseProvider === "nuxthub" ? "Hub" : configData.config.module?.databaseProvider === "convex" ? "Convex" : "Off" }}
385
385
  </UBadge>
386
386
  </div>
387
387
  <div class="config-row">
@@ -1,4 +1,4 @@
1
- import type { BetterAuthOptions } from 'better-auth';
1
+ import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth';
2
2
  import type { BetterAuthClientOptions } from 'better-auth/client';
3
3
  import type { CasingOption } from '../schema-generator.js';
4
4
  import type { ServerAuthContext } from './types/augment.js';
@@ -7,12 +7,17 @@ export type { ServerAuthContext };
7
7
  export interface ClientAuthContext {
8
8
  siteUrl: string;
9
9
  }
10
- export type ServerAuthConfig = Omit<BetterAuthOptions, 'database' | 'secret' | 'baseURL'>;
10
+ export type ServerAuthConfig = Omit<BetterAuthOptions, 'secret' | 'baseURL'> & {
11
+ plugins?: readonly BetterAuthPlugin[];
12
+ };
11
13
  export type ClientAuthConfig = Omit<BetterAuthClientOptions, 'baseURL'> & {
12
14
  baseURL?: string;
13
15
  };
14
16
  export type ServerAuthConfigFn = (ctx: ServerAuthContext) => ServerAuthConfig;
15
17
  export type ClientAuthConfigFn = (ctx: ClientAuthContext) => ClientAuthConfig;
18
+ export type ModuleDatabaseProviderId = 'none' | 'nuxthub' | (string & {});
19
+ export type EffectiveDatabaseProviderId = 'user' | ModuleDatabaseProviderId;
20
+ export type DatabaseSource = 'module' | 'user';
16
21
  export interface BetterAuthModuleOptions {
17
22
  /** Client-only mode - skip server setup for external auth backends */
18
23
  clientOnly?: boolean;
@@ -24,6 +29,16 @@ export interface BetterAuthModuleOptions {
24
29
  login?: string;
25
30
  guest?: string;
26
31
  };
32
+ session?: {
33
+ /**
34
+ * When enabled, and session/user are already hydrated from SSR, skip the initial
35
+ * client `/api/auth/get-session` bootstrap request. This also skips Better Auth's
36
+ * session refresh manager on those pages.
37
+ *
38
+ * Default: false
39
+ */
40
+ skipHydratedSsrGetSession?: boolean;
41
+ };
27
42
  /** Enable KV secondary storage for sessions. Requires hub.kv: true */
28
43
  secondaryStorage?: boolean;
29
44
  /** Schema generation options. Must match drizzleAdapter config. */
@@ -40,10 +55,16 @@ export interface AuthRuntimeConfig {
40
55
  guest: string;
41
56
  };
42
57
  useDatabase: boolean;
58
+ databaseProvider: EffectiveDatabaseProviderId;
59
+ databaseSource: DatabaseSource;
43
60
  clientOnly: boolean;
61
+ session: {
62
+ skipHydratedSsrGetSession: boolean;
63
+ };
44
64
  }
45
65
  export interface AuthPrivateRuntimeConfig {
46
66
  secondaryStorage: boolean;
47
67
  }
48
- export declare function defineServerAuth<T extends ServerAuthConfig>(config: T | ((ctx: ServerAuthContext) => T)): (ctx: ServerAuthContext) => T;
68
+ export declare function defineServerAuth<const R extends ServerAuthConfig>(config: R): (ctx: ServerAuthContext) => R;
69
+ export declare function defineServerAuth<const R extends ServerAuthConfig>(config: (ctx: ServerAuthContext) => R): (ctx: ServerAuthContext) => R;
49
70
  export declare function defineClientAuth<T extends ClientAuthConfig>(config: T | ((ctx: ClientAuthContext) => T)): (baseURL: string) => ReturnType<typeof createAuthClient<T>>;
@@ -7,6 +7,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
7
7
  };
8
8
  secondaryStorage: boolean;
9
9
  useDatabase: boolean;
10
+ databaseProvider: "none" | "nuxthub" | "convex";
10
11
  };
11
12
  server: {
12
13
  baseURL: any;
@@ -14,6 +15,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
14
15
  socialProviders: string[];
15
16
  plugins: any;
16
17
  trustedOrigins: any;
18
+ configuredTrustedOrigins: any;
17
19
  session: {
18
20
  expiresIn: string;
19
21
  updateAge: string;
@@ -5,9 +5,12 @@ export default defineEventHandler(async (event) => {
5
5
  try {
6
6
  const auth = serverAuth(event);
7
7
  const options = auth.options;
8
+ const authContext = await auth.$context;
8
9
  const runtimeConfig = useRuntimeConfig();
9
10
  const publicAuth = runtimeConfig.public?.auth;
10
11
  const privateAuth = runtimeConfig.auth;
12
+ const configuredTrustedOrigins = Array.isArray(options.trustedOrigins) ? options.trustedOrigins : [];
13
+ const effectiveTrustedOrigins = authContext?.trustedOrigins || configuredTrustedOrigins;
11
14
  const sessionConfig = options.session || {};
12
15
  const expiresInDays = sessionConfig.expiresIn ? Math.round(sessionConfig.expiresIn / 86400) : 7;
13
16
  const updateAgeDays = sessionConfig.updateAge ? Math.round(sessionConfig.updateAge / 86400) : 1;
@@ -17,7 +20,8 @@ export default defineEventHandler(async (event) => {
17
20
  module: {
18
21
  redirects: publicAuth?.redirects || { login: "/login", guest: "/" },
19
22
  secondaryStorage: privateAuth?.secondaryStorage ?? false,
20
- useDatabase: publicAuth?.useDatabase ?? false
23
+ useDatabase: publicAuth?.useDatabase ?? false,
24
+ databaseProvider: publicAuth?.databaseProvider ?? "none"
21
25
  },
22
26
  // Server config (server/auth.config.ts)
23
27
  server: {
@@ -25,7 +29,8 @@ export default defineEventHandler(async (event) => {
25
29
  basePath: options.basePath || "/api/auth",
26
30
  socialProviders: Object.keys(options.socialProviders || {}),
27
31
  plugins: (options.plugins || []).map((p) => p.id || "unknown"),
28
- trustedOrigins: options.trustedOrigins || [],
32
+ trustedOrigins: effectiveTrustedOrigins,
33
+ configuredTrustedOrigins,
29
34
  session: {
30
35
  expiresIn: `${expiresInDays} days`,
31
36
  updateAge: `${updateAgeDays} days`,
@@ -2,6 +2,6 @@ import type { Auth } from 'better-auth';
2
2
  import type { H3Event } from 'h3';
3
3
  import createServerAuth from '#auth/server';
4
4
  type AuthInstance = Auth<ReturnType<typeof createServerAuth>>;
5
- /** Returns Better Auth instance. Pass event for accurate URL detection on first call. */
5
+ /** Returns Better Auth instance. Caches per resolved host (or single instance when siteUrl is explicit). */
6
6
  export declare function serverAuth(event?: H3Event): AuthInstance;
7
7
  export {};
@@ -5,15 +5,53 @@ 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
- let _auth = null;
8
+ const _authCache = /* @__PURE__ */ new Map();
9
+ let _baseURLInferenceLogged = false;
10
+ function normalizeLoopbackOrigin(origin) {
11
+ if (!import.meta.dev)
12
+ return origin;
13
+ try {
14
+ const url = new URL(origin);
15
+ if (url.hostname === "127.0.0.1" || url.hostname === "::1" || url.hostname === "[::1]") {
16
+ url.hostname = "localhost";
17
+ return url.origin;
18
+ }
19
+ } catch {
20
+ }
21
+ return origin;
22
+ }
23
+ function logInferredBaseURL(baseURL, source) {
24
+ if (!import.meta.dev || _baseURLInferenceLogged)
25
+ return;
26
+ _baseURLInferenceLogged = true;
27
+ console.warn(`[nuxt-better-auth] Using inferred baseURL "${baseURL}" from ${source}. Set runtimeConfig.public.siteUrl for deterministic OAuth callbacks.`);
28
+ }
9
29
  function validateURL(url) {
10
30
  try {
11
- return new URL(url).origin;
31
+ return normalizeLoopbackOrigin(new URL(url).origin);
12
32
  } catch {
13
33
  throw new Error(`Invalid siteUrl: "${url}". Must be a valid URL.`);
14
34
  }
15
35
  }
16
- function getNitroOrigin(e) {
36
+ function resolveConfiguredSiteUrl(config) {
37
+ if (typeof config.public.siteUrl !== "string" || !config.public.siteUrl)
38
+ return void 0;
39
+ return validateURL(config.public.siteUrl);
40
+ }
41
+ function resolveEventOrigin(event) {
42
+ if (!event)
43
+ return void 0;
44
+ const host = getRequestHost(event, { xForwardedHost: true });
45
+ const protocol = getRequestProtocol(event, { xForwardedProto: true });
46
+ if (!host || !protocol)
47
+ return void 0;
48
+ try {
49
+ return validateURL(`${protocol}://${host}`);
50
+ } catch {
51
+ return void 0;
52
+ }
53
+ }
54
+ function getNitroOrigin() {
17
55
  const cert = process.env.NITRO_SSL_CERT;
18
56
  const key = process.env.NITRO_SSL_KEY;
19
57
  let host = process.env.NITRO_HOST || process.env.HOST;
@@ -30,15 +68,18 @@ function getNitroOrigin(e) {
30
68
  const origin = JSON.parse(process.env.NUXT_VITE_NODE_OPTIONS).baseURL.replace("/__nuxt_vite_node__", "");
31
69
  host = withoutProtocol(origin);
32
70
  protocol = origin.includes("https") ? "https" : "http";
33
- } else if (e) {
34
- host = getRequestHost(e, { xForwardedHost: true }) || host;
35
- protocol = getRequestProtocol(e, { xForwardedProto: true }) || protocol;
36
71
  }
37
72
  } catch {
38
73
  }
39
74
  if (!host)
40
75
  return void 0;
41
- if (host.includes(":") && !host.startsWith("[")) {
76
+ if (host.startsWith("[") && host.includes("]:")) {
77
+ const lastBracketColon = host.lastIndexOf("]:");
78
+ const extractedPort = host.slice(lastBracketColon + 2);
79
+ host = host.slice(0, lastBracketColon + 1);
80
+ if (extractedPort)
81
+ port = extractedPort;
82
+ } else if (host.includes(":") && !host.startsWith("[")) {
42
83
  const hostParts = host.split(":");
43
84
  port = hostParts.pop();
44
85
  host = hostParts.join(":");
@@ -46,36 +87,116 @@ function getNitroOrigin(e) {
46
87
  const portSuffix = port ? `:${port}` : "";
47
88
  return `${protocol}://${host}${portSuffix}`;
48
89
  }
49
- function getBaseURL(event) {
50
- const config = useRuntimeConfig();
51
- if (config.public.siteUrl && typeof config.public.siteUrl === "string")
52
- return validateURL(config.public.siteUrl);
53
- const nitroOrigin = getNitroOrigin(event);
90
+ function resolveEnvironmentOrigin() {
91
+ const nitroOrigin = getNitroOrigin();
54
92
  if (nitroOrigin)
55
- return validateURL(nitroOrigin);
93
+ return { origin: validateURL(nitroOrigin), source: "Nitro environment detection" };
56
94
  if (process.env.VERCEL_URL)
57
- return validateURL(`https://${process.env.VERCEL_URL}`);
95
+ return { origin: validateURL(`https://${process.env.VERCEL_URL}`), source: "VERCEL_URL" };
58
96
  if (process.env.CF_PAGES_URL)
59
- return validateURL(`https://${process.env.CF_PAGES_URL}`);
97
+ return { origin: validateURL(`https://${process.env.CF_PAGES_URL}`), source: "CF_PAGES_URL" };
60
98
  if (process.env.URL)
61
- return validateURL(process.env.URL.startsWith("http") ? process.env.URL : `https://${process.env.URL}`);
62
- if (import.meta.dev)
63
- return "http://localhost:3000";
99
+ return { origin: validateURL(process.env.URL.startsWith("http") ? process.env.URL : `https://${process.env.URL}`), source: "URL" };
100
+ return void 0;
101
+ }
102
+ function resolveDevFallback() {
103
+ if (!import.meta.dev)
104
+ return void 0;
105
+ return { origin: "http://localhost:3000", source: "development fallback" };
106
+ }
107
+ function getBaseURL(event) {
108
+ const config = useRuntimeConfig();
109
+ const configuredSiteUrl = resolveConfiguredSiteUrl(config);
110
+ if (configuredSiteUrl)
111
+ return configuredSiteUrl;
112
+ const eventOrigin = resolveEventOrigin(event);
113
+ if (eventOrigin) {
114
+ logInferredBaseURL(eventOrigin, "request origin");
115
+ return eventOrigin;
116
+ }
117
+ const environmentOrigin = resolveEnvironmentOrigin();
118
+ if (environmentOrigin) {
119
+ logInferredBaseURL(environmentOrigin.origin, environmentOrigin.source);
120
+ return environmentOrigin.origin;
121
+ }
122
+ const devFallback = resolveDevFallback();
123
+ if (devFallback) {
124
+ logInferredBaseURL(devFallback.origin, devFallback.source);
125
+ return devFallback.origin;
126
+ }
64
127
  throw new Error("siteUrl required. Set NUXT_PUBLIC_SITE_URL.");
65
128
  }
129
+ function dedupeOrigins(origins) {
130
+ return [...new Set(origins)];
131
+ }
132
+ function getDevTrustedOrigins() {
133
+ const fallbackOrigin = "http://localhost:3000";
134
+ const nitroOrigin = getNitroOrigin();
135
+ if (!nitroOrigin)
136
+ return [fallbackOrigin];
137
+ try {
138
+ const url = new URL(nitroOrigin);
139
+ const protocol = url.protocol === "https:" ? "https" : "http";
140
+ const port = url.port || "3000";
141
+ const localhostOrigin = `${protocol}://localhost:${port}`;
142
+ return dedupeOrigins([localhostOrigin, url.origin]);
143
+ } catch {
144
+ return [fallbackOrigin];
145
+ }
146
+ }
147
+ function getRequestOrigin(request) {
148
+ if (!request)
149
+ return void 0;
150
+ try {
151
+ return new URL(request.url).origin;
152
+ } catch {
153
+ return void 0;
154
+ }
155
+ }
156
+ function withDevTrustedOrigins(trustedOrigins, hasExplicitSiteUrl) {
157
+ if (!import.meta.dev || !hasExplicitSiteUrl)
158
+ return trustedOrigins;
159
+ const devOrigins = getDevTrustedOrigins();
160
+ const mergeOrigins = (origins, request) => {
161
+ const validOrigins = origins.filter((origin) => typeof origin === "string");
162
+ const requestOrigin = getRequestOrigin(request);
163
+ return dedupeOrigins(requestOrigin ? [...validOrigins, ...devOrigins, requestOrigin] : [...validOrigins, ...devOrigins]);
164
+ };
165
+ if (typeof trustedOrigins === "function") {
166
+ return async (request) => {
167
+ const resolvedOrigins = await trustedOrigins(request);
168
+ return mergeOrigins(resolvedOrigins, request);
169
+ };
170
+ }
171
+ if (Array.isArray(trustedOrigins)) {
172
+ const baseOrigins = mergeOrigins(trustedOrigins);
173
+ return async (request) => {
174
+ return mergeOrigins(baseOrigins, request);
175
+ };
176
+ }
177
+ return async (request) => {
178
+ return mergeOrigins([], request);
179
+ };
180
+ }
66
181
  export function serverAuth(event) {
67
- if (_auth)
68
- return _auth;
69
182
  const runtimeConfig = useRuntimeConfig();
70
183
  const siteUrl = getBaseURL(event);
184
+ const hasExplicitSiteUrl = runtimeConfig.public.siteUrl && typeof runtimeConfig.public.siteUrl === "string";
185
+ const cacheKey = hasExplicitSiteUrl ? "__explicit__" : siteUrl;
186
+ const cached = _authCache.get(cacheKey);
187
+ if (cached)
188
+ return cached;
71
189
  const database = createDatabase();
72
190
  const userConfig = createServerAuth({ runtimeConfig, db });
73
- _auth = betterAuth({
191
+ const trustedOrigins = withDevTrustedOrigins(userConfig.trustedOrigins, Boolean(hasExplicitSiteUrl));
192
+ const auth = betterAuth({
74
193
  ...userConfig,
75
194
  ...database && { database },
76
195
  secondaryStorage: createSecondaryStorage(),
77
196
  secret: runtimeConfig.betterAuthSecret,
78
- baseURL: siteUrl
197
+ baseURL: siteUrl,
198
+ trustedOrigins
79
199
  });
80
- return _auth;
200
+ _authCache.set(cacheKey, auth);
201
+ return auth;
81
202
  }
@@ -1,9 +1,17 @@
1
+ import type { AuthSession, AuthUser } from '#nuxt-better-auth';
1
2
  import type { H3Event } from 'h3';
2
- import type { AuthSession, AuthUser, RequireSessionOptions } from '../../types.js';
3
+ import type { UserMatch } from '../../types.js';
3
4
  interface FullSession {
4
5
  user: AuthUser;
5
6
  session: AuthSession;
6
7
  }
8
+ interface RequireUserSessionOptions {
9
+ user?: UserMatch<AuthUser>;
10
+ rule?: (ctx: {
11
+ user: AuthUser;
12
+ session: AuthSession;
13
+ }) => boolean | Promise<boolean>;
14
+ }
7
15
  export declare function getUserSession(event: H3Event): Promise<FullSession | null>;
8
- export declare function requireUserSession(event: H3Event, options?: RequireSessionOptions): Promise<FullSession>;
16
+ export declare function requireUserSession(event: H3Event, options?: RequireUserSessionOptions): Promise<FullSession>;
9
17
  export {};
@@ -38,5 +38,5 @@ export interface UserSessionComposable {
38
38
  signOut: (options?: {
39
39
  onSuccess?: () => void | Promise<void>;
40
40
  }) => Promise<void>;
41
- updateUser: (updates: Partial<AuthUser>) => void;
41
+ updateUser: (updates: Partial<AuthUser>) => Promise<void>;
42
42
  }
@@ -1,7 +1,7 @@
1
1
  import type { NitroRouteRules } from 'nitropack/types';
2
2
  import type { AuthSession, AuthUser } from './types/augment.js';
3
3
  export type { AuthSession, AuthUser, ServerAuthContext, UserSessionComposable } from './types/augment.js';
4
- export type { Auth, InferPluginTypes, InferSession, InferUser } from 'better-auth';
4
+ export type { Auth, InferPluginTypes, InferSessionFromClient as InferSession, InferUserFromClient as InferUser } from 'better-auth';
5
5
  export type AuthMode = 'guest' | 'user';
6
6
  export type UserMatch<T> = {
7
7
  [K in keyof T]?: T[K] | T[K][];
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@onmax/nuxt-better-auth",
3
3
  "type": "module",
4
- "version": "0.0.2-alpha.21",
4
+ "version": "0.0.2-alpha.23",
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",
8
8
  "license": "MIT",
9
+ "homepage": "https://better-auth.nuxt.dev",
9
10
  "repository": {
10
11
  "type": "git",
11
12
  "url": "https://github.com/nuxt-modules/better-auth"
@@ -26,10 +27,6 @@
26
27
  "./config": {
27
28
  "types": "./dist/runtime/config.d.ts",
28
29
  "import": "./dist/runtime/config.js"
29
- },
30
- "./adapters/convex": {
31
- "types": "./dist/runtime/adapters/convex.d.ts",
32
- "import": "./dist/runtime/adapters/convex.js"
33
30
  }
34
31
  },
35
32
  "main": "./dist/module.mjs",
@@ -40,9 +37,6 @@
40
37
  ],
41
38
  "config": [
42
39
  "./dist/runtime/config.d.ts"
43
- ],
44
- "adapters/convex": [
45
- "./dist/runtime/adapters/convex.d.ts"
46
40
  ]
47
41
  }
48
42
  },
@@ -67,15 +61,11 @@
67
61
  },
68
62
  "peerDependencies": {
69
63
  "@nuxthub/core": ">=0.10.5",
70
- "better-auth": ">=1.0.0",
71
- "convex": ">=1.25.0"
64
+ "better-auth": ">=1.0.0"
72
65
  },
73
66
  "peerDependenciesMeta": {
74
67
  "@nuxthub/core": {
75
68
  "optional": true
76
- },
77
- "convex": {
78
- "optional": true
79
69
  }
80
70
  },
81
71
  "dependencies": {
@@ -1,111 +0,0 @@
1
- import type { FunctionReference } from 'convex/server';
2
- interface ConvexCleanedWhere {
3
- field: string;
4
- value: string | number | boolean | string[] | number[] | null;
5
- operator?: 'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'in' | 'not_in' | 'ne' | 'contains' | 'starts_with' | 'ends_with';
6
- connector?: 'AND' | 'OR';
7
- }
8
- interface PaginationResult<T> {
9
- page: T[];
10
- isDone: boolean;
11
- continueCursor: string | null;
12
- splitCursor?: string;
13
- pageStatus?: 'SplitRecommended' | 'SplitRequired' | string;
14
- count?: number;
15
- }
16
- interface ConvexAuthApi {
17
- create: FunctionReference<'mutation', 'public', {
18
- input: {
19
- model: string;
20
- data: Record<string, unknown>;
21
- };
22
- select?: string[];
23
- }, unknown>;
24
- findOne: FunctionReference<'query', 'public', {
25
- model: string;
26
- where?: ConvexCleanedWhere[];
27
- select?: string[];
28
- }, unknown>;
29
- findMany: FunctionReference<'query', 'public', {
30
- model: string;
31
- where?: ConvexCleanedWhere[];
32
- limit?: number;
33
- sortBy?: {
34
- direction: 'asc' | 'desc';
35
- field: string;
36
- };
37
- paginationOpts: {
38
- numItems: number;
39
- cursor: string | null;
40
- };
41
- }, PaginationResult<unknown>>;
42
- updateOne: FunctionReference<'mutation', 'public', {
43
- input: {
44
- model: string;
45
- where?: ConvexCleanedWhere[];
46
- update: Record<string, unknown>;
47
- };
48
- }, unknown>;
49
- updateMany: FunctionReference<'mutation', 'public', {
50
- input: {
51
- model: string;
52
- where?: ConvexCleanedWhere[];
53
- update: Record<string, unknown>;
54
- };
55
- paginationOpts: {
56
- numItems: number;
57
- cursor: string | null;
58
- };
59
- }, PaginationResult<unknown> & {
60
- count: number;
61
- }>;
62
- deleteOne: FunctionReference<'mutation', 'public', {
63
- input: {
64
- model: string;
65
- where?: ConvexCleanedWhere[];
66
- };
67
- }, unknown>;
68
- deleteMany: FunctionReference<'mutation', 'public', {
69
- input: {
70
- model: string;
71
- where?: ConvexCleanedWhere[];
72
- };
73
- paginationOpts: {
74
- numItems: number;
75
- cursor: string | null;
76
- };
77
- }, PaginationResult<unknown> & {
78
- count: number;
79
- }>;
80
- }
81
- export interface ConvexHttpAdapterOptions {
82
- /** Convex deployment URL (e.g., https://your-app.convex.cloud) */
83
- url: string;
84
- /** Convex API functions for auth operations - import from your convex/_generated/api */
85
- api: ConvexAuthApi;
86
- /** Enable debug logging for adapter operations */
87
- debugLogs?: boolean;
88
- }
89
- /**
90
- * Creates a Better Auth adapter that communicates with Convex via HTTP.
91
- * Uses ConvexHttpClient for server-side auth operations.
92
- *
93
- * @example
94
- * ```ts
95
- * import { api } from '~/convex/_generated/api'
96
- *
97
- * export default defineServerAuth(() => ({
98
- * database: createConvexHttpAdapter({
99
- * url: process.env.CONVEX_URL!,
100
- * api: api.auth,
101
- * }),
102
- * }))
103
- * ```
104
- *
105
- * @limitations
106
- * - `update()` only supports AND-connected where clauses (no OR support)
107
- * - `count()` fetches all documents client-side (Convex limitation)
108
- * - `offset` pagination not supported in `findMany()`
109
- */
110
- export declare function createConvexHttpAdapter(options: ConvexHttpAdapterOptions): import("better-auth/adapters").AdapterFactory;
111
- export {};