@onmax/nuxt-better-auth 0.0.2-alpha.8 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +57 -17
  2. package/dist/module.d.mts +28 -1
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +1272 -339
  5. package/dist/runtime/app/components/BetterAuthState.d.vue.ts +4 -4
  6. package/dist/runtime/app/components/BetterAuthState.vue +1 -0
  7. package/dist/runtime/app/components/BetterAuthState.vue.d.ts +4 -4
  8. package/dist/runtime/app/composables/useAction.d.ts +2 -0
  9. package/dist/runtime/app/composables/useAction.js +6 -0
  10. package/dist/runtime/app/composables/useAuthAsyncData.d.ts +6 -0
  11. package/dist/runtime/app/composables/useAuthAsyncData.js +16 -0
  12. package/dist/runtime/app/composables/useAuthClient.d.ts +9 -0
  13. package/dist/runtime/app/composables/useAuthClient.js +34 -0
  14. package/dist/runtime/app/composables/useAuthClientAction.d.ts +3 -0
  15. package/dist/runtime/app/composables/useAuthClientAction.js +15 -0
  16. package/dist/runtime/app/composables/useAuthRequestFetch.d.ts +11 -0
  17. package/dist/runtime/app/composables/useAuthRequestFetch.js +4 -0
  18. package/dist/runtime/app/composables/useSignIn.d.ts +16 -0
  19. package/dist/runtime/app/composables/useSignIn.js +8 -0
  20. package/dist/runtime/app/composables/useSignUp.d.ts +5 -0
  21. package/dist/runtime/app/composables/useSignUp.js +8 -0
  22. package/dist/runtime/app/composables/useUserSession.d.ts +6 -5
  23. package/dist/runtime/app/composables/useUserSession.js +189 -100
  24. package/dist/runtime/app/composables/useUserSessionState.d.ts +3 -0
  25. package/dist/runtime/app/composables/useUserSessionState.js +4 -0
  26. package/dist/runtime/app/internal/auth-action-error.d.ts +3 -0
  27. package/dist/runtime/app/internal/auth-action-error.js +33 -0
  28. package/dist/runtime/app/internal/auth-action-handles.d.ts +18 -0
  29. package/dist/runtime/app/internal/auth-action-handles.js +105 -0
  30. package/dist/runtime/app/internal/redirect-helpers.d.ts +4 -0
  31. package/dist/runtime/app/internal/redirect-helpers.js +37 -0
  32. package/dist/runtime/app/internal/session-fetch.d.ts +12 -0
  33. package/dist/runtime/app/internal/session-fetch.js +56 -0
  34. package/dist/runtime/app/internal/utils.d.ts +1 -0
  35. package/dist/runtime/app/internal/utils.js +3 -0
  36. package/dist/runtime/app/internal/vue-safe-auth-proxy.d.ts +3 -0
  37. package/dist/runtime/app/internal/vue-safe-auth-proxy.js +68 -0
  38. package/dist/runtime/app/internal/wrap-auth-method.d.ts +15 -0
  39. package/dist/runtime/app/internal/wrap-auth-method.js +66 -0
  40. package/dist/runtime/app/middleware/auth.global.js +77 -15
  41. package/dist/runtime/app/pages/__better-auth-devtools.vue +4 -10
  42. package/dist/runtime/composables.d.ts +11 -0
  43. package/dist/runtime/composables.js +9 -0
  44. package/dist/runtime/config.d.ts +69 -15
  45. package/dist/runtime/config.js +9 -2
  46. package/dist/runtime/server/api/_better-auth/_schema.d.ts +1 -5
  47. package/dist/runtime/server/api/_better-auth/_schema.js +2 -1
  48. package/dist/runtime/server/api/_better-auth/accounts.get.d.ts +2 -2
  49. package/dist/runtime/server/api/_better-auth/accounts.get.js +3 -2
  50. package/dist/runtime/server/api/_better-auth/config.get.d.ts +9 -3
  51. package/dist/runtime/server/api/_better-auth/config.get.js +18 -6
  52. package/dist/runtime/server/api/_better-auth/sessions.delete.js +3 -2
  53. package/dist/runtime/server/api/_better-auth/sessions.get.d.ts +5 -3
  54. package/dist/runtime/server/api/_better-auth/sessions.get.js +3 -2
  55. package/dist/runtime/server/api/_better-auth/users.get.d.ts +2 -2
  56. package/dist/runtime/server/api/_better-auth/users.get.js +3 -2
  57. package/dist/runtime/server/api/auth/[...all].js +1 -1
  58. package/dist/runtime/server/middleware/route-access.js +2 -1
  59. package/dist/runtime/server/tsconfig.json +9 -1
  60. package/dist/runtime/server/utils/auth.d.ts +16 -8
  61. package/dist/runtime/server/utils/auth.js +229 -23
  62. package/dist/runtime/server/utils/custom-secondary-storage.d.ts +6 -0
  63. package/dist/runtime/server/utils/custom-secondary-storage.js +8 -0
  64. package/dist/runtime/server/utils/session.d.ts +6 -8
  65. package/dist/runtime/server/utils/session.js +216 -4
  66. package/dist/runtime/server/virtual-modules.d.ts +27 -0
  67. package/dist/runtime/types/augment.d.ts +18 -4
  68. package/dist/runtime/types.d.ts +12 -13
  69. package/dist/types.d.mts +1 -1
  70. package/package.json +51 -47
