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"
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
})
```
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
```vue title="index.vue"
<script setup lang="ts">
import { client } from "~/lib/client"
const session = client.useSession()
import { authClient } from "~/lib/client"
const session = authClient.useSession()
</script>
<template>
@@ -66,4 +66,22 @@ const session = client.useSession()
</div>
</div>
</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";
export const client = createAuthClient({
export const authClient = createAuthClient({
baseURL: "http://localhost:3000",
});
@@ -11,4 +11,4 @@ export const {
useSession,
forgetPassword,
resetPassword,
} = client;
} = authClient;

View File

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

View File

@@ -17,7 +17,7 @@ const features = [
"Rate Limiting",
"Session Management",
];
const session = useSession();
const { data: session } = await useSession(useFetch);
</script>
<template>
@@ -39,6 +39,7 @@ const session = useSession();
features and capabilities. <br />
</p>
<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="text-xs flex items-center gap-2 justify-center text-muted-foreground">
@@ -58,12 +59,12 @@ const session = useSession();
</div>
</div>
<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">
Sign In
</Button>
</NuxtLink>
<NuxtLink to="/dashboard" v-if="session.data">
<NuxtLink to="/dashboard" v-if="session">
<Button variant="outline" class="rounded-none">
Dashboard
</Button>

View File

@@ -13,7 +13,7 @@
"lint": "biome check .",
"lint:fix": "biome check . --apply",
"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",
"typecheck": "turbo --filter \"./packages/*\" typecheck"
},

View File

@@ -53,9 +53,43 @@ export function createAuthClient<Option extends ClientOptions>(
}
const { $session, _sessionSignal, $Infer } = getSessionAtom<Option>($fetch);
function useSession() {
type Session = ReturnType<typeof $session.get>["data"];
function useStoreSession() {
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 = {
...pluginsActions,
...resolvedHooks,