mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-10 04:19:32 +00:00
examples
This commit is contained in:
@@ -468,4 +468,17 @@ export const contents: Content[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Guides",
|
||||||
|
Icon: () => (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.4em" height="1.4em" viewBox="0 0 24 24"><path fill="currentColor" d="M5.616 20q-.691 0-1.153-.462T4 18.384V5.616q0-.691.463-1.153T5.616 4h12.769q.69 0 1.153.463T20 5.616v12.769q0 .69-.462 1.153T18.384 20zM12.5 5v5.414q0 .242.202.36t.414-.012l.975-.597q.192-.13.409-.13t.41.13l.974.597q.212.13.414.012t.202-.36V5z"></path></svg>
|
||||||
|
),
|
||||||
|
list: [{
|
||||||
|
title: "Setting up Login with Github",
|
||||||
|
href: "/docs/guides/github-login",
|
||||||
|
icon: () => (
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24"><path fill="currentColor" d="M8 17.175V6.825q0-.425.3-.713t.7-.287q.125 0 .263.037t.262.113l8.15 5.175q.225.15.338.375t.112.475t-.112.475t-.338.375l-8.15 5.175q-.125.075-.262.113T9 18.175q-.4 0-.7-.288t-.3-.712"></path></svg>
|
||||||
|
)
|
||||||
|
}]
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ title: Basic Usage
|
|||||||
description: Usage
|
description: Usage
|
||||||
---
|
---
|
||||||
|
|
||||||
## Signin and Signup with Email
|
## Sign-in & Sign-up with Email & Password
|
||||||
|
|
||||||
To use signin and signup with email, you need to configure the email and password authenticator. You can do this by adding the following code to your `auth.ts` file:
|
To use email and password as authentication startgey, you need to enable `emailAndPassword` in the `auth` config.
|
||||||
|
|
||||||
```ts title="auth.ts" twoslash
|
```ts title="auth.ts" twoslash
|
||||||
import { betterAuth } from "better-auth"
|
import { betterAuth } from "better-auth"
|
||||||
@@ -200,7 +200,7 @@ the client providers a `useSession` hook or a `session` object that you can use
|
|||||||
```svelte title="user.svelte"
|
```svelte title="user.svelte"
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { client } from "$lib/client";
|
import { client } from "$lib/client";
|
||||||
const session = client.$session;
|
const session = client.useSsession;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -334,10 +334,11 @@ npx better-auth migrate
|
|||||||
Once we're done with the server, we need to add the plugin to the client. To do this, you need to import the plugin and pass it to the `authPlugins` option of the auth client. For example, to add two facor authentication, you can use the following code:
|
Once we're done with the server, we need to add the plugin to the client. To do this, you need to import the plugin and pass it to the `authPlugins` option of the auth client. For example, to add two facor authentication, you can use the following code:
|
||||||
|
|
||||||
```ts title="client.ts" twoslash /
|
```ts title="client.ts" twoslash /
|
||||||
import { createAuthClient, twoFactorClient } from "better-auth/client"
|
import { createAuthClient } from "better-auth/client";
|
||||||
|
import { twoFactorClient } from "better-auth/client/plugins";
|
||||||
|
|
||||||
const client = createAuthClient({
|
const client = createAuthClient({
|
||||||
authPlugins: [ // [!code highlight]
|
plugins: [ // [!code highlight]
|
||||||
twoFactorClient({ // [!code highlight]
|
twoFactorClient({ // [!code highlight]
|
||||||
twoFactorPage: "/two-factor" // [!code highlight]
|
twoFactorPage: "/two-factor" // [!code highlight]
|
||||||
}) // [!code highlight]
|
}) // [!code highlight]
|
||||||
@@ -349,10 +350,11 @@ now two factor related methods will be available on the client.
|
|||||||
|
|
||||||
```ts title="profile.ts" twoslash
|
```ts title="profile.ts" twoslash
|
||||||
// @filename: client.ts
|
// @filename: client.ts
|
||||||
import { createAuthClient, twoFactorClient } from "better-auth/client"
|
import { createAuthClient } from "better-auth/client";
|
||||||
|
import { twoFactorClient } from "better-auth/client/plugins";
|
||||||
|
|
||||||
export const client = createAuthClient({
|
export const client = createAuthClient({
|
||||||
authPlugins: [ // [!code highlight]
|
plugins: [ // [!code highlight]
|
||||||
twoFactorClient({ // [!code highlight]
|
twoFactorClient({ // [!code highlight]
|
||||||
twoFactorPage: "/two-factor" // [!code highlight]
|
twoFactorPage: "/two-factor" // [!code highlight]
|
||||||
}) // [!code highlight]
|
}) // [!code highlight]
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ description: Installation
|
|||||||
<GenerateSecret/>
|
<GenerateSecret/>
|
||||||
</Step>
|
</Step>
|
||||||
<Step>
|
<Step>
|
||||||
### Create Server
|
### Create A Better Auth Instance
|
||||||
better auth requries a file called `auth.ts` or `auth.config.ts` to be present in the root directory or one of the following directories:
|
better auth requries a file called `auth.ts` or `auth.config.ts` to be present in the root directory or one of the following directories:
|
||||||
- `lib/`
|
- `lib/`
|
||||||
- `utils/`
|
- `utils/`
|
||||||
@@ -160,6 +160,10 @@ description: Installation
|
|||||||
<Step>
|
<Step>
|
||||||
### Create Client
|
### Create Client
|
||||||
better auth client comes with a support for differnt frameworks including React, Vue, Svelte, and Solid. You can also use it with vanilla javascript.
|
better auth client comes with a support for differnt frameworks including React, Vue, Svelte, and Solid. You can also use it with vanilla javascript.
|
||||||
|
|
||||||
|
<Callout type="warn">
|
||||||
|
Make sure you import the client from the correct path.
|
||||||
|
</Callout>
|
||||||
<Tabs items={["vanilla","react", "vue", "svelte", "solid"]} defaultValue="react">
|
<Tabs items={["vanilla","react", "vue", "svelte", "solid"]} defaultValue="react">
|
||||||
<Tab value="vanilla">
|
<Tab value="vanilla">
|
||||||
```ts
|
```ts
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ Some of the actinos are reactive. The client use [nano-store](https://github.com
|
|||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example: Getting Session on a ServerComponent
|
### Example: Getting Session on a loader
|
||||||
|
|
||||||
```ts title="+page.ts"
|
```ts title="+page.ts"
|
||||||
import { auth } from "$lib/auth";
|
import { auth } from "$lib/auth";
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
"@tsparticles/engine": "^3.5.0",
|
"@tsparticles/engine": "^3.5.0",
|
||||||
"@tsparticles/react": "^3.0.0",
|
"@tsparticles/react": "^3.0.0",
|
||||||
"@tsparticles/slim": "^3.5.0",
|
"@tsparticles/slim": "^3.5.0",
|
||||||
"better-auth": "^0.0.4",
|
"better-auth": "workspace:0.0.8-beta.5",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "1.0.0",
|
"cmdk": "1.0.0",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { PasswordInput } from "@/components/ui/password-input";
|
import { PasswordInput } from "@/components/ui/password-input";
|
||||||
import { authClient } from "@/lib/auth-client";
|
import { authClient } from "@/lib/auth-client";
|
||||||
|
import { GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||||
import { Key } from "lucide-react";
|
import { Key } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
@@ -95,7 +96,7 @@ export default function Page() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-full"
|
className="w-full gap-2"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await authClient.signIn.social({
|
await authClient.signIn.social({
|
||||||
provider: "github",
|
provider: "github",
|
||||||
@@ -103,7 +104,43 @@ export default function Page() {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Login with Github
|
<GitHubLogoIcon />
|
||||||
|
Signup with Github
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="w-full gap-2"
|
||||||
|
onClick={async () => {
|
||||||
|
await authClient.signIn.social({
|
||||||
|
provider: "google",
|
||||||
|
callbackURL: "http://localhost:3000",
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="0.98em"
|
||||||
|
height="1em"
|
||||||
|
viewBox="0 0 256 262"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#4285F4"
|
||||||
|
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#34A853"
|
||||||
|
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#FBBC05"
|
||||||
|
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#EB4335"
|
||||||
|
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Login with Google
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { authClient } from "@/lib/auth-client";
|
import { authClient } from "@/lib/auth-client";
|
||||||
import { AlertCircle, CheckCircle2, Mail } from "lucide-react";
|
import { AlertCircle, CheckCircle2, Mail } from "lucide-react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function Component() {
|
export default function Component() {
|
||||||
@@ -21,22 +22,40 @@ export default function Component() {
|
|||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const [isError, setIsError] = useState(false);
|
const [isError, setIsError] = useState(false);
|
||||||
const [isValidated, setIsValidated] = useState(false);
|
const [isValidated, setIsValidated] = useState(false);
|
||||||
|
const [OTP, setOTP] = useState("");
|
||||||
|
|
||||||
// In a real app, this email would come from your authentication context
|
// In a real app, this email would come from your authentication context
|
||||||
const userEmail = "user@example.com";
|
const userEmail = "user@example.com";
|
||||||
|
|
||||||
const requestOTP = async () => {
|
const requestOTP = async () => {
|
||||||
await authClient.twoFactor.sendOtp();
|
const res = await authClient.twoFactor.sendOtp({
|
||||||
|
options: {
|
||||||
|
body: {
|
||||||
|
returnOTP: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setOTP(res.data?.OTP || "");
|
||||||
// In a real app, this would call your backend API to send the OTP
|
// In a real app, this would call your backend API to send the OTP
|
||||||
setMessage("OTP sent to your email");
|
setMessage("OTP sent to your email");
|
||||||
setIsError(false);
|
setIsError(false);
|
||||||
setIsOtpSent(true);
|
setIsOtpSent(true);
|
||||||
};
|
};
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const validateOTP = async () => {
|
const validateOTP = async () => {
|
||||||
await authClient.twoFactor.verifyOtp({
|
const res = await authClient.twoFactor.verifyOtp({
|
||||||
code: otp,
|
code: otp,
|
||||||
});
|
});
|
||||||
|
if (res.data) {
|
||||||
|
setMessage("OTP validated successfully");
|
||||||
|
setIsError(false);
|
||||||
|
setIsValidated(true);
|
||||||
|
router.push("/")
|
||||||
|
} else {
|
||||||
|
setIsError(true)
|
||||||
|
setMessage("Invalid OTP")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<main className="flex flex-col items-center justify-center min-h-screen">
|
<main className="flex flex-col items-center justify-center min-h-screen">
|
||||||
@@ -57,6 +76,10 @@ export default function Component() {
|
|||||||
<>
|
<>
|
||||||
<div className="flex flex-col space-y-1.5">
|
<div className="flex flex-col space-y-1.5">
|
||||||
<Label htmlFor="otp">One-Time Password</Label>
|
<Label htmlFor="otp">One-Time Password</Label>
|
||||||
|
<Label className="py-2">
|
||||||
|
Use <span className="text-blue-100 bg-slate-800 px-2">
|
||||||
|
{OTP}</span> (on real app, this would be sent to your email)
|
||||||
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="otp"
|
id="otp"
|
||||||
placeholder="Enter 6-digit OTP"
|
placeholder="Enter 6-digit OTP"
|
||||||
@@ -76,8 +99,7 @@ export default function Component() {
|
|||||||
</div>
|
</div>
|
||||||
{message && (
|
{message && (
|
||||||
<div
|
<div
|
||||||
className={`flex items-center gap-2 mt-4 ${
|
className={`flex items-center gap-2 mt-4 ${isError ? "text-red-500" : "text-primary"
|
||||||
isError ? "text-destructive" : "text-primary"
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isError ? (
|
{isError ? (
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Label } from "@/components/ui/label";
|
|
||||||
import { authClient } from "@/lib/auth-client";
|
import { authClient } from "@/lib/auth-client";
|
||||||
import { Fingerprint } from "lucide-react";
|
import { Fingerprint } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -23,7 +21,7 @@ export default function AddPasskey() {
|
|||||||
// This is where you would implement the actual passkey addition logic
|
// This is where you would implement the actual passkey addition logic
|
||||||
const res = await authClient.passkey.register()
|
const res = await authClient.passkey.register()
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
setPasskeyName("");
|
alert("Passkey added successfully. You can now use it to login.");
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
@@ -41,20 +39,7 @@ export default function AddPasskey() {
|
|||||||
password.
|
password.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="grid gap-4 py-4">
|
|
||||||
<div className="grid grid-cols-4 items-center gap-4">
|
|
||||||
<Label htmlFor="passkey-name" className="text-right">
|
|
||||||
Name
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
id="passkey-name"
|
|
||||||
value={passkeyName}
|
|
||||||
onChange={(e) => setPasskeyName(e.target.value)}
|
|
||||||
className="col-span-3"
|
|
||||||
placeholder="My Passkey"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button type="submit" onClick={handleAddPasskey} className="w-full">
|
<Button type="submit" onClick={handleAddPasskey} className="w-full">
|
||||||
<Fingerprint className="mr-2 h-4 w-4" />
|
<Fingerprint className="mr-2 h-4 w-4" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import { organization, passkey, twoFactor } from "better-auth/plugins";
|
import { organization, passkey, twoFactor } from "better-auth/plugins";
|
||||||
import { github } from "better-auth/social-providers";
|
import { github, google } from "better-auth/social-providers";
|
||||||
|
|
||||||
export const auth = betterAuth({
|
export const auth = betterAuth({
|
||||||
basePath: "/api/auth",
|
basePath: "/api/auth",
|
||||||
@@ -9,6 +9,10 @@ export const auth = betterAuth({
|
|||||||
clientId: process.env.GITHUB_CLIENT_ID as string,
|
clientId: process.env.GITHUB_CLIENT_ID as string,
|
||||||
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
|
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
|
||||||
}),
|
}),
|
||||||
|
google({
|
||||||
|
clientId: process.env.GOOGLE_CLIENT_ID as string,
|
||||||
|
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
database: {
|
database: {
|
||||||
provider: "sqlite",
|
provider: "sqlite",
|
||||||
|
|||||||
@@ -38,11 +38,22 @@ export const createInternalAdapter = (
|
|||||||
});
|
});
|
||||||
return createdUser;
|
return createdUser;
|
||||||
},
|
},
|
||||||
createSession: async (userId: string, request?: Request) => {
|
createSession: async (
|
||||||
|
userId: string,
|
||||||
|
request?: Request,
|
||||||
|
dontRememberMe?: boolean,
|
||||||
|
) => {
|
||||||
const data: Session = {
|
const data: Session = {
|
||||||
id: generateRandomString(32, alphabet("a-z", "0-9", "A-Z")),
|
id: generateRandomString(32, alphabet("a-z", "0-9", "A-Z")),
|
||||||
userId,
|
userId,
|
||||||
expiresAt: getDate(sessionExpiration),
|
/**
|
||||||
|
* If the user doesn't want to be remembered
|
||||||
|
* set the session to expire in 1 day.
|
||||||
|
* The cookie will be set to expire at the end of the session
|
||||||
|
*/
|
||||||
|
expiresAt: dontRememberMe
|
||||||
|
? getDate(1000 * 60 * 60 * 24) // 1 day
|
||||||
|
: getDate(sessionExpiration),
|
||||||
ipAddress: request?.headers.get("x-forwarded-for") || "",
|
ipAddress: request?.headers.get("x-forwarded-for") || "",
|
||||||
userAgent: request?.headers.get("user-agent") || "",
|
userAgent: request?.headers.get("user-agent") || "",
|
||||||
};
|
};
|
||||||
@@ -82,45 +93,18 @@ export const createInternalAdapter = (
|
|||||||
user,
|
user,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
updateSession: async (session: Session) => {
|
updateSession: async (sessionId: string, session: Partial<Session>) => {
|
||||||
const updateAge =
|
const updatedSession = await adapter.update<Session>({
|
||||||
options.session?.updateAge === undefined
|
|
||||||
? 1000 // 1 hour update age
|
|
||||||
: options.session?.updateAge;
|
|
||||||
const updateDate = updateAge === 0 ? 0 : getDate(updateAge).valueOf();
|
|
||||||
const maxAge = getDate(sessionExpiration);
|
|
||||||
const shouldBeUpdated =
|
|
||||||
session.expiresAt.valueOf() - maxAge.valueOf() + updateDate <=
|
|
||||||
Date.now();
|
|
||||||
if (shouldBeUpdated) {
|
|
||||||
const updatedSession = await adapter.create<Session>({
|
|
||||||
model: tables.session.tableName,
|
|
||||||
data: {
|
|
||||||
...session,
|
|
||||||
id: generateRandomString(32, alphabet("a-z", "0-9", "A-Z")),
|
|
||||||
expiresAt: new Date(Date.now() + sessionExpiration),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await adapter.update<Session>({
|
|
||||||
model: tables.session.tableName,
|
model: tables.session.tableName,
|
||||||
where: [
|
where: [
|
||||||
{
|
{
|
||||||
field: "id",
|
field: "id",
|
||||||
value: session.id,
|
value: sessionId,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
update: {
|
update: session,
|
||||||
/**
|
|
||||||
* update the session to expire in 2 minute. This is to prevent
|
|
||||||
* the session from expiring too quickly and logging the user out.
|
|
||||||
*/
|
|
||||||
expiresAt: new Date(Date.now() + 1000 * 60 * 2),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
return updatedSession;
|
return updatedSession;
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
|
||||||
},
|
},
|
||||||
deleteSession: async (id: string) => {
|
deleteSession: async (id: string) => {
|
||||||
const session = await adapter.delete<Session>({
|
const session = await adapter.delete<Session>({
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const createAuthMiddleware = createMiddlewareCreator({
|
|||||||
*/
|
*/
|
||||||
createMiddleware(async () => {
|
createMiddleware(async () => {
|
||||||
return {} as {
|
return {} as {
|
||||||
returned: Response;
|
returned?: Response;
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -19,14 +19,13 @@ export const csrfMiddleware = createAuthMiddleware(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = new URL(ctx.request.url);
|
const url = new URL(ctx.request.url);
|
||||||
console.log(url.origin, ctx.context.options.baseURL);
|
|
||||||
/**
|
/**
|
||||||
* If origin is the same as baseURL or if the
|
* If origin is the same as baseURL or if the
|
||||||
* origin is in the trustedOrigins then we
|
* origin is in the trustedOrigins then we
|
||||||
* don't need to check the CSRF token.
|
* don't need to check the CSRF token.
|
||||||
*/
|
*/
|
||||||
if (
|
if (
|
||||||
url.origin === ctx.context.options.baseURL ||
|
url.origin === new URL(ctx.context.baseURL).origin ||
|
||||||
ctx.context.options.trustedOrigins?.includes(url.origin)
|
ctx.context.options.trustedOrigins?.includes(url.origin)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { parseState } from "../../utils/state";
|
|||||||
import { createAuthEndpoint } from "../call";
|
import { createAuthEndpoint } from "../call";
|
||||||
import { HIDE_ON_CLIENT_METADATA } from "../../client/client-utils";
|
import { HIDE_ON_CLIENT_METADATA } from "../../client/client-utils";
|
||||||
import { getAccountTokens } from "../../utils/getAccount";
|
import { getAccountTokens } from "../../utils/getAccount";
|
||||||
|
import { setSessionCookie } from "../../utils/cookies";
|
||||||
|
|
||||||
export const callbackOAuth = createAuthEndpoint(
|
export const callbackOAuth = createAuthEndpoint(
|
||||||
"/callback/:id",
|
"/callback/:id",
|
||||||
@@ -14,7 +15,6 @@ export const callbackOAuth = createAuthEndpoint(
|
|||||||
query: z.object({
|
query: z.object({
|
||||||
state: z.string(),
|
state: z.string(),
|
||||||
code: z.string(),
|
code: z.string(),
|
||||||
code_verifier: z.string().optional(),
|
|
||||||
}),
|
}),
|
||||||
metadata: HIDE_ON_CLIENT_METADATA,
|
metadata: HIDE_ON_CLIENT_METADATA,
|
||||||
},
|
},
|
||||||
@@ -30,9 +30,14 @@ export const callbackOAuth = createAuthEndpoint(
|
|||||||
);
|
);
|
||||||
throw new APIError("NOT_FOUND");
|
throw new APIError("NOT_FOUND");
|
||||||
}
|
}
|
||||||
|
const codeVerifier = await c.getSignedCookie(
|
||||||
|
c.context.authCookies.pkCodeVerifier.name,
|
||||||
|
c.context.secret,
|
||||||
|
);
|
||||||
const tokens = await provider.validateAuthorizationCode(
|
const tokens = await provider.validateAuthorizationCode(
|
||||||
c.query.code,
|
c.query.code,
|
||||||
c.query.code_verifier || "",
|
codeVerifier,
|
||||||
|
`${c.context.baseURL}/callback/${provider.id}`,
|
||||||
);
|
);
|
||||||
if (!tokens) {
|
if (!tokens) {
|
||||||
c.context.logger.error("Code verification failed");
|
c.context.logger.error("Code verification failed");
|
||||||
@@ -44,7 +49,14 @@ export const callbackOAuth = createAuthEndpoint(
|
|||||||
...user,
|
...user,
|
||||||
id,
|
id,
|
||||||
});
|
});
|
||||||
const { callbackURL, currentURL } = parseState(c.query.state);
|
const parsedState = parseState(c.query.state);
|
||||||
|
if (!parsedState.success) {
|
||||||
|
c.context.logger.error("Unable to parse state");
|
||||||
|
throw new APIError("BAD_REQUEST", {
|
||||||
|
message: "invalid state",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const { callbackURL, currentURL, dontRememberMe } = parsedState.data;
|
||||||
if (!user || data.success === false) {
|
if (!user || data.success === false) {
|
||||||
if (currentURL) {
|
if (currentURL) {
|
||||||
throw c.redirect(`${currentURL}?error=oauth_validation_failed`);
|
throw c.redirect(`${currentURL}?error=oauth_validation_failed`);
|
||||||
@@ -105,14 +117,10 @@ export const callbackOAuth = createAuthEndpoint(
|
|||||||
const session = await c.context.internalAdapter.createSession(
|
const session = await c.context.internalAdapter.createSession(
|
||||||
userId || id,
|
userId || id,
|
||||||
c.request,
|
c.request,
|
||||||
|
dontRememberMe,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
await c.setSignedCookie(
|
await setSessionCookie(c, session.id, dontRememberMe);
|
||||||
c.context.authCookies.sessionToken.name,
|
|
||||||
session.id,
|
|
||||||
c.context.secret,
|
|
||||||
c.context.authCookies.sessionToken.options,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
c.context.logger.error("Unable to set session cookie", e);
|
c.context.logger.error("Unable to set session cookie", e);
|
||||||
const url = new URL(currentURL || callbackURL);
|
const url = new URL(currentURL || callbackURL);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export const getCSRFToken = createAuthEndpoint(
|
|||||||
csrfToken,
|
csrfToken,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = generateRandomString(32, alphabet("a-z", "0-9", "A-Z"));
|
const token = generateRandomString(32, alphabet("a-z", "0-9", "A-Z"));
|
||||||
const hash = await hs256(ctx.context.secret, token);
|
const hash = await hs256(ctx.context.secret, token);
|
||||||
const cookie = `${token}!${hash}`;
|
const cookie = `${token}!${hash}`;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { Context } from "better-call";
|
import type { Context } from "better-call";
|
||||||
import { createAuthEndpoint } from "../call";
|
import { createAuthEndpoint } from "../call";
|
||||||
|
import { getDate } from "../../utils/date";
|
||||||
|
import { deleteSessionCookie, setSessionCookie } from "../../utils/cookies";
|
||||||
|
|
||||||
export const getSession = createAuthEndpoint(
|
export const getSession = createAuthEndpoint(
|
||||||
"/session",
|
"/session",
|
||||||
@@ -12,43 +14,68 @@ export const getSession = createAuthEndpoint(
|
|||||||
ctx.context.authCookies.sessionToken.name,
|
ctx.context.authCookies.sessionToken.name,
|
||||||
ctx.context.secret,
|
ctx.context.secret,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sessionCookieToken) {
|
if (!sessionCookieToken) {
|
||||||
|
ctx.setHeader("set-cookie", "");
|
||||||
return ctx.json(null, {
|
return ctx.json(null, {
|
||||||
status: 401,
|
status: 401,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const session =
|
const session =
|
||||||
await ctx.context.internalAdapter.findSession(sessionCookieToken);
|
await ctx.context.internalAdapter.findSession(sessionCookieToken);
|
||||||
|
|
||||||
if (!session || session.session.expiresAt < new Date()) {
|
if (!session || session.session.expiresAt < new Date()) {
|
||||||
ctx.setSignedCookie(
|
deleteSessionCookie(ctx);
|
||||||
ctx.context.authCookies.sessionToken.name,
|
if (session) {
|
||||||
"",
|
/**
|
||||||
ctx.context.secret,
|
* if session expired clean up the session
|
||||||
{
|
*/
|
||||||
maxAge: 0,
|
await ctx.context.internalAdapter.deleteSession(session.session.id);
|
||||||
},
|
}
|
||||||
);
|
|
||||||
return ctx.json(null, {
|
return ctx.json(null, {
|
||||||
status: 401,
|
status: 401,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const updatedSession = await ctx.context.internalAdapter.updateSession(
|
const dontRememberMe = await ctx.getSignedCookie(
|
||||||
session.session,
|
ctx.context.authCookies.dontRememberToken.name,
|
||||||
);
|
|
||||||
|
|
||||||
await ctx.setSignedCookie(
|
|
||||||
ctx.context.authCookies.sessionToken.name,
|
|
||||||
updatedSession.id,
|
|
||||||
ctx.context.secret,
|
ctx.context.secret,
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* We don't need to update the session if the user doesn't want to be remembered
|
||||||
|
*/
|
||||||
|
if (dontRememberMe) {
|
||||||
|
return ctx.json(session);
|
||||||
|
}
|
||||||
|
const expiresIn = ctx.context.session.expiresIn;
|
||||||
|
const updateAge = ctx.context.session.updateAge;
|
||||||
|
/**
|
||||||
|
* Calculate last updated date to throttle write updates to database
|
||||||
|
* Formula: ({expiry date} - sessionMaxAge) + sessionUpdateAge
|
||||||
|
*
|
||||||
|
* e.g. ({expiry date} - 30 days) + 1 hour
|
||||||
|
*
|
||||||
|
* inspired by: https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/lib/
|
||||||
|
* actions/session.ts
|
||||||
|
*/
|
||||||
|
const sessionIsDueToBeUpdatedDate =
|
||||||
|
session.session.expiresAt.valueOf() - expiresIn * 1000 + updateAge * 1000;
|
||||||
|
|
||||||
|
if (sessionIsDueToBeUpdatedDate <= Date.now()) {
|
||||||
|
const updatedSession = await ctx.context.internalAdapter.updateSession(
|
||||||
|
session.session.id,
|
||||||
{
|
{
|
||||||
...ctx.context.authCookies.sessionToken.options,
|
expiresAt: getDate(ctx.context.session.expiresIn),
|
||||||
maxAge: updatedSession.expiresAt.valueOf() - Date.now(),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
await setSessionCookie(ctx, updatedSession.id, false, {
|
||||||
|
maxAge: updatedSession.expiresAt.valueOf() - Date.now(),
|
||||||
|
});
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
session: updatedSession,
|
session: updatedSession,
|
||||||
user: session.user,
|
user: session.user,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
return ctx.json(session);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { oAuthProviderList } from "../../social-providers";
|
|||||||
import { generateState } from "../../utils/state";
|
import { generateState } from "../../utils/state";
|
||||||
import { createAuthEndpoint } from "../call";
|
import { createAuthEndpoint } from "../call";
|
||||||
import { getSessionFromCtx } from "./session";
|
import { getSessionFromCtx } from "./session";
|
||||||
|
import { setSessionCookie } from "../../utils/cookies";
|
||||||
|
|
||||||
export const signInOAuth = createAuthEndpoint(
|
export const signInOAuth = createAuthEndpoint(
|
||||||
"/sign-in/social",
|
"/sign-in/social",
|
||||||
@@ -30,6 +31,10 @@ export const signInOAuth = createAuthEndpoint(
|
|||||||
* OAuth2 provider to use`
|
* OAuth2 provider to use`
|
||||||
*/
|
*/
|
||||||
provider: z.enum(oAuthProviderList),
|
provider: z.enum(oAuthProviderList),
|
||||||
|
/**
|
||||||
|
* If this is true the session will only be valid for the current browser session
|
||||||
|
*/
|
||||||
|
dontRememberMe: z.boolean().default(false).optional(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
async (c) => {
|
async (c) => {
|
||||||
@@ -73,6 +78,10 @@ export const signInOAuth = createAuthEndpoint(
|
|||||||
state: state.state,
|
state: state.state,
|
||||||
codeVerifier,
|
codeVerifier,
|
||||||
});
|
});
|
||||||
|
url.searchParams.set(
|
||||||
|
"redirect_uri",
|
||||||
|
`${c.context.baseURL}/callback/${c.body.provider}`,
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
url: url.toString(),
|
url: url.toString(),
|
||||||
state: state.state,
|
state: state.state,
|
||||||
@@ -109,12 +118,12 @@ export const signInEmail = createAuthEndpoint(
|
|||||||
}
|
}
|
||||||
const currentSession = await getSessionFromCtx(ctx);
|
const currentSession = await getSessionFromCtx(ctx);
|
||||||
if (currentSession) {
|
if (currentSession) {
|
||||||
return ctx.json({
|
/**
|
||||||
user: currentSession.user,
|
* Delete the current session if it exists
|
||||||
session: currentSession.session,
|
*/
|
||||||
redirect: !!ctx.body.callbackURL,
|
await ctx.context.internalAdapter.deleteSession(
|
||||||
url: ctx.body.callbackURL,
|
currentSession.session.id,
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
const { email, password } = ctx.body;
|
const { email, password } = ctx.body;
|
||||||
const checkEmail = z.string().email().safeParse(email);
|
const checkEmail = z.string().email().safeParse(email);
|
||||||
@@ -158,18 +167,9 @@ export const signInEmail = createAuthEndpoint(
|
|||||||
const session = await ctx.context.internalAdapter.createSession(
|
const session = await ctx.context.internalAdapter.createSession(
|
||||||
user.user.id,
|
user.user.id,
|
||||||
ctx.request,
|
ctx.request,
|
||||||
|
ctx.body.dontRememberMe,
|
||||||
);
|
);
|
||||||
await ctx.setSignedCookie(
|
await setSessionCookie(ctx, session.id, ctx.body.dontRememberMe);
|
||||||
ctx.context.authCookies.sessionToken.name,
|
|
||||||
session.id,
|
|
||||||
ctx.context.secret,
|
|
||||||
ctx.body.dontRememberMe
|
|
||||||
? {
|
|
||||||
...ctx.context.authCookies.sessionToken.options,
|
|
||||||
maxAge: undefined,
|
|
||||||
}
|
|
||||||
: ctx.context.authCookies.sessionToken.options,
|
|
||||||
);
|
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
user: user.user,
|
user: user.user,
|
||||||
session,
|
session,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { createAuthEndpoint } from "../call";
|
import { createAuthEndpoint } from "../call";
|
||||||
|
import { deleteSessionCookie } from "../../utils/cookies";
|
||||||
|
|
||||||
export const signOut = createAuthEndpoint(
|
export const signOut = createAuthEndpoint(
|
||||||
"/sign-out",
|
"/sign-out",
|
||||||
@@ -20,9 +21,7 @@ export const signOut = createAuthEndpoint(
|
|||||||
return ctx.json(null);
|
return ctx.json(null);
|
||||||
}
|
}
|
||||||
await ctx.context.internalAdapter.deleteSession(sessionCookieToken);
|
await ctx.context.internalAdapter.deleteSession(sessionCookieToken);
|
||||||
ctx.setCookie(ctx.context.authCookies.sessionToken.name, "", {
|
deleteSessionCookie(ctx);
|
||||||
maxAge: 0,
|
|
||||||
});
|
|
||||||
return ctx.json(null, {
|
return ctx.json(null, {
|
||||||
body: {
|
body: {
|
||||||
redirect: !!ctx.body?.callbackURL,
|
redirect: !!ctx.body?.callbackURL,
|
||||||
|
|||||||
@@ -32,6 +32,17 @@ export const csrfPlugin = {
|
|||||||
id: "csrf",
|
id: "csrf",
|
||||||
name: "CSRF Check",
|
name: "CSRF Check",
|
||||||
async init(url, options) {
|
async init(url, options) {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
/**
|
||||||
|
* If origin is the same as baseURL
|
||||||
|
* then we don't need to check the CSRF token.
|
||||||
|
*/
|
||||||
|
const isTheSameOrigin =
|
||||||
|
new URL(options?.baseURL || url).origin === window.location.origin;
|
||||||
|
if (isTheSameOrigin) {
|
||||||
|
return { url, options };
|
||||||
|
}
|
||||||
|
}
|
||||||
if (options?.method !== "GET") {
|
if (options?.method !== "GET") {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
const { data, error } = await betterFetch<{
|
const { data, error } = await betterFetch<{
|
||||||
|
|||||||
@@ -68,7 +68,13 @@ export function createDynamicPathProxy<T extends Record<string, any>>(
|
|||||||
|
|
||||||
return await client(routePath, {
|
return await client(routePath, {
|
||||||
...options,
|
...options,
|
||||||
body: method === "GET" ? undefined : body,
|
body:
|
||||||
|
method === "GET"
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
|
...body,
|
||||||
|
...(options?.body || {}),
|
||||||
|
},
|
||||||
query: query,
|
query: query,
|
||||||
method,
|
method,
|
||||||
async onSuccess(context) {
|
async onSuccess(context) {
|
||||||
@@ -79,8 +85,10 @@ export function createDynamicPathProxy<T extends Record<string, any>>(
|
|||||||
if (!matches) return;
|
if (!matches) return;
|
||||||
const signal = atoms[matches.signal];
|
const signal = atoms[matches.signal];
|
||||||
if (!signal) return;
|
if (!signal) return;
|
||||||
|
setTimeout(() => {
|
||||||
//@ts-expect-error
|
//@ts-expect-error
|
||||||
signal.set(!signal.get());
|
signal.set(!signal.get());
|
||||||
|
}, 0);
|
||||||
await options?.onSuccess?.(context);
|
await options?.onSuccess?.(context);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ export const init = (options: BetterAuthOptions) => {
|
|||||||
baseURL,
|
baseURL,
|
||||||
},
|
},
|
||||||
baseURL: baseURL || "",
|
baseURL: baseURL || "",
|
||||||
|
session: {
|
||||||
|
updateAge: options.session?.updateAge || 24 * 60 * 60, // 24 hours
|
||||||
|
expiresIn: options.session?.expiresIn || 60 * 60 * 24 * 7, // 7 days
|
||||||
|
},
|
||||||
secret:
|
secret:
|
||||||
options.secret ||
|
options.secret ||
|
||||||
process.env.BETTER_AUTH_SECRET ||
|
process.env.BETTER_AUTH_SECRET ||
|
||||||
@@ -47,4 +51,8 @@ export type AuthContext = {
|
|||||||
internalAdapter: ReturnType<typeof createInternalAdapter>;
|
internalAdapter: ReturnType<typeof createInternalAdapter>;
|
||||||
createAuthCookie: ReturnType<typeof createCookieGetter>;
|
createAuthCookie: ReturnType<typeof createCookieGetter>;
|
||||||
secret: string;
|
secret: string;
|
||||||
|
session: {
|
||||||
|
updateAge: number;
|
||||||
|
expiresIn: number;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { createAuthEndpoint } from "../../api/call";
|
|||||||
import { sessionMiddleware } from "../../api/middlewares/session";
|
import { sessionMiddleware } from "../../api/middlewares/session";
|
||||||
import { getSessionFromCtx } from "../../api/routes";
|
import { getSessionFromCtx } from "../../api/routes";
|
||||||
import type { BetterAuthPlugin } from "../../types/plugins";
|
import type { BetterAuthPlugin } from "../../types/plugins";
|
||||||
|
import { setSessionCookie } from "../../utils/cookies";
|
||||||
|
|
||||||
export interface PasskeyOptions {
|
export interface PasskeyOptions {
|
||||||
/**
|
/**
|
||||||
@@ -386,12 +387,7 @@ export const passkey = (options: PasskeyOptions) => {
|
|||||||
passkey.userId,
|
passkey.userId,
|
||||||
ctx.request,
|
ctx.request,
|
||||||
);
|
);
|
||||||
await ctx.setSignedCookie(
|
await setSessionCookie(ctx, s.id);
|
||||||
ctx.context.authCookies.sessionToken.name,
|
|
||||||
s.id,
|
|
||||||
ctx.context.secret,
|
|
||||||
ctx.context.authCookies.sessionToken.options,
|
|
||||||
);
|
|
||||||
if (callbackURL) {
|
if (callbackURL) {
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
url: callbackURL,
|
url: callbackURL,
|
||||||
|
|||||||
@@ -28,6 +28,16 @@ export const otp2fa = (options?: OTPOptions) => {
|
|||||||
"/two-factor/send-otp",
|
"/two-factor/send-otp",
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
body: z
|
||||||
|
.object({
|
||||||
|
/**
|
||||||
|
* should only be used for testing
|
||||||
|
* purposes. This will return the otp
|
||||||
|
* on the response body.
|
||||||
|
*/
|
||||||
|
returnOTP: z.boolean().default(false),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
use: [verifyTwoFactorMiddleware],
|
use: [verifyTwoFactorMiddleware],
|
||||||
},
|
},
|
||||||
async (ctx) => {
|
async (ctx) => {
|
||||||
@@ -57,7 +67,13 @@ export const otp2fa = (options?: OTPOptions) => {
|
|||||||
ctx.context.secret,
|
ctx.context.secret,
|
||||||
cookie.options,
|
cookie.options,
|
||||||
);
|
);
|
||||||
return ctx.json({ status: true });
|
/**
|
||||||
|
* only used for testing purposes
|
||||||
|
*/
|
||||||
|
if (ctx.body?.returnOTP) {
|
||||||
|
return ctx.json({ OTP: otp, status: true });
|
||||||
|
}
|
||||||
|
return ctx.json({ status: true, OTP: undefined });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { createAuthMiddleware } from "../../api/call";
|
|||||||
import { hs256 } from "../../crypto";
|
import { hs256 } from "../../crypto";
|
||||||
import { TWO_FACTOR_COOKIE_NAME } from "./constant";
|
import { TWO_FACTOR_COOKIE_NAME } from "./constant";
|
||||||
import type { UserWithTwoFactor } from "./types";
|
import type { UserWithTwoFactor } from "./types";
|
||||||
|
import { setSessionCookie } from "../../utils/cookies";
|
||||||
|
|
||||||
export const verifyTwoFactorMiddleware = createAuthMiddleware(async (ctx) => {
|
export const verifyTwoFactorMiddleware = createAuthMiddleware(async (ctx) => {
|
||||||
const cookie = await ctx.getSignedCookie(
|
const cookie = await ctx.getSignedCookie(
|
||||||
@@ -62,15 +63,7 @@ export const verifyTwoFactorMiddleware = createAuthMiddleware(async (ctx) => {
|
|||||||
if (hashToMatch === hash) {
|
if (hashToMatch === hash) {
|
||||||
return {
|
return {
|
||||||
valid: async () => {
|
valid: async () => {
|
||||||
/**
|
await setSessionCookie(ctx, session.id, false);
|
||||||
* Set the session cookie
|
|
||||||
*/
|
|
||||||
await ctx.setSignedCookie(
|
|
||||||
ctx.context.authCookies.sessionToken.name,
|
|
||||||
session.id,
|
|
||||||
ctx.context.secret,
|
|
||||||
ctx.context.authCookies.sessionToken.options,
|
|
||||||
);
|
|
||||||
if (ctx.body.callbackURL) {
|
if (ctx.body.callbackURL) {
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
status: true,
|
status: true,
|
||||||
@@ -78,7 +71,6 @@ export const verifyTwoFactorMiddleware = createAuthMiddleware(async (ctx) => {
|
|||||||
redirect: true,
|
redirect: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.json({ status: true });
|
return ctx.json({ status: true });
|
||||||
},
|
},
|
||||||
invalid: async () => {
|
invalid: async () => {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { betterFetch } from "@better-fetch/fetch";
|
import { betterFetch } from "@better-fetch/fetch";
|
||||||
import { Discord } from "arctic";
|
import { Discord } from "arctic";
|
||||||
import type { OAuthProvider } from ".";
|
import type { OAuthProvider } from ".";
|
||||||
import { getRedirectURI } from "./utils";
|
import { getRedirectURI, validateAuthorizationCode } from "./utils";
|
||||||
|
import { createOAuth2Request, sendTokenRequest } from "arctic/dist/request";
|
||||||
|
|
||||||
export interface DiscordProfile extends Record<string, any> {
|
export interface DiscordProfile extends Record<string, any> {
|
||||||
/** the user's id (i.e. the numerical snowflake) */
|
/** the user's id (i.e. the numerical snowflake) */
|
||||||
@@ -81,15 +82,11 @@ export interface DiscordOptions {
|
|||||||
redirectURI?: string;
|
redirectURI?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const discord = ({
|
export const discord = (options: DiscordOptions) => {
|
||||||
clientId,
|
|
||||||
clientSecret,
|
|
||||||
redirectURI,
|
|
||||||
}: DiscordOptions) => {
|
|
||||||
const discordArctic = new Discord(
|
const discordArctic = new Discord(
|
||||||
clientId,
|
options.clientId,
|
||||||
clientSecret,
|
options.clientSecret,
|
||||||
getRedirectURI("discord", redirectURI),
|
getRedirectURI("discord", options.redirectURI),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
id: "discord",
|
id: "discord",
|
||||||
@@ -98,7 +95,16 @@ export const discord = ({
|
|||||||
const _scope = scopes || ["email"];
|
const _scope = scopes || ["email"];
|
||||||
return discordArctic.createAuthorizationURL(state, _scope);
|
return discordArctic.createAuthorizationURL(state, _scope);
|
||||||
},
|
},
|
||||||
validateAuthorizationCode: discordArctic.validateAuthorizationCode,
|
validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
|
||||||
|
return validateAuthorizationCode({
|
||||||
|
code,
|
||||||
|
codeVerifier,
|
||||||
|
redirectURI:
|
||||||
|
redirectURI || getRedirectURI("discord", options.redirectURI),
|
||||||
|
options,
|
||||||
|
tokenEndpoint: "https://discord.com/api/oauth2/token",
|
||||||
|
});
|
||||||
|
},
|
||||||
async getUserInfo(token) {
|
async getUserInfo(token) {
|
||||||
const { data: profile, error } = await betterFetch<DiscordProfile>(
|
const { data: profile, error } = await betterFetch<DiscordProfile>(
|
||||||
"https://discord.com/api/users/@me",
|
"https://discord.com/api/users/@me",
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { betterFetch } from "@better-fetch/fetch";
|
import { betterFetch } from "@better-fetch/fetch";
|
||||||
import { Facebook } from "arctic";
|
import { Facebook } from "arctic";
|
||||||
import type { OAuthProvider } from ".";
|
import type { OAuthProvider } from ".";
|
||||||
import { getRedirectURI } from "./utils";
|
import { getRedirectURI, validateAuthorizationCode } from "./utils";
|
||||||
|
import { createOAuth2Request, sendTokenRequest } from "arctic/dist/request";
|
||||||
|
|
||||||
export interface FacebookProfile {
|
export interface FacebookProfile {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -22,15 +23,11 @@ export interface FacebookOptions {
|
|||||||
clientSecret: string;
|
clientSecret: string;
|
||||||
redirectURI?: string;
|
redirectURI?: string;
|
||||||
}
|
}
|
||||||
export const facebook = ({
|
export const facebook = (options: FacebookOptions) => {
|
||||||
clientId,
|
|
||||||
clientSecret,
|
|
||||||
redirectURI,
|
|
||||||
}: FacebookOptions) => {
|
|
||||||
const facebookArctic = new Facebook(
|
const facebookArctic = new Facebook(
|
||||||
clientId,
|
options.clientId,
|
||||||
clientSecret,
|
options.clientSecret,
|
||||||
getRedirectURI("facebook", redirectURI),
|
getRedirectURI("facebook", options.redirectURI),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
id: "facebook",
|
id: "facebook",
|
||||||
@@ -39,7 +36,16 @@ export const facebook = ({
|
|||||||
const _scopes = scopes || ["email", "public_profile"];
|
const _scopes = scopes || ["email", "public_profile"];
|
||||||
return facebookArctic.createAuthorizationURL(state, _scopes);
|
return facebookArctic.createAuthorizationURL(state, _scopes);
|
||||||
},
|
},
|
||||||
validateAuthorizationCode: facebookArctic.validateAuthorizationCode,
|
validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
|
||||||
|
return validateAuthorizationCode({
|
||||||
|
code,
|
||||||
|
codeVerifier,
|
||||||
|
redirectURI:
|
||||||
|
redirectURI || getRedirectURI("facebook", options.redirectURI),
|
||||||
|
options,
|
||||||
|
tokenEndpoint: "https://graph.facebook.com/v16.0/oauth/access_token",
|
||||||
|
});
|
||||||
|
},
|
||||||
async getUserInfo(token) {
|
async getUserInfo(token) {
|
||||||
const { data: profile, error } = await betterFetch<FacebookProfile>(
|
const { data: profile, error } = await betterFetch<FacebookProfile>(
|
||||||
"https://graph.facebook.com/me",
|
"https://graph.facebook.com/me",
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { Google } from "arctic";
|
import { Google } from "arctic";
|
||||||
import { parseJWT } from "oslo/jwt";
|
import { parseJWT } from "oslo/jwt";
|
||||||
import type { OAuthProvider } from ".";
|
import type { OAuthProvider, ProviderOptions } from ".";
|
||||||
import { getRedirectURI } from "./utils";
|
|
||||||
import { BetterAuthError } from "../error/better-auth-error";
|
import { BetterAuthError } from "../error/better-auth-error";
|
||||||
|
import { logger } from "../utils/logger";
|
||||||
|
import { createOAuth2Request, sendTokenRequest } from "arctic/dist/request";
|
||||||
|
import { getRedirectURI, validateAuthorizationCode } from "./utils";
|
||||||
|
|
||||||
export interface GoogleProfile {
|
export interface GoogleProfile {
|
||||||
aud: string;
|
aud: string;
|
||||||
@@ -31,37 +33,40 @@ export interface GoogleProfile {
|
|||||||
sub: string;
|
sub: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GoogleOptions {
|
export interface GoogleOptions extends ProviderOptions {}
|
||||||
clientId: string;
|
|
||||||
clientSecret: string;
|
|
||||||
redirectURI?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const google = ({
|
export const google = (options: GoogleOptions) => {
|
||||||
clientId,
|
|
||||||
clientSecret,
|
|
||||||
redirectURI,
|
|
||||||
}: GoogleOptions) => {
|
|
||||||
const googleArctic = new Google(
|
const googleArctic = new Google(
|
||||||
clientId,
|
options.clientId,
|
||||||
clientSecret,
|
options.clientSecret,
|
||||||
getRedirectURI("google", redirectURI),
|
getRedirectURI("google", options.redirectURI),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
id: "google",
|
id: "google",
|
||||||
name: "Google",
|
name: "Google",
|
||||||
createAuthorizationURL({ state, scopes, codeVerifier }) {
|
createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
||||||
|
redirectURI;
|
||||||
|
if (!options.clientId || !options.clientSecret) {
|
||||||
|
logger.error(
|
||||||
|
"clientId and clientSecret is required for Google. Make sure to you have provided them in the options",
|
||||||
|
);
|
||||||
|
throw new BetterAuthError("clientId is required for Google");
|
||||||
|
}
|
||||||
if (!codeVerifier) {
|
if (!codeVerifier) {
|
||||||
throw new BetterAuthError("codeVerifier is required for Google");
|
throw new BetterAuthError("codeVerifier is required for Google");
|
||||||
}
|
}
|
||||||
const _scopes = scopes || ["email", "profile"];
|
const _scopes = scopes || ["email", "profile"];
|
||||||
return googleArctic.createAuthorizationURL(state, codeVerifier, _scopes);
|
return googleArctic.createAuthorizationURL(state, codeVerifier, _scopes);
|
||||||
},
|
},
|
||||||
validateAuthorizationCode: async (code, codeVerifier) => {
|
validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
|
||||||
if (!codeVerifier) {
|
return validateAuthorizationCode({
|
||||||
throw new BetterAuthError("codeVerifier is required for Google");
|
code,
|
||||||
}
|
codeVerifier,
|
||||||
return googleArctic.validateAuthorizationCode(code, codeVerifier);
|
redirectURI:
|
||||||
|
redirectURI || getRedirectURI("google", options.redirectURI),
|
||||||
|
options,
|
||||||
|
tokenEndpoint: "https://oauth2.googleapis.com/token",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
async getUserInfo(token) {
|
async getUserInfo(token) {
|
||||||
if (!token.idToken) {
|
if (!token.idToken) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { betterFetch } from "@better-fetch/fetch";
|
import { betterFetch } from "@better-fetch/fetch";
|
||||||
import { Spotify } from "arctic";
|
import { Spotify } from "arctic";
|
||||||
import type { OAuthProvider } from ".";
|
import type { OAuthProvider } from ".";
|
||||||
import { getRedirectURI } from "./utils";
|
import { getRedirectURI, validateAuthorizationCode } from "./utils";
|
||||||
|
|
||||||
export interface SpotifyProfile {
|
export interface SpotifyProfile {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -18,15 +18,11 @@ export interface SpotifyOptions {
|
|||||||
redirectURI?: string;
|
redirectURI?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const spotify = ({
|
export const spotify = (options: SpotifyOptions) => {
|
||||||
clientId,
|
|
||||||
clientSecret,
|
|
||||||
redirectURI,
|
|
||||||
}: SpotifyOptions) => {
|
|
||||||
const spotifyArctic = new Spotify(
|
const spotifyArctic = new Spotify(
|
||||||
clientId,
|
options.clientId,
|
||||||
clientSecret,
|
options.clientSecret,
|
||||||
getRedirectURI("spotify", redirectURI),
|
getRedirectURI("spotify", options.redirectURI),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
id: "spotify",
|
id: "spotify",
|
||||||
@@ -35,7 +31,16 @@ export const spotify = ({
|
|||||||
const _scopes = scopes || ["user-read-email"];
|
const _scopes = scopes || ["user-read-email"];
|
||||||
return spotifyArctic.createAuthorizationURL(state, _scopes);
|
return spotifyArctic.createAuthorizationURL(state, _scopes);
|
||||||
},
|
},
|
||||||
validateAuthorizationCode: spotifyArctic.validateAuthorizationCode,
|
validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
|
||||||
|
return validateAuthorizationCode({
|
||||||
|
code,
|
||||||
|
codeVerifier,
|
||||||
|
redirectURI:
|
||||||
|
redirectURI || getRedirectURI("spotify", options.redirectURI),
|
||||||
|
options,
|
||||||
|
tokenEndpoint: "https://accounts.spotify.com/api/token",
|
||||||
|
});
|
||||||
|
},
|
||||||
async getUserInfo(token) {
|
async getUserInfo(token) {
|
||||||
const { data: profile, error } = await betterFetch<SpotifyProfile>(
|
const { data: profile, error } = await betterFetch<SpotifyProfile>(
|
||||||
"https://api.spotify.com/v1/me",
|
"https://api.spotify.com/v1/me",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { betterFetch } from "@better-fetch/fetch";
|
import { betterFetch } from "@better-fetch/fetch";
|
||||||
import { Twitch } from "arctic";
|
import { Twitch } from "arctic";
|
||||||
import type { OAuthProvider } from ".";
|
import type { OAuthProvider } from ".";
|
||||||
import { getRedirectURI } from "./utils";
|
import { getRedirectURI, validateAuthorizationCode } from "./utils";
|
||||||
|
|
||||||
export interface TwitchProfile {
|
export interface TwitchProfile {
|
||||||
/**
|
/**
|
||||||
@@ -28,15 +28,11 @@ export interface TwitchOptions {
|
|||||||
redirectURI?: string;
|
redirectURI?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const twitch = ({
|
export const twitch = (options: TwitchOptions) => {
|
||||||
clientId,
|
|
||||||
clientSecret,
|
|
||||||
redirectURI,
|
|
||||||
}: TwitchOptions) => {
|
|
||||||
const twitchArctic = new Twitch(
|
const twitchArctic = new Twitch(
|
||||||
clientId,
|
options.clientId,
|
||||||
clientSecret,
|
options.clientSecret,
|
||||||
getRedirectURI("twitch", redirectURI),
|
getRedirectURI("twitch", options.redirectURI),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
id: "twitch",
|
id: "twitch",
|
||||||
@@ -45,7 +41,16 @@ export const twitch = ({
|
|||||||
const _scopes = scopes || ["activity:write", "read"];
|
const _scopes = scopes || ["activity:write", "read"];
|
||||||
return twitchArctic.createAuthorizationURL(state, _scopes);
|
return twitchArctic.createAuthorizationURL(state, _scopes);
|
||||||
},
|
},
|
||||||
validateAuthorizationCode: twitchArctic.validateAuthorizationCode,
|
validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
|
||||||
|
return validateAuthorizationCode({
|
||||||
|
code,
|
||||||
|
codeVerifier,
|
||||||
|
redirectURI:
|
||||||
|
redirectURI || getRedirectURI("twitch", options.redirectURI),
|
||||||
|
options,
|
||||||
|
tokenEndpoint: "https://id.twitch.tv/oauth2/token",
|
||||||
|
});
|
||||||
|
},
|
||||||
async getUserInfo(token) {
|
async getUserInfo(token) {
|
||||||
const { data: profile, error } = await betterFetch<TwitchProfile>(
|
const { data: profile, error } = await betterFetch<TwitchProfile>(
|
||||||
"https://api.twitch.tv/helix/users",
|
"https://api.twitch.tv/helix/users",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { betterFetch } from "@better-fetch/fetch";
|
import { betterFetch } from "@better-fetch/fetch";
|
||||||
import { Twitter } from "arctic";
|
import { Twitter } from "arctic";
|
||||||
import type { OAuthProvider } from ".";
|
import type { OAuthProvider } from ".";
|
||||||
import { getRedirectURI } from "./utils";
|
import { getRedirectURI, validateAuthorizationCode } from "./utils";
|
||||||
import { BetterAuthError } from "../error/better-auth-error";
|
import { BetterAuthError } from "../error/better-auth-error";
|
||||||
|
|
||||||
export interface TwitterProfile {
|
export interface TwitterProfile {
|
||||||
@@ -99,15 +99,11 @@ export interface TwitterOption {
|
|||||||
redirectURI?: string;
|
redirectURI?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const twitter = ({
|
export const twitter = (options: TwitterOption) => {
|
||||||
clientId,
|
|
||||||
clientSecret,
|
|
||||||
redirectURI,
|
|
||||||
}: TwitterOption) => {
|
|
||||||
const twitterArctic = new Twitter(
|
const twitterArctic = new Twitter(
|
||||||
clientId,
|
options.clientId,
|
||||||
clientSecret,
|
options.clientSecret,
|
||||||
getRedirectURI("twitter", redirectURI),
|
getRedirectURI("twitter", options.redirectURI),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
id: "twitter",
|
id: "twitter",
|
||||||
@@ -120,11 +116,15 @@ export const twitter = ({
|
|||||||
_scopes,
|
_scopes,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
validateAuthorizationCode: async (code, codeVerifier) => {
|
validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
|
||||||
if (!codeVerifier) {
|
return validateAuthorizationCode({
|
||||||
throw new BetterAuthError("codeVerifier is required for Twitter");
|
code,
|
||||||
}
|
codeVerifier,
|
||||||
return twitterArctic.validateAuthorizationCode(code, codeVerifier);
|
redirectURI:
|
||||||
|
redirectURI || getRedirectURI("twitch", options.redirectURI),
|
||||||
|
options,
|
||||||
|
tokenEndpoint: "https://id.twitch.tv/oauth2/token",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
async getUserInfo(token) {
|
async getUserInfo(token) {
|
||||||
const { data: profile, error } = await betterFetch<TwitterProfile>(
|
const { data: profile, error } = await betterFetch<TwitterProfile>(
|
||||||
|
|||||||
@@ -1,5 +1,32 @@
|
|||||||
|
import { createOAuth2Request, sendTokenRequest } from "arctic/dist/request";
|
||||||
|
import type { ProviderOptions } from ".";
|
||||||
import { getBaseURL } from "../utils/base-url";
|
import { getBaseURL } from "../utils/base-url";
|
||||||
|
|
||||||
export function getRedirectURI(providerId: string, redirectURI?: string) {
|
export function getRedirectURI(providerId: string, redirectURI?: string) {
|
||||||
return redirectURI || `${getBaseURL()}/callback/${providerId}`;
|
return redirectURI || `${getBaseURL()}/callback/${providerId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function validateAuthorizationCode({
|
||||||
|
code,
|
||||||
|
codeVerifier,
|
||||||
|
redirectURI,
|
||||||
|
options,
|
||||||
|
tokenEndpoint,
|
||||||
|
}: {
|
||||||
|
code: string;
|
||||||
|
redirectURI: string;
|
||||||
|
options: ProviderOptions;
|
||||||
|
codeVerifier?: string;
|
||||||
|
tokenEndpoint: string;
|
||||||
|
}) {
|
||||||
|
const body = new URLSearchParams();
|
||||||
|
body.set("grant_type", "authorization_code");
|
||||||
|
body.set("code", code);
|
||||||
|
body.set("code_verifier", codeVerifier || "");
|
||||||
|
body.set("redirect_uri", redirectURI);
|
||||||
|
body.set("client_id", options.clientId);
|
||||||
|
body.set("client_secret", options.clientSecret);
|
||||||
|
const request = createOAuth2Request(tokenEndpoint, body);
|
||||||
|
const tokens = await sendTokenRequest(request);
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
import type { ContextTools } from "better-call";
|
import type { ContextTools } from "better-call";
|
||||||
import type { AuthContext } from "../init";
|
import type { AuthContext } from "../init";
|
||||||
|
|
||||||
|
export type HookEndpointContext = ContextTools & {
|
||||||
|
context: AuthContext;
|
||||||
|
} & {
|
||||||
|
body: any;
|
||||||
|
request?: Request;
|
||||||
|
headers?: Headers;
|
||||||
|
params?: Record<string, string> | undefined;
|
||||||
|
query?: any;
|
||||||
|
method?: any;
|
||||||
|
};
|
||||||
|
|
||||||
export type GenericEndpointContext = ContextTools & {
|
export type GenericEndpointContext = ContextTools & {
|
||||||
context: AuthContext;
|
context: AuthContext;
|
||||||
} & {
|
} & {
|
||||||
body: any;
|
body?: any;
|
||||||
request: Request;
|
request?: Request;
|
||||||
headers: Headers;
|
headers?: Headers;
|
||||||
params?: Record<string, string> | undefined;
|
params?: Record<string, string> | undefined;
|
||||||
query: any;
|
query?: any;
|
||||||
method: "*";
|
method?: any;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { Endpoint, EndpointResponse } from "better-call";
|
|||||||
import type { Migration } from "kysely";
|
import type { Migration } from "kysely";
|
||||||
import type { AuthEndpoint } from "../api/call";
|
import type { AuthEndpoint } from "../api/call";
|
||||||
import type { FieldAttribute } from "../db/field";
|
import type { FieldAttribute } from "../db/field";
|
||||||
import type { GenericEndpointContext } from "./context";
|
import type { HookEndpointContext } from "./context";
|
||||||
import type { LiteralString } from "./helper";
|
import type { LiteralString } from "./helper";
|
||||||
|
|
||||||
export type PluginSchema = {
|
export type PluginSchema = {
|
||||||
@@ -25,15 +25,15 @@ export type BetterAuthPlugin = {
|
|||||||
}[];
|
}[];
|
||||||
hooks?: {
|
hooks?: {
|
||||||
before?: {
|
before?: {
|
||||||
matcher: (context: GenericEndpointContext) => boolean;
|
matcher: (context: HookEndpointContext) => boolean;
|
||||||
handler: (context: GenericEndpointContext) => Promise<void | {
|
handler: (context: HookEndpointContext) => Promise<void | {
|
||||||
context: Partial<GenericEndpointContext>;
|
context: Partial<HookEndpointContext>;
|
||||||
}>;
|
}>;
|
||||||
}[];
|
}[];
|
||||||
after?: {
|
after?: {
|
||||||
matcher: (context: GenericEndpointContext) => boolean;
|
matcher: (context: HookEndpointContext) => boolean;
|
||||||
handler: (
|
handler: (
|
||||||
context: GenericEndpointContext & {
|
context: HookEndpointContext & {
|
||||||
returned: EndpointResponse;
|
returned: EndpointResponse;
|
||||||
},
|
},
|
||||||
) => Promise<void | {
|
) => Promise<void | {
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ export interface OAuthProvider<
|
|||||||
state: string;
|
state: string;
|
||||||
codeVerifier: string;
|
codeVerifier: string;
|
||||||
scopes?: string[];
|
scopes?: string[];
|
||||||
|
redirectURI?: string;
|
||||||
}) => URL;
|
}) => URL;
|
||||||
name: string;
|
name: string;
|
||||||
validateAuthorizationCode: (
|
validateAuthorizationCode: (
|
||||||
code: string,
|
code: string,
|
||||||
codeVerifier?: string,
|
codeVerifier?: string,
|
||||||
|
redirectURI?: string,
|
||||||
) => Promise<OAuth2Tokens>;
|
) => Promise<OAuth2Tokens>;
|
||||||
getUserInfo: (token: OAuth2Tokens) => Promise<{
|
getUserInfo: (token: OAuth2Tokens) => Promise<{
|
||||||
user: Omit<User, "createdAt" | "updatedAt">;
|
user: Omit<User, "createdAt" | "updatedAt">;
|
||||||
@@ -26,3 +28,24 @@ export interface OAuthProvider<
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type OAuthProviderList = typeof oAuthProviderList;
|
export type OAuthProviderList = typeof oAuthProviderList;
|
||||||
|
|
||||||
|
export type ProviderOptions = {
|
||||||
|
/**
|
||||||
|
* The client ID of your application
|
||||||
|
*/
|
||||||
|
clientId: string;
|
||||||
|
/**
|
||||||
|
* The client secret of your application
|
||||||
|
*/
|
||||||
|
clientSecret: string;
|
||||||
|
/**
|
||||||
|
* The scopes you want to request from the provider
|
||||||
|
*/
|
||||||
|
scope?: string[];
|
||||||
|
/**
|
||||||
|
* The redirect URL for your application. This is where the provider will
|
||||||
|
* redirect the user after the sign in process. Make sure this URL is
|
||||||
|
* whitelisted in the provider's dashboard.
|
||||||
|
*/
|
||||||
|
redirectURI?: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { CookieOptions } from "better-call";
|
import type { Context, CookieOptions } from "better-call";
|
||||||
import { TimeSpan } from "oslo";
|
import { TimeSpan } from "oslo";
|
||||||
import type { BetterAuthOptions } from "../types/options";
|
import type { BetterAuthOptions } from "../types/options";
|
||||||
|
import type { GenericEndpointContext } from "../types/context";
|
||||||
|
|
||||||
export function getCookies(options: BetterAuthOptions) {
|
export function getCookies(options: BetterAuthOptions) {
|
||||||
const secure =
|
const secure =
|
||||||
@@ -50,6 +51,16 @@ export function getCookies(options: BetterAuthOptions) {
|
|||||||
maxAge: 60 * 15, // 15 minutes in seconds
|
maxAge: 60 * 15, // 15 minutes in seconds
|
||||||
} as CookieOptions,
|
} as CookieOptions,
|
||||||
},
|
},
|
||||||
|
dontRememberToken: {
|
||||||
|
name: `${secureCookiePrefix}${cookiePrefix}.dont_remember`,
|
||||||
|
options: {
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: "lax",
|
||||||
|
path: "/",
|
||||||
|
secure,
|
||||||
|
//no max age so it expires when the browser closes
|
||||||
|
} as CookieOptions,
|
||||||
|
},
|
||||||
nonce: {
|
nonce: {
|
||||||
name: `${secureCookiePrefix}${cookiePrefix}.nonce`,
|
name: `${secureCookiePrefix}${cookiePrefix}.nonce`,
|
||||||
options: {
|
options: {
|
||||||
@@ -87,3 +98,43 @@ export function createCookieGetter(options: BetterAuthOptions) {
|
|||||||
return getCookie;
|
return getCookie;
|
||||||
}
|
}
|
||||||
export type BetterAuthCookies = ReturnType<typeof getCookies>;
|
export type BetterAuthCookies = ReturnType<typeof getCookies>;
|
||||||
|
|
||||||
|
export async function setSessionCookie(
|
||||||
|
ctx: GenericEndpointContext,
|
||||||
|
sessionToken: string,
|
||||||
|
dontRememberMe?: boolean,
|
||||||
|
overrides?: Partial<CookieOptions>,
|
||||||
|
) {
|
||||||
|
await ctx.setSignedCookie(
|
||||||
|
ctx.context.authCookies.sessionToken.name,
|
||||||
|
sessionToken,
|
||||||
|
ctx.context.secret,
|
||||||
|
dontRememberMe
|
||||||
|
? {
|
||||||
|
...ctx.context.authCookies.sessionToken.options,
|
||||||
|
maxAge: undefined,
|
||||||
|
...overrides,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
...ctx.context.authCookies.sessionToken.options,
|
||||||
|
...overrides,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (dontRememberMe) {
|
||||||
|
await ctx.setSignedCookie(
|
||||||
|
ctx.context.authCookies.dontRememberToken.name,
|
||||||
|
"true",
|
||||||
|
ctx.context.secret,
|
||||||
|
ctx.context.authCookies.dontRememberToken.options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteSessionCookie(ctx: GenericEndpointContext) {
|
||||||
|
ctx.setCookie(ctx.context.authCookies.sessionToken.name, "", {
|
||||||
|
maxAge: 0,
|
||||||
|
});
|
||||||
|
ctx.setCookie(ctx.context.authCookies.dontRememberToken.name, "", {
|
||||||
|
maxAge: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ import { createConsola } from "consola";
|
|||||||
const consola = createConsola({
|
const consola = createConsola({
|
||||||
formatOptions: {
|
formatOptions: {
|
||||||
date: false,
|
date: false,
|
||||||
|
colors: true,
|
||||||
|
compact: true,
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
|
tag: "[Better Auth]",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,29 @@
|
|||||||
import { generateState as generateStateOAuth } from "oslo/oauth2";
|
import { generateState as generateStateOAuth } from "oslo/oauth2";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export function generateState(callbackURL?: string, currentURL?: string) {
|
export function generateState(
|
||||||
|
callbackURL?: string,
|
||||||
|
currentURL?: string,
|
||||||
|
dontRememberMe?: boolean,
|
||||||
|
) {
|
||||||
const code = generateStateOAuth();
|
const code = generateStateOAuth();
|
||||||
const state = `${code}!${callbackURL}!${currentURL}`;
|
const state = JSON.stringify({
|
||||||
|
code,
|
||||||
|
callbackURL,
|
||||||
|
currentURL,
|
||||||
|
dontRememberMe,
|
||||||
|
});
|
||||||
return { state, code };
|
return { state, code };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseState(state: string) {
|
export function parseState(state: string) {
|
||||||
const [code, callbackURL, currentURL] = state.split("!");
|
const data = z
|
||||||
return { code, callbackURL, currentURL };
|
.object({
|
||||||
|
code: z.string(),
|
||||||
|
callbackURL: z.string().optional(),
|
||||||
|
currentURL: z.string().optional(),
|
||||||
|
dontRememberMe: z.boolean().optional(),
|
||||||
|
})
|
||||||
|
.safeParse(JSON.parse(state));
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
249
pnpm-lock.yaml
generated
249
pnpm-lock.yaml
generated
@@ -41,7 +41,7 @@ importers:
|
|||||||
version: 1.12.2(hono@4.5.9)
|
version: 1.12.2(hono@4.5.9)
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.4.38(typescript@5.6.0-beta))
|
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.5
|
specifier: ^16.4.5
|
||||||
version: 16.4.5
|
version: 16.4.5
|
||||||
@@ -60,7 +60,7 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4))
|
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.0(typescript@5.5.4))
|
||||||
react:
|
react:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
@@ -148,7 +148,7 @@ importers:
|
|||||||
version: 3.12.0(react@18.3.1)
|
version: 3.12.0(react@18.3.1)
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4))
|
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.0(typescript@5.5.4))
|
||||||
better-call:
|
better-call:
|
||||||
specifier: ^0.1.0
|
specifier: ^0.1.0
|
||||||
version: 0.1.0(typescript@5.5.4)
|
version: 0.1.0(typescript@5.5.4)
|
||||||
@@ -227,13 +227,13 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.4.38(typescript@5.6.0-beta))
|
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
nuxt:
|
nuxt:
|
||||||
specifier: ^3.13.0
|
specifier: ^3.13.0
|
||||||
version: 3.13.0(@biomejs/biome@1.7.3)(@parcel/watcher@2.4.1)(@types/node@22.3.0)(eslint@9.9.1)(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.0-beta)(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))
|
version: 3.13.0(@biomejs/biome@1.7.3)(@parcel/watcher@2.4.1)(@types/node@22.3.0)(eslint@9.9.1)(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.0-beta)(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))
|
||||||
vue:
|
vue:
|
||||||
specifier: latest
|
specifier: latest
|
||||||
version: 3.4.38(typescript@5.6.0-beta)
|
version: 3.5.0(typescript@5.6.0-beta)
|
||||||
|
|
||||||
dev/solidjs:
|
dev/solidjs:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -248,7 +248,7 @@ importers:
|
|||||||
version: 10.4.20(postcss@8.4.41)
|
version: 10.4.20(postcss@8.4.41)
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.4.38(typescript@5.6.0-beta))
|
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
postcss:
|
postcss:
|
||||||
specifier: ^8.4.38
|
specifier: ^8.4.38
|
||||||
version: 8.4.41
|
version: 8.4.41
|
||||||
@@ -266,7 +266,7 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4))
|
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.0(typescript@5.5.4))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@sveltejs/adapter-auto':
|
'@sveltejs/adapter-auto':
|
||||||
specifier: ^3.0.0
|
specifier: ^3.0.0
|
||||||
@@ -282,7 +282,7 @@ importers:
|
|||||||
version: 4.2.19
|
version: 4.2.19
|
||||||
svelte-check:
|
svelte-check:
|
||||||
specifier: ^3.6.0
|
specifier: ^3.6.0
|
||||||
version: 3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.41))(postcss@8.4.41)(svelte@4.2.19)
|
version: 3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44))(postcss@8.4.44)(svelte@4.2.19)
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.5.4
|
version: 5.5.4
|
||||||
@@ -392,8 +392,8 @@ importers:
|
|||||||
specifier: ^3.5.0
|
specifier: ^3.5.0
|
||||||
version: 3.5.0
|
version: 3.5.0
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: ^0.0.4
|
specifier: workspace:0.0.8-beta.5
|
||||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4))
|
version: link:../packages/better-auth
|
||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0
|
version: 0.7.0
|
||||||
@@ -662,7 +662,7 @@ importers:
|
|||||||
version: 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
version: 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
||||||
'@nanostores/vue':
|
'@nanostores/vue':
|
||||||
specifier: ^0.10.0
|
specifier: ^0.10.0
|
||||||
version: 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.4.38(typescript@5.6.0-beta))
|
version: 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
'@noble/ciphers':
|
'@noble/ciphers':
|
||||||
specifier: ^0.6.0
|
specifier: ^0.6.0
|
||||||
version: 0.6.0
|
version: 0.6.0
|
||||||
@@ -780,7 +780,7 @@ importers:
|
|||||||
version: 2.2.5(react@18.3.1)
|
version: 2.2.5(react@18.3.1)
|
||||||
tsup:
|
tsup:
|
||||||
specifier: ^8.2.4
|
specifier: ^8.2.4
|
||||||
version: 8.2.4(jiti@1.21.6)(postcss@8.4.41)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0)
|
version: 8.2.4(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0)
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 5.6.0-beta
|
specifier: 5.6.0-beta
|
||||||
version: 5.6.0-beta
|
version: 5.6.0-beta
|
||||||
@@ -3647,15 +3647,27 @@ packages:
|
|||||||
'@vue/compiler-core@3.4.38':
|
'@vue/compiler-core@3.4.38':
|
||||||
resolution: {integrity: sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==}
|
resolution: {integrity: sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==}
|
||||||
|
|
||||||
|
'@vue/compiler-core@3.5.0':
|
||||||
|
resolution: {integrity: sha512-ja7cpqAOfw4tyFAxgBz70Z42miNDeaqTxExTsnXDLomRpqfyCgyvZvFp482fmsElpfvsoMJUsvzULhvxUTW6Iw==}
|
||||||
|
|
||||||
'@vue/compiler-dom@3.4.38':
|
'@vue/compiler-dom@3.4.38':
|
||||||
resolution: {integrity: sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==}
|
resolution: {integrity: sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==}
|
||||||
|
|
||||||
|
'@vue/compiler-dom@3.5.0':
|
||||||
|
resolution: {integrity: sha512-xYjUybWZXl+1R/toDy815i4PbeehL2hThiSGkcpmIOCy2HoYyeeC/gAWK/Y/xsoK+GSw198/T5O31bYuQx5uvQ==}
|
||||||
|
|
||||||
'@vue/compiler-sfc@3.4.38':
|
'@vue/compiler-sfc@3.4.38':
|
||||||
resolution: {integrity: sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==}
|
resolution: {integrity: sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==}
|
||||||
|
|
||||||
|
'@vue/compiler-sfc@3.5.0':
|
||||||
|
resolution: {integrity: sha512-B9DgLtrqok2GLuaFjLlSL15ZG3ZDBiitUH1ecex9guh/ZcA5MCdwuVE6nsfQxktuZY/QY0awJ35/ripIviCQTQ==}
|
||||||
|
|
||||||
'@vue/compiler-ssr@3.4.38':
|
'@vue/compiler-ssr@3.4.38':
|
||||||
resolution: {integrity: sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==}
|
resolution: {integrity: sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==}
|
||||||
|
|
||||||
|
'@vue/compiler-ssr@3.5.0':
|
||||||
|
resolution: {integrity: sha512-E263QZmA1dqRd7c3u/sWTLRMpQOT0aZ8av/L9SoD/v/BVMZaWFHPUUBswS+bzrfvG2suJF8vSLKx6k6ba5SUdA==}
|
||||||
|
|
||||||
'@vue/devtools-api@6.6.3':
|
'@vue/devtools-api@6.6.3':
|
||||||
resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==}
|
resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==}
|
||||||
|
|
||||||
@@ -3668,23 +3680,26 @@ packages:
|
|||||||
'@vue/devtools-shared@7.3.9':
|
'@vue/devtools-shared@7.3.9':
|
||||||
resolution: {integrity: sha512-CdfMRZKXyI8vw+hqOcQIiLihB6Hbbi7WNZGp7LsuH1Qe4aYAFmTaKjSciRZ301oTnwmU/knC/s5OGuV6UNiNoA==}
|
resolution: {integrity: sha512-CdfMRZKXyI8vw+hqOcQIiLihB6Hbbi7WNZGp7LsuH1Qe4aYAFmTaKjSciRZ301oTnwmU/knC/s5OGuV6UNiNoA==}
|
||||||
|
|
||||||
'@vue/reactivity@3.4.38':
|
'@vue/reactivity@3.5.0':
|
||||||
resolution: {integrity: sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==}
|
resolution: {integrity: sha512-Ew3F5riP3B3ZDGjD3ZKb9uZylTTPSqt8hAf4sGbvbjrjDjrFb3Jm15Tk1/w7WwTE5GbQ2Qhwxx1moc9hr8A/OQ==}
|
||||||
|
|
||||||
'@vue/runtime-core@3.4.38':
|
'@vue/runtime-core@3.5.0':
|
||||||
resolution: {integrity: sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==}
|
resolution: {integrity: sha512-mQyW0F9FaNRdt8ghkAs+BMG3iQ7LGgWKOpkzUzR5AI5swPNydHGL5hvVTqFaeMzwecF1g0c86H4yFQsSxJhH1w==}
|
||||||
|
|
||||||
'@vue/runtime-dom@3.4.38':
|
'@vue/runtime-dom@3.5.0':
|
||||||
resolution: {integrity: sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==}
|
resolution: {integrity: sha512-NQQXjpdXgyYVJ2M56FJ+lSJgZiecgQ2HhxhnQBN95FymXegRNY/N2htI7vOTwpP75pfxhIeYOJ8mE8sW8KAW6A==}
|
||||||
|
|
||||||
'@vue/server-renderer@3.4.38':
|
'@vue/server-renderer@3.5.0':
|
||||||
resolution: {integrity: sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==}
|
resolution: {integrity: sha512-HyDIFUg+l7L4PKrEnJlCYWHUOlm6NxZhmSxIefZ5MTYjkIPfDfkwhX7hqxAQHfgIAE1uLMLQZwuNR/ozI0NhZg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: 3.4.38
|
vue: 3.5.0
|
||||||
|
|
||||||
'@vue/shared@3.4.38':
|
'@vue/shared@3.4.38':
|
||||||
resolution: {integrity: sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==}
|
resolution: {integrity: sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==}
|
||||||
|
|
||||||
|
'@vue/shared@3.5.0':
|
||||||
|
resolution: {integrity: sha512-m9IgiteBpCkFaMNwCOBkFksA7z8QiKc30ooRuoXWUFRDu0mGyNPlFHmbncF0/Kra1RlX8QrmBbRaIxVvikaR0Q==}
|
||||||
|
|
||||||
abbrev@1.1.1:
|
abbrev@1.1.1:
|
||||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||||
|
|
||||||
@@ -6713,6 +6728,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
|
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
postcss@8.4.44:
|
||||||
|
resolution: {integrity: sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
postgres-array@2.0.0:
|
postgres-array@2.0.0:
|
||||||
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
|
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -8156,8 +8175,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.2.0
|
vue: ^3.2.0
|
||||||
|
|
||||||
vue@3.4.38:
|
vue@3.5.0:
|
||||||
resolution: {integrity: sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==}
|
resolution: {integrity: sha512-1t70favYoFijwfWJ7g81aTd32obGaAnKYE9FNyMgnEzn3F4YncRi/kqAHHKloG0VXTD8vBYMhbgLKCA+Sk6QDw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
@@ -9075,17 +9094,17 @@ snapshots:
|
|||||||
nanostores: 0.11.2
|
nanostores: 0.11.2
|
||||||
solid-js: 1.8.21
|
solid-js: 1.8.21
|
||||||
|
|
||||||
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.4.38(typescript@5.5.4))':
|
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.0(typescript@5.5.4))':
|
||||||
dependencies:
|
dependencies:
|
||||||
nanostores: 0.11.2
|
nanostores: 0.11.2
|
||||||
vue: 3.4.38(typescript@5.5.4)
|
vue: 3.5.0(typescript@5.5.4)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vue/devtools-api': 6.6.3
|
'@vue/devtools-api': 6.6.3
|
||||||
|
|
||||||
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.4.38(typescript@5.6.0-beta))':
|
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.0(typescript@5.6.0-beta))':
|
||||||
dependencies:
|
dependencies:
|
||||||
nanostores: 0.11.2
|
nanostores: 0.11.2
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vue/devtools-api': 6.6.3
|
'@vue/devtools-api': 6.6.3
|
||||||
|
|
||||||
@@ -9414,12 +9433,12 @@ snapshots:
|
|||||||
- rollup
|
- rollup
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@nuxt/vite-builder@3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.0-beta)(vue@3.4.38(typescript@5.6.0-beta))':
|
'@nuxt/vite-builder@3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.0-beta)(vue@3.5.0(typescript@5.6.0-beta))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nuxt/kit': 3.13.0(magicast@0.3.5)(rollup@4.21.2)
|
'@nuxt/kit': 3.13.0(magicast@0.3.5)(rollup@4.21.2)
|
||||||
'@rollup/plugin-replace': 5.0.7(rollup@4.21.2)
|
'@rollup/plugin-replace': 5.0.7(rollup@4.21.2)
|
||||||
'@vitejs/plugin-vue': 5.1.3(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.4.38(typescript@5.6.0-beta))
|
'@vitejs/plugin-vue': 5.1.3(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
'@vitejs/plugin-vue-jsx': 4.0.1(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.4.38(typescript@5.6.0-beta))
|
'@vitejs/plugin-vue-jsx': 4.0.1(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
autoprefixer: 10.4.20(postcss@8.4.41)
|
autoprefixer: 10.4.20(postcss@8.4.41)
|
||||||
clear: 0.1.0
|
clear: 0.1.0
|
||||||
consola: 3.2.3
|
consola: 3.2.3
|
||||||
@@ -9448,7 +9467,7 @@ snapshots:
|
|||||||
vite: 5.4.2(@types/node@22.3.0)(terser@5.31.6)
|
vite: 5.4.2(@types/node@22.3.0)(terser@5.31.6)
|
||||||
vite-node: 2.0.5(@types/node@22.3.0)(terser@5.31.6)
|
vite-node: 2.0.5(@types/node@22.3.0)(terser@5.31.6)
|
||||||
vite-plugin-checker: 0.7.2(@biomejs/biome@1.7.3)(eslint@9.9.1)(optionator@0.9.4)(typescript@5.6.0-beta)(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))
|
vite-plugin-checker: 0.7.2(@biomejs/biome@1.7.3)(eslint@9.9.1)(optionator@0.9.4)(typescript@5.6.0-beta)(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
vue-bundle-renderer: 2.1.0
|
vue-bundle-renderer: 2.1.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@biomejs/biome'
|
- '@biomejs/biome'
|
||||||
@@ -11117,13 +11136,13 @@ snapshots:
|
|||||||
'@unhead/schema': 1.10.0
|
'@unhead/schema': 1.10.0
|
||||||
'@unhead/shared': 1.10.0
|
'@unhead/shared': 1.10.0
|
||||||
|
|
||||||
'@unhead/vue@1.10.0(vue@3.4.38(typescript@5.6.0-beta))':
|
'@unhead/vue@1.10.0(vue@3.5.0(typescript@5.6.0-beta))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@unhead/schema': 1.10.0
|
'@unhead/schema': 1.10.0
|
||||||
'@unhead/shared': 1.10.0
|
'@unhead/shared': 1.10.0
|
||||||
hookable: 5.5.3
|
hookable: 5.5.3
|
||||||
unhead: 1.10.0
|
unhead: 1.10.0
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
|
|
||||||
'@vercel/nft@0.26.5':
|
'@vercel/nft@0.26.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -11211,20 +11230,20 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@vitejs/plugin-vue-jsx@4.0.1(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.4.38(typescript@5.6.0-beta))':
|
'@vitejs/plugin-vue-jsx@4.0.1(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.5.0(typescript@5.6.0-beta))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.25.2
|
'@babel/core': 7.25.2
|
||||||
'@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2)
|
'@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2)
|
||||||
'@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2)
|
'@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2)
|
||||||
vite: 5.4.2(@types/node@22.3.0)(terser@5.31.6)
|
vite: 5.4.2(@types/node@22.3.0)(terser@5.31.6)
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@vitejs/plugin-vue@5.1.3(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.4.38(typescript@5.6.0-beta))':
|
'@vitejs/plugin-vue@5.1.3(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))(vue@3.5.0(typescript@5.6.0-beta))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 5.4.2(@types/node@22.3.0)(terser@5.31.6)
|
vite: 5.4.2(@types/node@22.3.0)(terser@5.31.6)
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
|
|
||||||
'@vitest/expect@1.6.0':
|
'@vitest/expect@1.6.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -11255,7 +11274,7 @@ snapshots:
|
|||||||
loupe: 2.3.7
|
loupe: 2.3.7
|
||||||
pretty-format: 29.7.0
|
pretty-format: 29.7.0
|
||||||
|
|
||||||
'@vue-macros/common@1.12.2(rollup@4.21.2)(vue@3.4.38(typescript@5.6.0-beta))':
|
'@vue-macros/common@1.12.2(rollup@4.21.2)(vue@3.5.0(typescript@5.6.0-beta))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.25.6
|
'@babel/types': 7.25.6
|
||||||
'@rollup/pluginutils': 5.1.0(rollup@4.21.2)
|
'@rollup/pluginutils': 5.1.0(rollup@4.21.2)
|
||||||
@@ -11264,7 +11283,7 @@ snapshots:
|
|||||||
local-pkg: 0.5.0
|
local-pkg: 0.5.0
|
||||||
magic-string-ast: 0.6.2
|
magic-string-ast: 0.6.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
|
|
||||||
@@ -11305,11 +11324,24 @@ snapshots:
|
|||||||
estree-walker: 2.0.2
|
estree-walker: 2.0.2
|
||||||
source-map-js: 1.2.0
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
|
'@vue/compiler-core@3.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@babel/parser': 7.25.6
|
||||||
|
'@vue/shared': 3.5.0
|
||||||
|
entities: 4.5.0
|
||||||
|
estree-walker: 2.0.2
|
||||||
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
'@vue/compiler-dom@3.4.38':
|
'@vue/compiler-dom@3.4.38':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-core': 3.4.38
|
'@vue/compiler-core': 3.4.38
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.4.38
|
||||||
|
|
||||||
|
'@vue/compiler-dom@3.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@vue/compiler-core': 3.5.0
|
||||||
|
'@vue/shared': 3.5.0
|
||||||
|
|
||||||
'@vue/compiler-sfc@3.4.38':
|
'@vue/compiler-sfc@3.4.38':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/parser': 7.25.6
|
'@babel/parser': 7.25.6
|
||||||
@@ -11322,11 +11354,28 @@ snapshots:
|
|||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
source-map-js: 1.2.0
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
|
'@vue/compiler-sfc@3.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@babel/parser': 7.25.6
|
||||||
|
'@vue/compiler-core': 3.5.0
|
||||||
|
'@vue/compiler-dom': 3.5.0
|
||||||
|
'@vue/compiler-ssr': 3.5.0
|
||||||
|
'@vue/shared': 3.5.0
|
||||||
|
estree-walker: 2.0.2
|
||||||
|
magic-string: 0.30.11
|
||||||
|
postcss: 8.4.44
|
||||||
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
'@vue/compiler-ssr@3.4.38':
|
'@vue/compiler-ssr@3.4.38':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-dom': 3.4.38
|
'@vue/compiler-dom': 3.4.38
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.4.38
|
||||||
|
|
||||||
|
'@vue/compiler-ssr@3.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@vue/compiler-dom': 3.5.0
|
||||||
|
'@vue/shared': 3.5.0
|
||||||
|
|
||||||
'@vue/devtools-api@6.6.3': {}
|
'@vue/devtools-api@6.6.3': {}
|
||||||
|
|
||||||
'@vue/devtools-core@7.3.3(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))':
|
'@vue/devtools-core@7.3.3(vite@5.4.2(@types/node@22.3.0)(terser@5.31.6))':
|
||||||
@@ -11354,36 +11403,38 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
rfdc: 1.4.1
|
rfdc: 1.4.1
|
||||||
|
|
||||||
'@vue/reactivity@3.4.38':
|
'@vue/reactivity@3.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.5.0
|
||||||
|
|
||||||
'@vue/runtime-core@3.4.38':
|
'@vue/runtime-core@3.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/reactivity': 3.4.38
|
'@vue/reactivity': 3.5.0
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.5.0
|
||||||
|
|
||||||
'@vue/runtime-dom@3.4.38':
|
'@vue/runtime-dom@3.5.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/reactivity': 3.4.38
|
'@vue/reactivity': 3.5.0
|
||||||
'@vue/runtime-core': 3.4.38
|
'@vue/runtime-core': 3.5.0
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.5.0
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
|
|
||||||
'@vue/server-renderer@3.4.38(vue@3.4.38(typescript@5.5.4))':
|
'@vue/server-renderer@3.5.0(vue@3.5.0(typescript@5.5.4))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-ssr': 3.4.38
|
'@vue/compiler-ssr': 3.5.0
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.5.0
|
||||||
vue: 3.4.38(typescript@5.5.4)
|
vue: 3.5.0(typescript@5.5.4)
|
||||||
|
|
||||||
'@vue/server-renderer@3.4.38(vue@3.4.38(typescript@5.6.0-beta))':
|
'@vue/server-renderer@3.5.0(vue@3.5.0(typescript@5.6.0-beta))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-ssr': 3.4.38
|
'@vue/compiler-ssr': 3.5.0
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.5.0
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
|
|
||||||
'@vue/shared@3.4.38': {}
|
'@vue/shared@3.4.38': {}
|
||||||
|
|
||||||
|
'@vue/shared@3.5.0': {}
|
||||||
|
|
||||||
abbrev@1.1.1: {}
|
abbrev@1.1.1: {}
|
||||||
|
|
||||||
abort-controller@3.0.0:
|
abort-controller@3.0.0:
|
||||||
@@ -11582,7 +11633,7 @@ snapshots:
|
|||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.4.38(typescript@5.5.4)):
|
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.0(typescript@5.5.4)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@better-fetch/fetch': 1.1.4
|
'@better-fetch/fetch': 1.1.4
|
||||||
'@better-fetch/logger': 1.1.3
|
'@better-fetch/logger': 1.1.3
|
||||||
@@ -11590,7 +11641,7 @@ snapshots:
|
|||||||
'@nanostores/query': 0.3.4(nanostores@0.11.2)
|
'@nanostores/query': 0.3.4(nanostores@0.11.2)
|
||||||
'@nanostores/react': 0.7.3(nanostores@0.11.2)(react@18.3.1)
|
'@nanostores/react': 0.7.3(nanostores@0.11.2)(react@18.3.1)
|
||||||
'@nanostores/solid': 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
'@nanostores/solid': 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
||||||
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.4.38(typescript@5.5.4))
|
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.0(typescript@5.5.4))
|
||||||
'@noble/ciphers': 0.6.0
|
'@noble/ciphers': 0.6.0
|
||||||
'@noble/hashes': 1.4.0
|
'@noble/hashes': 1.4.0
|
||||||
'@paralleldrive/cuid2': 2.2.2
|
'@paralleldrive/cuid2': 2.2.2
|
||||||
@@ -11625,7 +11676,7 @@ snapshots:
|
|||||||
- typescript
|
- typescript
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.4.38(typescript@5.6.0-beta)):
|
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@18.3.1)(solid-js@1.8.21)(typescript@5.6.0-beta)(vue@3.5.0(typescript@5.6.0-beta)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@better-fetch/fetch': 1.1.4
|
'@better-fetch/fetch': 1.1.4
|
||||||
'@better-fetch/logger': 1.1.3
|
'@better-fetch/logger': 1.1.3
|
||||||
@@ -11633,7 +11684,7 @@ snapshots:
|
|||||||
'@nanostores/query': 0.3.4(nanostores@0.11.2)
|
'@nanostores/query': 0.3.4(nanostores@0.11.2)
|
||||||
'@nanostores/react': 0.7.3(nanostores@0.11.2)(react@18.3.1)
|
'@nanostores/react': 0.7.3(nanostores@0.11.2)(react@18.3.1)
|
||||||
'@nanostores/solid': 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
'@nanostores/solid': 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
||||||
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.4.38(typescript@5.6.0-beta))
|
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
'@noble/ciphers': 0.6.0
|
'@noble/ciphers': 0.6.0
|
||||||
'@noble/hashes': 1.4.0
|
'@noble/hashes': 1.4.0
|
||||||
'@paralleldrive/cuid2': 2.2.2
|
'@paralleldrive/cuid2': 2.2.2
|
||||||
@@ -14670,10 +14721,10 @@ snapshots:
|
|||||||
'@nuxt/kit': 3.13.0(magicast@0.3.5)(rollup@4.21.2)
|
'@nuxt/kit': 3.13.0(magicast@0.3.5)(rollup@4.21.2)
|
||||||
'@nuxt/schema': 3.13.0(rollup@4.21.2)
|
'@nuxt/schema': 3.13.0(rollup@4.21.2)
|
||||||
'@nuxt/telemetry': 2.5.4(magicast@0.3.5)(rollup@4.21.2)
|
'@nuxt/telemetry': 2.5.4(magicast@0.3.5)(rollup@4.21.2)
|
||||||
'@nuxt/vite-builder': 3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.0-beta)(vue@3.4.38(typescript@5.6.0-beta))
|
'@nuxt/vite-builder': 3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.0-beta)(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
'@unhead/dom': 1.10.0
|
'@unhead/dom': 1.10.0
|
||||||
'@unhead/ssr': 1.10.0
|
'@unhead/ssr': 1.10.0
|
||||||
'@unhead/vue': 1.10.0(vue@3.4.38(typescript@5.6.0-beta))
|
'@unhead/vue': 1.10.0(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.4.38
|
||||||
acorn: 8.12.1
|
acorn: 8.12.1
|
||||||
c12: 1.11.1(magicast@0.3.5)
|
c12: 1.11.1(magicast@0.3.5)
|
||||||
@@ -14717,13 +14768,13 @@ snapshots:
|
|||||||
unenv: 1.10.0
|
unenv: 1.10.0
|
||||||
unimport: 3.11.1(rollup@4.21.2)
|
unimport: 3.11.1(rollup@4.21.2)
|
||||||
unplugin: 1.12.2
|
unplugin: 1.12.2
|
||||||
unplugin-vue-router: 0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.4.38(typescript@5.6.0-beta)))(vue@3.4.38(typescript@5.6.0-beta))
|
unplugin-vue-router: 0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.5.0(typescript@5.6.0-beta)))(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
unstorage: 1.10.2(ioredis@5.4.1)
|
unstorage: 1.10.2(ioredis@5.4.1)
|
||||||
untyped: 1.4.2
|
untyped: 1.4.2
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
vue-bundle-renderer: 2.1.0
|
vue-bundle-renderer: 2.1.0
|
||||||
vue-devtools-stub: 0.1.0
|
vue-devtools-stub: 0.1.0
|
||||||
vue-router: 4.4.3(vue@3.4.38(typescript@5.6.0-beta))
|
vue-router: 4.4.3(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@parcel/watcher': 2.4.1
|
'@parcel/watcher': 2.4.1
|
||||||
'@types/node': 22.3.0
|
'@types/node': 22.3.0
|
||||||
@@ -15087,12 +15138,20 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
|
|
||||||
postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.41)(tsx@4.19.0)(yaml@2.5.0):
|
postcss-load-config@4.0.2(postcss@8.4.44):
|
||||||
|
dependencies:
|
||||||
|
lilconfig: 3.1.2
|
||||||
|
yaml: 2.5.0
|
||||||
|
optionalDependencies:
|
||||||
|
postcss: 8.4.44
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(yaml@2.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 3.1.2
|
lilconfig: 3.1.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
jiti: 1.21.6
|
jiti: 1.21.6
|
||||||
postcss: 8.4.41
|
postcss: 8.4.44
|
||||||
tsx: 4.19.0
|
tsx: 4.19.0
|
||||||
yaml: 2.5.0
|
yaml: 2.5.0
|
||||||
|
|
||||||
@@ -15248,6 +15307,12 @@ snapshots:
|
|||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
source-map-js: 1.2.0
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
|
postcss@8.4.44:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.7
|
||||||
|
picocolors: 1.0.1
|
||||||
|
source-map-js: 1.2.0
|
||||||
|
|
||||||
postgres-array@2.0.0: {}
|
postgres-array@2.0.0: {}
|
||||||
|
|
||||||
postgres-array@3.0.2: {}
|
postgres-array@3.0.2: {}
|
||||||
@@ -16012,14 +16077,14 @@ snapshots:
|
|||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0: {}
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
svelte-check@3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.41))(postcss@8.4.41)(svelte@4.2.19):
|
svelte-check@3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44))(postcss@8.4.44)(svelte@4.2.19):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.25
|
'@jridgewell/trace-mapping': 0.3.25
|
||||||
chokidar: 3.6.0
|
chokidar: 3.6.0
|
||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
sade: 1.8.1
|
sade: 1.8.1
|
||||||
svelte: 4.2.19
|
svelte: 4.2.19
|
||||||
svelte-preprocess: 5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.41))(postcss@8.4.41)(svelte@4.2.19)(typescript@5.5.4)
|
svelte-preprocess: 5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44))(postcss@8.4.44)(svelte@4.2.19)(typescript@5.5.4)
|
||||||
typescript: 5.5.4
|
typescript: 5.5.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
@@ -16036,7 +16101,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
svelte: 4.2.19
|
svelte: 4.2.19
|
||||||
|
|
||||||
svelte-preprocess@5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.41))(postcss@8.4.41)(svelte@4.2.19)(typescript@5.5.4):
|
svelte-preprocess@5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44))(postcss@8.4.44)(svelte@4.2.19)(typescript@5.5.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/pug': 2.0.10
|
'@types/pug': 2.0.10
|
||||||
detect-indent: 6.1.0
|
detect-indent: 6.1.0
|
||||||
@@ -16046,8 +16111,8 @@ snapshots:
|
|||||||
svelte: 4.2.19
|
svelte: 4.2.19
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@babel/core': 7.25.2
|
'@babel/core': 7.25.2
|
||||||
postcss: 8.4.41
|
postcss: 8.4.44
|
||||||
postcss-load-config: 4.0.2(postcss@8.4.41)
|
postcss-load-config: 4.0.2(postcss@8.4.44)
|
||||||
typescript: 5.5.4
|
typescript: 5.5.4
|
||||||
|
|
||||||
svelte@4.2.19:
|
svelte@4.2.19:
|
||||||
@@ -16270,7 +16335,7 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.6.3: {}
|
tslib@2.6.3: {}
|
||||||
|
|
||||||
tsup@8.2.4(jiti@1.21.6)(postcss@8.4.41)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0):
|
tsup@8.2.4(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
bundle-require: 5.0.0(esbuild@0.23.1)
|
bundle-require: 5.0.0(esbuild@0.23.1)
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
@@ -16282,14 +16347,14 @@ snapshots:
|
|||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
joycon: 3.1.1
|
joycon: 3.1.1
|
||||||
picocolors: 1.0.1
|
picocolors: 1.0.1
|
||||||
postcss-load-config: 6.0.1(jiti@1.21.6)(postcss@8.4.41)(tsx@4.19.0)(yaml@2.5.0)
|
postcss-load-config: 6.0.1(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(yaml@2.5.0)
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
rollup: 4.21.2
|
rollup: 4.21.2
|
||||||
source-map: 0.8.0-beta.0
|
source-map: 0.8.0-beta.0
|
||||||
sucrase: 3.35.0
|
sucrase: 3.35.0
|
||||||
tree-kill: 1.2.2
|
tree-kill: 1.2.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postcss: 8.4.41
|
postcss: 8.4.44
|
||||||
typescript: 5.6.0-beta
|
typescript: 5.6.0-beta
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- jiti
|
- jiti
|
||||||
@@ -16483,11 +16548,11 @@ snapshots:
|
|||||||
|
|
||||||
universalify@2.0.1: {}
|
universalify@2.0.1: {}
|
||||||
|
|
||||||
unplugin-vue-router@0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.4.38(typescript@5.6.0-beta)))(vue@3.4.38(typescript@5.6.0-beta)):
|
unplugin-vue-router@0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.5.0(typescript@5.6.0-beta)))(vue@3.5.0(typescript@5.6.0-beta)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.25.6
|
'@babel/types': 7.25.6
|
||||||
'@rollup/pluginutils': 5.1.0(rollup@4.21.2)
|
'@rollup/pluginutils': 5.1.0(rollup@4.21.2)
|
||||||
'@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.4.38(typescript@5.6.0-beta))
|
'@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
ast-walker-scope: 0.6.2
|
ast-walker-scope: 0.6.2
|
||||||
chokidar: 3.6.0
|
chokidar: 3.6.0
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
@@ -16500,7 +16565,7 @@ snapshots:
|
|||||||
unplugin: 1.12.2
|
unplugin: 1.12.2
|
||||||
yaml: 2.5.0
|
yaml: 2.5.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vue-router: 4.4.3(vue@3.4.38(typescript@5.6.0-beta))
|
vue-router: 4.4.3(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
- vue
|
- vue
|
||||||
@@ -16914,28 +16979,28 @@ snapshots:
|
|||||||
|
|
||||||
vue-devtools-stub@0.1.0: {}
|
vue-devtools-stub@0.1.0: {}
|
||||||
|
|
||||||
vue-router@4.4.3(vue@3.4.38(typescript@5.6.0-beta)):
|
vue-router@4.4.3(vue@3.5.0(typescript@5.6.0-beta)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/devtools-api': 6.6.3
|
'@vue/devtools-api': 6.6.3
|
||||||
vue: 3.4.38(typescript@5.6.0-beta)
|
vue: 3.5.0(typescript@5.6.0-beta)
|
||||||
|
|
||||||
vue@3.4.38(typescript@5.5.4):
|
vue@3.5.0(typescript@5.5.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-dom': 3.4.38
|
'@vue/compiler-dom': 3.5.0
|
||||||
'@vue/compiler-sfc': 3.4.38
|
'@vue/compiler-sfc': 3.5.0
|
||||||
'@vue/runtime-dom': 3.4.38
|
'@vue/runtime-dom': 3.5.0
|
||||||
'@vue/server-renderer': 3.4.38(vue@3.4.38(typescript@5.5.4))
|
'@vue/server-renderer': 3.5.0(vue@3.5.0(typescript@5.5.4))
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.5.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.5.4
|
typescript: 5.5.4
|
||||||
|
|
||||||
vue@3.4.38(typescript@5.6.0-beta):
|
vue@3.5.0(typescript@5.6.0-beta):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-dom': 3.4.38
|
'@vue/compiler-dom': 3.5.0
|
||||||
'@vue/compiler-sfc': 3.4.38
|
'@vue/compiler-sfc': 3.5.0
|
||||||
'@vue/runtime-dom': 3.4.38
|
'@vue/runtime-dom': 3.5.0
|
||||||
'@vue/server-renderer': 3.4.38(vue@3.4.38(typescript@5.6.0-beta))
|
'@vue/server-renderer': 3.5.0(vue@3.5.0(typescript@5.6.0-beta))
|
||||||
'@vue/shared': 3.4.38
|
'@vue/shared': 3.5.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.6.0-beta
|
typescript: 5.6.0-beta
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user