@@ -1,8 +1,8 @@
1
1
  declare var __VLS_1: {
2
- loggedIn: any;
3
- user: any;
4
- session: any;
5
- signOut: any;
2
+ loggedIn: boolean;
3
+ user: import("../../types.js").AuthUser | null;
4
+ session: import("../../types.js").AuthSession | null;
5
+ signOut: (options?: import("../composables/useUserSession.js").SignOutOptions) => Promise<void>;
6
6
  }, __VLS_3: {};
7
7
  type __VLS_Slots = {} & {
8
8
  default?: (props: typeof __VLS_1) => any;
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { useUserSession } from "../composables/useUserSession";
2
3
  const { loggedIn, user, session, signOut, ready } = useUserSession();
3
4
  </script>
4
5
 
@@ -1,8 +1,8 @@
1
1
  declare var __VLS_1: {
2
- loggedIn: any;
3
- user: any;
4
- session: any;
5
- signOut: any;
2
+ loggedIn: boolean;
3
+ user: import("../../types.js").AuthUser | null;
4
+ session: import("../../types.js").AuthSession | null;
5
+ signOut: (options?: import("../composables/useUserSession.js").SignOutOptions) => Promise<void>;
6
6
  }, __VLS_3: {};
7
7
  type __VLS_Slots = {} & {
8
8
  default?: (props: typeof __VLS_1) => any;
@@ -0,0 +1,2 @@
1
+ import type { UserAuthActionHandle } from '../internal/auth-action-handles.js';
2
+ export declare function useAction<TArgs extends unknown[], TResult>(runner: (...args: TArgs) => Promise<TResult>): UserAuthActionHandle<TArgs, TResult>;
@@ -0,0 +1,6 @@
1
+ import { createActionHandle } from "../internal/auth-action-handles.js";
2
+ export function useAction(runner) {
3
+ if (typeof runner !== "function")
4
+ throw new TypeError("useAction(runner) requires an async function");
5
+ return createActionHandle(() => runner);
6
+ }
@@ -0,0 +1,6 @@
1
+ import type { AsyncDataOptions } from '#app';
2
+ import { useAuthRequestFetch } from './useAuthRequestFetch.js';
3
+ export interface UseAuthAsyncDataOptions<T> extends Omit<AsyncDataOptions<T | null>, 'default'> {
4
+ requireAuth?: boolean;
5
+ }
6
+ export declare function useAuthAsyncData<T>(key: string, fetcher: (requestFetch: ReturnType<typeof useAuthRequestFetch>) => Promise<T>, options?: UseAuthAsyncDataOptions<T>): any;
@@ -0,0 +1,16 @@
1
+ import { useAsyncData } from "#imports";
2
+ import { useAuthRequestFetch } from "./useAuthRequestFetch.js";
3
+ import { useUserSession } from "./useUserSession.js";
4
+ export function useAuthAsyncData(key, fetcher, options = {}) {
5
+ const requestFetch = useAuthRequestFetch();
6
+ const { loggedIn } = useUserSession();
7
+ const { requireAuth = true, ...asyncDataOptions } = options;
8
+ return useAsyncData(key, async () => {
9
+ if (requireAuth && !loggedIn.value)
10
+ return null;
11
+ return await fetcher(requestFetch);
12
+ }, {
13
+ default: () => null,
14
+ ...asyncDataOptions
15
+ });
16
+ }
@@ -0,0 +1,9 @@
1
+ import type { AppAuthClient } from '#nuxt-better-auth';
2
+ interface RuntimeFlags {
3
+ client: boolean;
4
+ server: boolean;
5
+ }
6
+ export declare function getAuthRuntimeFlags(): RuntimeFlags;
7
+ export declare function useRawAuthClient(): AppAuthClient | null;
8
+ export declare function useAuthClient(): AppAuthClient | null;
9
+ export {};
@@ -0,0 +1,34 @@
1
+ import createAppAuthClient from "#auth/client";
2
+ import { useRequestURL, useRuntimeConfig } from "#imports";
3
+ import { createVueSafeAuthProxy } from "../internal/vue-safe-auth-proxy.js";
4
+ let _client = null;
5
+ let _clientFacade = null;
6
+ export function getAuthRuntimeFlags() {
7
+ const globalFlags = globalThis.__NUXT_BETTER_AUTH_TEST_FLAGS__;
8
+ if (globalFlags)
9
+ return globalFlags;
10
+ return { client: Boolean(import.meta.client), server: Boolean(import.meta.server) };
11
+ }
12
+ function getClient(baseURL) {
13
+ if (!_client)
14
+ _client = createAppAuthClient(baseURL);
15
+ return _client;
16
+ }
17
+ function getClientFacade(client) {
18
+ if (!_clientFacade)
19
+ _clientFacade = createVueSafeAuthProxy(client);
20
+ return _clientFacade;
21
+ }
22
+ export function useRawAuthClient() {
23
+ const runtimeFlags = getAuthRuntimeFlags();
24
+ if (!runtimeFlags.client)
25
+ return null;
26
+ const runtimeConfig = useRuntimeConfig();
27
+ const requestURL = useRequestURL();
28
+ const siteUrl = typeof runtimeConfig.public.siteUrl === "string" ? runtimeConfig.public.siteUrl : requestURL.origin;
29
+ return getClient(siteUrl);
30
+ }
31
+ export function useAuthClient() {
32
+ const rawClient = useRawAuthClient();
33
+ return rawClient ? getClientFacade(rawClient) : null;
34
+ }
@@ -0,0 +1,3 @@
1
+ import type { AppAuthClient } from '#nuxt-better-auth';
2
+ import type { UserAuthActionHandle } from '../internal/auth-action-handles.js';
3
+ export declare function useAuthClientAction<TArgs extends unknown[], TResult>(select: (client: AppAuthClient) => (...args: TArgs) => Promise<TResult>): UserAuthActionHandle<TArgs, TResult>;
@@ -0,0 +1,15 @@
1
+ import { useAction } from "./useAction.js";
2
+ import { useAuthClient } from "./useAuthClient.js";
3
+ export function useAuthClientAction(select) {
4
+ if (typeof select !== "function")
5
+ throw new TypeError("useAuthClientAction(select) requires a selector function");
6
+ return useAction(async (...args) => {
7
+ const client = useAuthClient();
8
+ if (!client)
9
+ throw new Error("Auth client is unavailable. This action can only run on client-side.");
10
+ const method = select(client);
11
+ if (typeof method !== "function")
12
+ throw new TypeError("useAuthClientAction(select) must resolve to a function");
13
+ return method(...args);
14
+ });
15
+ }
@@ -0,0 +1,11 @@
1
+ import type { NitroFetchOptions } from 'nitropack/types';
2
+ import type { AuthApiEndpointMethod, AuthApiEndpointPath, AuthApiEndpointResponse } from '#nuxt-better-auth';
3
+ import { useRequestFetch } from '#imports';
4
+ type AuthRequestFetchExtractedMethod<Options> = Options extends undefined ? 'get' : Lowercase<Extract<Exclude<Options extends {
5
+ method?: infer Method;
6
+ } ? Method : never, undefined>, string>> extends infer NormalizedMethod extends string ? NormalizedMethod : 'get';
7
+ type AuthRequestFetchMethodFromOptions<Path extends AuthApiEndpointPath, Options> = NitroFetchOptions<Path> extends Options ? 'get' : AuthRequestFetchExtractedMethod<Options>;
8
+ type AuthRequestFetchResolvedMethod<Path extends AuthApiEndpointPath, Options> = Extract<AuthRequestFetchMethodFromOptions<Path, Options>, AuthApiEndpointMethod<Path>> extends infer Method extends string ? Method : never;
9
+ type AuthRequestFetch = <Path extends AuthApiEndpointPath, Options extends NitroFetchOptions<Path> = NitroFetchOptions<Path>>(request: Path, opts?: Options) => Promise<AuthApiEndpointResponse<Path, Extract<AuthRequestFetchResolvedMethod<Path, Options>, AuthApiEndpointMethod<Path>>>>;
10
+ export declare function useAuthRequestFetch(): AuthRequestFetch & ReturnType<typeof useRequestFetch>;
11
+ export {};
@@ -0,0 +1,4 @@
1
+ import { useRequestFetch } from "#imports";
2
+ export function useAuthRequestFetch() {
3
+ return useRequestFetch();
4
+ }
@@ -0,0 +1,16 @@
1
+ import type { AppAuthClient, AuthSocialProviderRegistry } from '#nuxt-better-auth';
2
+ import type { ActionHandleFor } from '../internal/auth-action-handles.js';
3
+ type SignIn = NonNullable<AppAuthClient>['signIn'];
4
+ type AuthSocialProviderId = AuthSocialProviderRegistry extends {
5
+ ids: infer T;
6
+ } ? Extract<T, string> : never;
7
+ type TypedSocialMethod<Method> = Method extends (data: infer Data, ...rest: infer Rest) => Promise<infer Result> ? (data: Omit<Extract<Data, Record<string, unknown>>, 'provider'> & {
8
+ provider: AuthSocialProviderId;
9
+ }, ...rest: Rest) => Promise<Result> : Method;
10
+ type SignInWithTypedSocial = Omit<SignIn, 'social'> & (SignIn extends {
11
+ social: infer SocialMethod;
12
+ } ? {
13
+ social: TypedSocialMethod<SocialMethod>;
14
+ } : unknown);
15
+ export declare function useSignIn<MethodKey extends keyof SignInWithTypedSocial>(method: MethodKey): ActionHandleFor<SignInWithTypedSocial[MethodKey]>;
16
+ export {};
@@ -0,0 +1,8 @@
1
+ import { createActionHandles } from "../internal/auth-action-handles.js";
2
+ import { useAuthActionNamespaces } from "./useUserSession.js";
3
+ export function useSignIn(method) {
4
+ if (method === void 0 || method === null)
5
+ throw new TypeError("useSignIn(method) requires a sign-in method key");
6
+ const handles = createActionHandles(() => useAuthActionNamespaces().signIn, "signIn");
7
+ return handles[method];
8
+ }
@@ -0,0 +1,5 @@
1
+ import type { AppAuthClient } from '#nuxt-better-auth';
2
+ import type { ActionHandleFor } from '../internal/auth-action-handles.js';
3
+ type SignUp = NonNullable<AppAuthClient>['signUp'];
4
+ export declare function useSignUp<MethodKey extends keyof SignUp>(method: MethodKey): ActionHandleFor<SignUp[MethodKey]>;
5
+ export {};
@@ -0,0 +1,8 @@
1
+ import { createActionHandles } from "../internal/auth-action-handles.js";
2
+ import { useAuthActionNamespaces } from "./useUserSession.js";
3
+ export function useSignUp(method) {
4
+ if (method === void 0 || method === null)
5
+ throw new TypeError("useSignUp(method) requires a sign-up method key");
6
+ const handles = createActionHandles(() => useAuthActionNamespaces().signUp, "signUp");
7
+ return handles[method];
8
+ }
@@ -1,22 +1,23 @@
1
- import type { AppAuthClient, AuthSession, AuthUser } from '#nuxt-better-auth';
2
1
  import type { ComputedRef, Ref } from 'vue';
2
+ import type { AuthSession, AuthUser } from '#nuxt-better-auth';
3
3
  export interface SignOutOptions {
4
4
  onSuccess?: () => void | Promise<void>;
5
5
  }
6
6
  export interface UseUserSessionReturn {
7
- client: AppAuthClient | null;
8
7
  session: Ref<AuthSession | null>;
9
8
  user: Ref<AuthUser | null>;
10
9
  loggedIn: ComputedRef<boolean>;
11
10
  ready: ComputedRef<boolean>;
12
- signIn: NonNullable<AppAuthClient>['signIn'];
13
- signUp: NonNullable<AppAuthClient>['signUp'];
14
11
  signOut: (options?: SignOutOptions) => Promise<void>;
15
12
  waitForSession: () => Promise<void>;
16
13
  fetchSession: (options?: {
17
14
  headers?: HeadersInit;
18
15
  force?: boolean;
19
16
  }) => Promise<void>;
20
- updateUser: (updates: Partial<AuthUser>) => void;
17
+ updateUser: (updates: Partial<AuthUser>) => Promise<void>;
21
18
  }
22
19
  export declare function useUserSession(): UseUserSessionReturn;
20
+ export declare function useAuthActionNamespaces(): {
21
+ signIn: any;
22
+ signUp: any;
23
+ };
@@ -1,41 +1,154 @@
1
- import { createAppAuthClient } from "#auth/client";
2
- import { computed, nextTick, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
3
- let _client = null;
4
- function getClient(baseURL) {
5
- if (!_client)
6
- _client = createAppAuthClient(baseURL);
7
- return _client;
1
+ import { computed, navigateTo, nextTick, useNuxtApp, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
2
+ import { normalizeAuthActionError } from "../internal/auth-action-error.js";
3
+ import { resolvePostAuthSuccessRedirect, withFallbackSocialCallbackURL } from "../internal/redirect-helpers.js";
4
+ import { fetchSessionClient, fetchSessionServer, stripToken } from "../internal/session-fetch.js";
5
+ import { isRecord } from "../internal/utils.js";
6
+ import { createVueSafeAuthFacade, isAuthProxyProbeKey } from "../internal/vue-safe-auth-proxy.js";
7
+ import { wrapAuthMethod } from "../internal/wrap-auth-method.js";
8
+ import { getAuthRuntimeFlags, useRawAuthClient } from "./useAuthClient.js";
9
+ let _sessionSignalListenerBound = false;
10
+ let _signOutPromise = null;
11
+ function createServerOnlyActionNamespace(path) {
12
+ return new Proxy({}, {
13
+ get(_target, prop) {
14
+ if (isAuthProxyProbeKey(prop))
15
+ return void 0;
16
+ const key = prop;
17
+ return async () => {
18
+ throw new Error(`${path}.${key}() can only be called on client-side`);
19
+ };
20
+ }
21
+ });
22
+ }
23
+ const _signInServerOnly = createServerOnlyActionNamespace("signIn");
24
+ const _signUpServerOnly = createServerOnlyActionNamespace("signUp");
25
+ function ensureSessionSignalListener(client, onSignal) {
26
+ if (_sessionSignalListenerBound)
27
+ return;
28
+ const store = client.$store;
29
+ if (!isRecord(store))
30
+ return;
31
+ const listen = store.listen;
32
+ if (typeof listen !== "function")
33
+ return;
34
+ _sessionSignalListenerBound = true;
35
+ const listenFn = listen;
36
+ listenFn("$sessionSignal", async () => {
37
+ try {
38
+ await onSignal();
39
+ } catch {
40
+ }
41
+ });
8
42
  }
9
43
  export function useUserSession() {
44
+ const runtimeFlags = getAuthRuntimeFlags();
10
45
  const runtimeConfig = useRuntimeConfig();
11
- const requestURL = useRequestURL();
12
- const client = import.meta.client ? getClient(runtimeConfig.public.siteUrl || requestURL.origin) : null;
46
+ const nuxtApp = useNuxtApp();
47
+ const rawClient = useRawAuthClient();
13
48
  const session = useState("auth:session", () => null);
14
49
  const user = useState("auth:user", () => null);
15
50
  const authReady = useState("auth:ready", () => false);
51
+ const prerenderReadyResetQueued = useState("auth:prerender-ready-reset-queued", () => false);
52
+ const hydrationReconcileQueued = useState("auth:hydration-reconcile-queued", () => false);
16
53
  const ready = computed(() => authReady.value);
17
54
  const loggedIn = computed(() => Boolean(session.value && user.value));
55
+ const isPrerenderedPayload = computed(() => Boolean(nuxtApp.payload.prerenderedAt || nuxtApp.payload.isCached));
56
+ const isPrerenderHydrationEmptySnapshot = computed(() => {
57
+ if (!runtimeFlags.client)
58
+ return false;
59
+ if (!nuxtApp.isHydrating || !nuxtApp.payload.serverRendered || !isPrerenderedPayload.value)
60
+ return false;
61
+ return !session.value && !user.value;
62
+ });
63
+ const skipHydratedSsrGetSession = computed(() => {
64
+ const authConfig = runtimeConfig.public.auth;
65
+ return Boolean(authConfig?.session?.skipHydratedSsrGetSession);
66
+ });
67
+ const shouldSkipInitialClientSessionFetch = computed(() => {
68
+ if (!skipHydratedSsrGetSession.value)
69
+ return false;
70
+ if (!runtimeFlags.client)
71
+ return false;
72
+ if (!nuxtApp.payload.serverRendered)
73
+ return false;
74
+ if (isPrerenderedPayload.value)
75
+ return false;
76
+ return Boolean(session.value && user.value);
77
+ });
78
+ if (isPrerenderHydrationEmptySnapshot.value && authReady.value && !prerenderReadyResetQueued.value) {
79
+ prerenderReadyResetQueued.value = true;
80
+ nuxtApp.hook("app:suspense:resolve", () => {
81
+ try {
82
+ if (!session.value && !user.value && authReady.value)
83
+ authReady.value = false;
84
+ } finally {
85
+ prerenderReadyResetQueued.value = false;
86
+ }
87
+ });
88
+ }
89
+ if (shouldSkipInitialClientSessionFetch.value && !authReady.value)
90
+ authReady.value = true;
18
91
  function clearSession() {
19
92
  session.value = null;
20
93
  user.value = null;
21
94
  }
22
- function updateUser(updates) {
23
- if (user.value)
24
- user.value = { ...user.value, ...updates };
95
+ async function fetchSession(options = {}) {
96
+ if (runtimeFlags.server)
97
+ return fetchSessionServer(session, user, authReady, options);
98
+ if (rawClient)
99
+ return fetchSessionClient(rawClient, session, user, authReady, options);
25
100
  }
26
- if (import.meta.client && client) {
27
- const clientSession = client.useSession();
101
+ async function updateUser(updates) {
102
+ if (!user.value)
103
+ return;
104
+ const previousUser = user.value;
105
+ user.value = { ...user.value, ...updates };
106
+ if (!rawClient)
107
+ return;
108
+ try {
109
+ const clientWithUpdateUser = rawClient;
110
+ const result = await clientWithUpdateUser.updateUser(updates);
111
+ if (result?.error) {
112
+ if (result.error instanceof Error)
113
+ throw result.error;
114
+ const normalizedError = normalizeAuthActionError(result.error);
115
+ throw new Error(normalizedError.message);
116
+ }
117
+ } catch (error) {
118
+ user.value = previousUser;
119
+ if (!(error instanceof Error)) {
120
+ const normalizedError = normalizeAuthActionError(error);
121
+ throw new Error(normalizedError.message);
122
+ }
123
+ throw error;
124
+ }
125
+ }
126
+ if (runtimeFlags.client && rawClient && !shouldSkipInitialClientSessionFetch.value) {
127
+ const clientSession = rawClient.useSession();
28
128
  watch(
29
129
  () => clientSession.value,
30
130
  (newSession) => {
131
+ const shouldWaitForPrerenderResolution = isPrerenderHydrationEmptySnapshot.value && !newSession?.data?.session && !newSession?.data?.user;
132
+ if (shouldWaitForPrerenderResolution)
133
+ return;
31
134
  if (newSession?.data?.session && newSession?.data?.user) {
32
- const { token: _, ...safeSession } = newSession.data.session;
33
- session.value = safeSession;
135
+ session.value = stripToken(newSession.data.session);
34
136
  user.value = newSession.data.user;
35
- } else if (!newSession?.isPending) {
137
+ } else if (!newSession?.isPending && !newSession?.isRefetching) {
138
+ const isHydrationEmptySnapshot = nuxtApp.isHydrating && nuxtApp.payload.serverRendered && Boolean(session.value && user.value) && !newSession?.data?.session && !newSession?.data?.user;
139
+ if (isHydrationEmptySnapshot) {
140
+ if (!hydrationReconcileQueued.value) {
141
+ hydrationReconcileQueued.value = true;
142
+ nuxtApp.hook("app:mounted", async () => {
143
+ await fetchSession({ force: true });
144
+ hydrationReconcileQueued.value = false;
145
+ });
146
+ }
147
+ return;
148
+ }
36
149
  clearSession();
37
150
  }
38
- if (!authReady.value && !newSession?.isPending)
151
+ if (!authReady.value && !newSession?.isPending && !newSession?.isRefetching)
39
152
  authReady.value = true;
40
153
  },
41
154
  { immediate: true, deep: true }
@@ -59,101 +172,77 @@ export function useUserSession() {
59
172
  }, 5e3);
60
173
  });
61
174
  }
62
- function wrapOnSuccess(cb) {
63
- return async (ctx) => {
64
- await fetchSession({ force: true });
65
- if (!loggedIn.value)
66
- await waitForSession();
67
- await nextTick();
68
- await cb(ctx);
69
- };
70
- }
71
- function wrapAuthMethod(method) {
72
- return (async (...args) => {
73
- const [data, options] = args;
74
- if (data?.fetchOptions?.onSuccess) {
75
- return method({ ...data, fetchOptions: { ...data.fetchOptions, onSuccess: wrapOnSuccess(data.fetchOptions.onSuccess) } }, options);
76
- }
77
- if (options?.onSuccess) {
78
- return method(data, { ...options, onSuccess: wrapOnSuccess(options.onSuccess) });
79
- }
80
- return method(data, options);
81
- });
175
+ if (runtimeFlags.client && rawClient && shouldSkipInitialClientSessionFetch.value) {
176
+ ensureSessionSignalListener(rawClient, () => fetchSession({ force: true }));
82
177
  }
83
- const signIn = client?.signIn ? new Proxy(client.signIn, {
84
- get(target, prop) {
85
- const targetRecord = target;
86
- const method = targetRecord[prop];
87
- if (typeof method !== "function")
88
- return method;
89
- return wrapAuthMethod((...args) => targetRecord[prop](...args));
90
- }
91
- }) : new Proxy({}, {
92
- get: (_, prop) => {
93
- throw new Error(`signIn.${String(prop)}() can only be called on client-side`);
94
- }
95
- });
96
- const signUp = client?.signUp ? new Proxy(client.signUp, {
97
- get(target, prop) {
98
- const targetRecord = target;
99
- const method = targetRecord[prop];
100
- if (typeof method !== "function")
101
- return method;
102
- return wrapAuthMethod((...args) => targetRecord[prop](...args));
103
- }
104
- }) : new Proxy({}, {
105
- get: (_, prop) => {
106
- throw new Error(`signUp.${String(prop)}() can only be called on client-side`);
107
- }
108
- });
109
- async function fetchSession(options = {}) {
110
- if (import.meta.server) {
111
- if (!authReady.value)
112
- authReady.value = true;
178
+ async function signOut(options) {
179
+ if (!rawClient)
180
+ throw new Error("signOut can only be called on client-side");
181
+ if (_signOutPromise) {
182
+ await _signOutPromise;
113
183
  return;
114
184
  }
115
- if (client) {
116
- try {
117
- const headers = options.headers || useRequestHeaders(["cookie"]);
118
- const fetchOptions = headers ? { headers } : void 0;
119
- const query = options.force ? { disableCookieCache: true } : void 0;
120
- const result = await client.getSession({ query }, fetchOptions);
121
- const data = result.data;
122
- if (data?.session && data?.user) {
123
- const { token: _, ...safeSession } = data.session;
124
- session.value = safeSession;
125
- user.value = data.user;
126
- } else {
127
- clearSession();
128
- }
129
- } catch (error) {
130
- clearSession();
131
- console.error("[nuxt-better-auth] Failed to fetch session:", error);
132
- } finally {
133
- if (!authReady.value)
134
- authReady.value = true;
185
+ _signOutPromise = (async () => {
186
+ await rawClient.signOut();
187
+ clearSession();
188
+ if (options?.onSuccess) {
189
+ await options.onSuccess();
190
+ return;
135
191
  }
136
- }
137
- }
138
- async function signOut(options) {
139
- if (!client)
140
- throw new Error("signOut can only be called on client-side");
141
- await client.signOut();
142
- clearSession();
143
- if (options?.onSuccess)
144
- await options.onSuccess();
192
+ const authConfig = runtimeConfig.public.auth;
193
+ const logoutRedirect = authConfig?.redirects?.logout;
194
+ if (logoutRedirect) {
195
+ await nextTick();
196
+ await navigateTo(logoutRedirect);
197
+ }
198
+ })().finally(() => {
199
+ _signOutPromise = null;
200
+ });
201
+ await _signOutPromise;
145
202
  }
146
203
  return {
147
- client,
148
204
  session,
149
205
  user,
150
206
  loggedIn,
151
207
  ready,
152
- signIn,
153
- signUp,
154
208
  signOut,
155
209
  waitForSession,
156
210
  fetchSession,
157
211
  updateUser
158
212
  };
159
213
  }
214
+ export function useAuthActionNamespaces() {
215
+ const rawClient = useRawAuthClient();
216
+ const auth = useUserSession();
217
+ const requestURL = useRequestURL();
218
+ const wrapDeps = {
219
+ fetchSession: auth.fetchSession,
220
+ loggedIn: auth.loggedIn,
221
+ waitForSession: auth.waitForSession,
222
+ resolvePostAuthSuccessRedirect: () => resolvePostAuthSuccessRedirect(requestURL)
223
+ };
224
+ const signIn = rawClient?.signIn ? createVueSafeAuthFacade((prop) => {
225
+ const targetRecord = rawClient.signIn;
226
+ const method = targetRecord[prop];
227
+ if (typeof method !== "function")
228
+ return method;
229
+ const shouldSkipSessionSync = prop === "social" ? (data) => {
230
+ const socialData = isRecord(data) ? data : void 0;
231
+ return socialData?.disableRedirect !== true;
232
+ } : void 0;
233
+ const transformData = prop === "social" ? (data) => withFallbackSocialCallbackURL(data, requestURL) : void 0;
234
+ return wrapAuthMethod(
235
+ (...args) => targetRecord[prop](...args),
236
+ wrapDeps,
237
+ { shouldSkipSessionSync, transformData }
238
+ );
239
+ }) : _signInServerOnly;
240
+ const signUp = rawClient?.signUp ? createVueSafeAuthFacade((prop) => {
241
+ const targetRecord = rawClient.signUp;
242
+ const method = targetRecord[prop];
243
+ if (typeof method !== "function")
244
+ return method;
245
+ return wrapAuthMethod((...args) => targetRecord[prop](...args), wrapDeps);
246
+ }) : _signUpServerOnly;
247
+ return { signIn, signUp };
248
+ }
@@ -0,0 +1,3 @@
1
+ import type { UseUserSessionReturn } from './useUserSession.js';
2
+ export type UseUserSessionStateReturn = UseUserSessionReturn;
3
+ export declare function useUserSessionState(): UseUserSessionStateReturn;
@@ -0,0 +1,4 @@
1
+ import { useUserSession } from "./useUserSession.js";
2
+ export function useUserSessionState() {
3
+ return useUserSession();
4
+ }
@@ -0,0 +1,3 @@
1
+ import type { AuthActionError } from '../../types.js';
2
+ export declare const DEFAULT_AUTH_ACTION_ERROR_MESSAGE = "Request failed. Please try again.";
3
+ export declare function normalizeAuthActionError(error: unknown): AuthActionError;
@@ -0,0 +1,33 @@
1
+ import { isRecord } from "./utils.js";
2
+ export const DEFAULT_AUTH_ACTION_ERROR_MESSAGE = "Request failed. Please try again.";
3
+ function getMessage(value) {
4
+ if (value instanceof Error)
5
+ return value.message;
6
+ if (typeof value === "string")
7
+ return value;
8
+ if (isRecord(value) && typeof value.message === "string")
9
+ return value.message;
10
+ return DEFAULT_AUTH_ACTION_ERROR_MESSAGE;
11
+ }
12
+ function getCode(value) {
13
+ if (!isRecord(value))
14
+ return void 0;
15
+ return typeof value.code === "string" ? value.code : void 0;
16
+ }
17
+ function getStatus(value) {
18
+ if (!isRecord(value))
19
+ return void 0;
20
+ if (typeof value.status === "number")
21
+ return value.status;
22
+ if (typeof value.statusCode === "number")
23
+ return value.statusCode;
24
+ return void 0;
25
+ }
26
+ export function normalizeAuthActionError(error) {
27
+ return {
28
+ message: getMessage(error),
29
+ code: getCode(error),
30
+ status: getStatus(error),
31
+ raw: error
32
+ };
33
+ }
@@ -0,0 +1,18 @@
1
+ import type { Ref } from 'vue';
2
+ import type { AuthActionError } from '../../types.js';
3
+ export type UserAuthActionStatus = 'idle' | 'pending' | 'success' | 'error';
4
+ export interface UserAuthActionHandle<TArgs extends unknown[], TResult> {
5
+ execute: (...args: TArgs) => Promise<void>;
6
+ status: Ref<UserAuthActionStatus>;
7
+ data: Ref<TResult | null>;
8
+ error: Ref<AuthActionError | null>;
9
+ }
10
+ export interface CreateActionHandleOptions {
11
+ keepPendingOnRedirect?: boolean;
12
+ }
13
+ export type ActionHandleFor<T> = T extends (...args: infer A) => Promise<infer R> ? UserAuthActionHandle<A, R> : never;
14
+ export type ActionHandleMap<T> = {
15
+ [K in keyof T]: ActionHandleFor<T[K]>;
16
+ };
17
+ export declare function createActionHandle<TArgs extends unknown[], TResult>(getMethod: () => (...args: TArgs) => Promise<TResult>, options?: CreateActionHandleOptions): UserAuthActionHandle<TArgs, TResult>;
18
+ export declare function createActionHandles<T extends object>(getTarget: () => T, targetName: string): ActionHandleMap<T>;