feat: support useSession ssr for nuxt (#209)

This commit is contained in:
Bereket Engida
2024-10-17 22:14:56 +03:00
committed by GitHub
parent cda582f339
commit ab0d9cc309
6 changed files with 71 additions and 19 deletions

View File

@@ -35,20 +35,20 @@ Create a client instance. You can name the file anything you want. Here we are c
```ts title="client.ts" ```ts title="client.ts"
import { createAuthClient } from "better-auth/vue" // make sure to import from better-auth/vue import { createAuthClient } from "better-auth/vue" // make sure to import from better-auth/vue
export const client = createAuthClient({ export const authClient = createAuthClient({
//you can pass client configuration here //you can pass client configuration here
}) })
``` ```
Once you have created the client, you can use it to sign up, sign in, and perform other actions. Once you have created the client, you can use it to sign up, sign in, and perform other actions.
Some of the actinos are reactive. The client use [nano-store](https://github.com/nanostores/nanostores) to store the state and re-render the components when the state changes. Some of the actinos are reactive.
### Example usage ### Example usage
```vue title="index.vue" ```vue title="index.vue"
<script setup lang="ts"> <script setup lang="ts">
import { client } from "~/lib/client" import { authClient } from "~/lib/client"
const session = client.useSession() const session = authClient.useSession()
</script> </script>
<template> <template>
@@ -66,4 +66,22 @@ const session = client.useSession()
</div> </div>
</div> </div>
</template> </template>
``` ```
### SSR Usage
If you are using Nuxt with SSR, you can use the `useSession` function in the `setup` function of your page component and pass `useFetch` to make it work with SSR.
```vue title="index.vue"
<script setup lang="ts">
import { authClient } from "~/lib/auth-clietn";
const { data: session } = authClient.useSession(useFetch);
</script>
<template>
<p>
{{ session }}
</p>
</template>
```

View File

@@ -1,6 +1,6 @@
import { createAuthClient } from "better-auth/vue"; import { createAuthClient } from "better-auth/vue";
export const client = createAuthClient({ export const authClient = createAuthClient({
baseURL: "http://localhost:3000", baseURL: "http://localhost:3000",
}); });
@@ -11,4 +11,4 @@ export const {
useSession, useSession,
forgetPassword, forgetPassword,
resetPassword, resetPassword,
} = client; } = authClient;

View File

@@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { useSession, signOut } from "~/lib/auth-client"; import { useSession, signOut } from "~/lib/auth-client";
const session = useSession(); const { data: session, isPending, error } = await useSession(useFetch);
const router = useRouter();
</script> </script>
@@ -16,15 +15,15 @@ const router = useRouter();
<CardContent> <CardContent>
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<Avatar> <Avatar>
<AvatarImage :src="session.data?.user.image || ''" alt="User profile" /> <AvatarImage :src="session?.user.image || ''" alt="User profile" />
<AvatarFallback>{{ session.data?.user.name[0] }}</AvatarFallback> <AvatarFallback>{{ session?.user.name[0] }}</AvatarFallback>
</Avatar> </Avatar>
<div> <div>
<p class="text-sm"> <p class="text-sm">
{{ session.data?.user?.name }} {{ session?.user?.name }}
</p> </p>
<p class="text-xs"> <p class="text-xs">
{{ session.data?.user?.email }} {{ session?.user?.email }}
</p> </p>
</div> </div>
</div> </div>
@@ -32,7 +31,7 @@ const router = useRouter();
<CardFooter> <CardFooter>
<Button @click="async () => { <Button @click="async () => {
await signOut() await signOut()
router.push('/') // router.push('/')
}" variant="secondary"> }" variant="secondary">
Sing Out Sing Out
</Button> </Button>

View File

@@ -17,7 +17,7 @@ const features = [
"Rate Limiting", "Rate Limiting",
"Session Management", "Session Management",
]; ];
const session = useSession(); const { data: session } = await useSession(useFetch);
</script> </script>
<template> <template>
@@ -39,6 +39,7 @@ const session = useSession();
features and capabilities. <br /> features and capabilities. <br />
</p> </p>
<div class="flex flex-col gap-3 pt-2 flex-wrap"> <div class="flex flex-col gap-3 pt-2 flex-wrap">
<div class="border-y py-2 border-dotted bg-secondary/60 opacity-80"> <div class="border-y py-2 border-dotted bg-secondary/60 opacity-80">
<div class="text-xs flex items-center gap-2 justify-center text-muted-foreground"> <div class="text-xs flex items-center gap-2 justify-center text-muted-foreground">
@@ -58,12 +59,12 @@ const session = useSession();
</div> </div>
</div> </div>
<div class="flex items-center gap-2 mt-2 mx-auto"> <div class="flex items-center gap-2 mt-2 mx-auto">
<NuxtLink to="/sign-in" v-if="!session.data"> <NuxtLink to="/sign-in" v-if="!session">
<Button variant="outline" class="rounded-none"> <Button variant="outline" class="rounded-none">
Sign In Sign In
</Button> </Button>
</NuxtLink> </NuxtLink>
<NuxtLink to="/dashboard" v-if="session.data"> <NuxtLink to="/dashboard" v-if="session">
<Button variant="outline" class="rounded-none"> <Button variant="outline" class="rounded-none">
Dashboard Dashboard
</Button> </Button>

View File

@@ -13,7 +13,7 @@
"lint": "biome check .", "lint": "biome check .",
"lint:fix": "biome check . --apply", "lint:fix": "biome check . --apply",
"release": "turbo --filter \"./packages/*\" build && bumpp && pnpm -r publish --access public --no-git-checks", "release": "turbo --filter \"./packages/*\" build && bumpp && pnpm -r publish --access public --no-git-checks",
"release:beta": "turbo --filter \"./packages/*\" build && bumpp && pnpm -r publish --access public --tag beta --no-git-checks", "release:beta": "turbo --filter \"./packages/*\" build && bumpp && pnpm -r publish --access public --tag next --no-git-checks",
"test": "turbo --filter \"./packages/*\" test", "test": "turbo --filter \"./packages/*\" test",
"typecheck": "turbo --filter \"./packages/*\" typecheck" "typecheck": "turbo --filter \"./packages/*\" typecheck"
}, },

View File

@@ -53,9 +53,43 @@ export function createAuthClient<Option extends ClientOptions>(
} }
const { $session, _sessionSignal, $Infer } = getSessionAtom<Option>($fetch); const { $session, _sessionSignal, $Infer } = getSessionAtom<Option>($fetch);
function useSession() { type Session = ReturnType<typeof $session.get>["data"];
function useStoreSession() {
return useStore($session); return useStore($session);
} }
function useSession(): ReturnType<typeof useStoreSession>;
function useSession<F extends (...args: any) => any>(
useFetch: F,
): Promise<{
data: Ref<Session>;
isPending: false; //this is just to be consistent with the default hook
error: Ref<{
message?: string;
status: number;
statusText: string;
}>;
}>;
function useSession<UseFetch extends <T>(...args: any) => any>(
useFetch?: UseFetch,
) {
if (useFetch) {
const ref = useStore(_sessionSignal);
const session = useFetch("/api/auth/session", {
ref,
}).then((res: any) => {
return {
data: res.data,
isPending: false,
error: res.error,
};
});
return session;
}
return useStoreSession();
}
const routes = { const routes = {
...pluginsActions, ...pluginsActions,
...resolvedHooks, ...resolvedHooks,