+ );
+};
+
+
+
+export const CircleIcon = ({
+ className,
+ delay,
+}: {
+ className?: string;
+ delay?: number;
+}) => {
+ return (
+
+ );
+};
diff --git a/docs/components/ui/sparkles.tsx b/docs/components/ui/sparkles.tsx
new file mode 100644
index 0000000000..903483b27b
--- /dev/null
+++ b/docs/components/ui/sparkles.tsx
@@ -0,0 +1,435 @@
+"use client";
+import React, { useId, useMemo } from "react";
+import { useEffect, useState } from "react";
+import Particles, { initParticlesEngine } from "@tsparticles/react";
+import type { Container, SingleOrMultiple } from "@tsparticles/engine";
+import { loadSlim } from "@tsparticles/slim";
+import { cn } from "@/lib/utils";
+import { motion, useAnimation } from "framer-motion";
+
+type ParticlesProps = {
+ id?: string;
+ className?: string;
+ background?: string;
+ particleSize?: number;
+ minSize?: number;
+ maxSize?: number;
+ speed?: number;
+ particleColor?: string;
+ particleDensity?: number;
+};
+export const SparklesCore = (props: ParticlesProps) => {
+ const {
+ id,
+ className,
+ background,
+ minSize,
+ maxSize,
+ speed,
+ particleColor,
+ particleDensity,
+ } = props;
+ const [init, setInit] = useState(false);
+ useEffect(() => {
+ initParticlesEngine(async (engine) => {
+ await loadSlim(engine);
+ }).then(() => {
+ setInit(true);
+ });
+ }, []);
+ const controls = useAnimation();
+
+ const particlesLoaded = async (container?: Container) => {
+ if (container) {
+ console.log(container);
+ controls.start({
+ opacity: 1,
+ transition: {
+ duration: 1,
+ },
+ });
+ }
+ };
+
+ const generatedId = useId();
+ return (
+
+ {init && (
+ | undefined,
+ },
+ groups: {},
+ move: {
+ angle: {
+ offset: 0,
+ value: 90,
+ },
+ attract: {
+ distance: 200,
+ enable: false,
+ rotate: {
+ x: 3000,
+ y: 3000,
+ },
+ },
+ center: {
+ x: 50,
+ y: 50,
+ mode: "percent",
+ radius: 0,
+ },
+ decay: 0,
+ distance: {},
+ direction: "none",
+ drift: 0,
+ enable: true,
+ gravity: {
+ acceleration: 9.81,
+ enable: false,
+ inverse: false,
+ maxSpeed: 50,
+ },
+ path: {
+ clamp: true,
+ delay: {
+ value: 0,
+ },
+ enable: false,
+ options: {},
+ },
+ outModes: {
+ default: "out",
+ },
+ random: false,
+ size: false,
+ speed: {
+ min: 0.1,
+ max: 1,
+ },
+ spin: {
+ acceleration: 0,
+ enable: false,
+ },
+ straight: false,
+ trail: {
+ enable: false,
+ length: 10,
+ fill: {},
+ },
+ vibrate: false,
+ warp: false,
+ },
+ number: {
+ density: {
+ enable: true,
+ width: 400,
+ height: 400,
+ },
+ limit: {
+ mode: "delete",
+ value: 0,
+ },
+ value: particleDensity || 120,
+ },
+ opacity: {
+ value: {
+ min: 0.1,
+ max: 1,
+ },
+ animation: {
+ count: 0,
+ enable: true,
+ speed: speed || 4,
+ decay: 0,
+ delay: 0,
+ sync: false,
+ mode: "auto",
+ startValue: "random",
+ destroy: "none",
+ },
+ },
+ reduceDuplicates: false,
+ shadow: {
+ blur: 0,
+ color: {
+ value: "#000",
+ },
+ enable: false,
+ offset: {
+ x: 0,
+ y: 0,
+ },
+ },
+ shape: {
+ close: true,
+ fill: true,
+ options: {},
+ type: "circle",
+ },
+ size: {
+ value: {
+ min: minSize || 1,
+ max: maxSize || 3,
+ },
+ animation: {
+ count: 0,
+ enable: false,
+ speed: 5,
+ decay: 0,
+ delay: 0,
+ sync: false,
+ mode: "auto",
+ startValue: "random",
+ destroy: "none",
+ },
+ },
+ stroke: {
+ width: 0,
+ },
+ zIndex: {
+ value: 0,
+ opacityRate: 1,
+ sizeRate: 1,
+ velocityRate: 1,
+ },
+ destroy: {
+ bounds: {},
+ mode: "none",
+ split: {
+ count: 1,
+ factor: {
+ value: 3,
+ },
+ rate: {
+ value: {
+ min: 4,
+ max: 9,
+ },
+ },
+ sizeOffset: true,
+ },
+ },
+ roll: {
+ darken: {
+ enable: false,
+ value: 0,
+ },
+ enable: false,
+ enlighten: {
+ enable: false,
+ value: 0,
+ },
+ mode: "vertical",
+ speed: 25,
+ },
+ tilt: {
+ value: 0,
+ animation: {
+ enable: false,
+ speed: 0,
+ decay: 0,
+ sync: false,
+ },
+ direction: "clockwise",
+ enable: false,
+ },
+ twinkle: {
+ lines: {
+ enable: false,
+ frequency: 0.05,
+ opacity: 1,
+ },
+ particles: {
+ enable: false,
+ frequency: 0.05,
+ opacity: 1,
+ },
+ },
+ wobble: {
+ distance: 5,
+ enable: false,
+ speed: {
+ angle: 50,
+ move: 10,
+ },
+ },
+ life: {
+ count: 0,
+ delay: {
+ value: 0,
+ sync: false,
+ },
+ duration: {
+ value: 0,
+ sync: false,
+ },
+ },
+ rotate: {
+ value: 0,
+ animation: {
+ enable: false,
+ speed: 0,
+ decay: 0,
+ sync: false,
+ },
+ direction: "clockwise",
+ path: false,
+ },
+ orbit: {
+ animation: {
+ count: 0,
+ enable: false,
+ speed: 1,
+ decay: 0,
+ delay: 0,
+ sync: false,
+ },
+ enable: false,
+ opacity: 1,
+ rotation: {
+ value: 45,
+ },
+ width: 1,
+ },
+ links: {
+ blink: false,
+ color: {
+ value: "#fff",
+ },
+ consent: false,
+ distance: 100,
+ enable: false,
+ frequency: 1,
+ opacity: 1,
+ shadow: {
+ blur: 5,
+ color: {
+ value: "#000",
+ },
+ enable: false,
+ },
+ triangles: {
+ enable: false,
+ frequency: 1,
+ },
+ width: 1,
+ warp: false,
+ },
+ repulse: {
+ value: 0,
+ enabled: false,
+ distance: 1,
+ duration: 1,
+ factor: 1,
+ speed: 1,
+ },
+ },
+ detectRetina: true,
+ }}
+ />
+ )}
+
+ );
+};
diff --git a/docs/content/docs/integrations/hono.mdx b/docs/content/docs/integrations/hono.mdx
new file mode 100644
index 0000000000..994122d33d
--- /dev/null
+++ b/docs/content/docs/integrations/hono.mdx
@@ -0,0 +1,73 @@
+---
+title: Hono
+description: Hono Integration Guide
+---
+
+This integration guide is assuming you are using Hono with node server.
+
+## Installation
+
+First, install Better Auth
+
+```package-install
+npm install better-auth
+```
+
+## Set Environment Variables
+
+Create a `.env` file in the root of your project and add the following environment variables:
+
+**Set Base URL**
+```txt title=".env"
+BETTER_AUTH_URL=http://localhost:3000 # Base URL of your Next.js app
+```
+
+**Set Secret**
+
+Random value used by the library for encryption and generating hashes. You can generate one using the button below or you can use something like openssl.
+```txt title=".env"
+BETTER_AUTH_SECRET=
+```
+
+
+## Configure Server
+
+### Create Better Auth instance
+
+We recommend to create `auth.ts` file inside your `lib/` directory. This file will contain your Better Auth instance.
+
+```ts twoslash title="auth.ts"
+import { betterAuth } from "better-auth"
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: "sqlite", //change this to your database provider
+ url: "./db.sqlite", // path to your database or connection string
+ }
+ // Refer to the api documentation for more configuration options
+})
+```
+
+
+Better Auth currently supports only SQLite, MySQL, and PostgreSQL. It uses Kysely under the hood, so you can also pass any Kysely dialect directly to the database object.
+
+
+### Mount the handler
+
+We need to mount the handler to hono endpoint.
+
+```ts
+import { Hono } from "hono";
+import { auth } from "./auth";
+import { serve } from "@hono/node-server";
+import { cors } from "hono/cors";
+
+const app = new Hono();
+
+app.on(["POST", "GET"], "/api/auth/**", (c) => {
+ return auth.handler(c.req.raw);
+});
+
+serve(app);
+```
+
diff --git a/docs/content/docs/integrations/next.mdx b/docs/content/docs/integrations/next.mdx
new file mode 100644
index 0000000000..308a92bd57
--- /dev/null
+++ b/docs/content/docs/integrations/next.mdx
@@ -0,0 +1,157 @@
+---
+title: Next JS integration
+description: Learn how to integrate Better Auth with Next.js
+---
+
+Better Auth can be easily integrated with Next.js. It'll also comes with utilities to make it easier to use Better Auth with Next.js.
+
+## Installation
+
+First, install Better Auth
+
+```package-install
+npm install better-auth
+```
+
+## Set Environment Variables
+
+Create a `.env` file in the root of your project and add the following environment variables:
+
+**Set Base URL**
+```txt title=".env"
+BETTER_AUTH_URL=http://localhost:3000 # Base URL of your Next.js app
+```
+
+**Set Secret**
+
+Random value used by the library for encryption and generating hashes. You can generate one using the button below or you can use something like openssl.
+```txt title=".env"
+BETTER_AUTH_SECRET=
+```
+
+
+## Configure Server
+
+### Create Better Auth instance
+
+We recommend to create `auth.ts` file inside your `lib/` directory. This file will contain your Better Auth instance.
+
+```ts twoslash title="auth.ts"
+import { betterAuth } from "better-auth"
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: "sqlite", //change this to your database provider
+ url: "./db.sqlite", // path to your database or connection string
+ }
+ // Refer to the api documentation for more configuration options
+})
+```
+
+
+Better Auth currently supports only SQLite, MySQL, and PostgreSQL. It uses Kysely under the hood, so you can also pass any Kysely dialect directly to the database object.
+
+
+### Create API Route
+
+We need to mount the handler to an API route. Create a route file inside `/api/[...auth]` directory. And add the following code:
+
+```ts twoslash title="api/[...auth]/route.ts"
+//@filename: @/lib/auth.ts
+import { betterAuth } from "better-auth"
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: "sqlite", //change this to your database provider
+ url: "./db.sqlite", // path to your database or connection string
+ }
+ // Refer to the api documentation for more configuration options
+})
+// ---cut---
+//@filename: api/[...auth]/route.ts
+//---cut---
+import { handler } from "@/lib/auth";
+import { toNextJsHandler } from "better-auth/next-js";
+
+export const { GET, POST } = toNextJsHandler(handler);
+```
+
+
+ You can change the path on your better-auth configuration but it's recommended to keep it as `/api/[...auth]`
+
+
+### Migrate the database
+Run the following command to create the necessary tables in your database:
+
+```bash
+npx better-auth migrate
+```
+
+## Create a client
+
+Create a client instance. You can name the file anything you want. Here we are creating `client.ts` file inside the `lib/` directory.
+
+```ts twoslash title="client.ts"
+import { createAuthClient } from "better-auth/react" // make sure to import from better-auth/react
+
+export const client = createAuthClient({
+ //you can pass client configuration here
+})
+```
+
+Once you have created the client, you can use it to sign up, sign in, and perform other actions.
+Some of the actinos are reactive. The client use [nano-store](https://github.com/nanostores/nanostores) to store the state and re-render the components when the state changes.
+
+The client also uses [better-fetch](https://github.com/bekacru/better-fetch) to make the requests. You can pass the fetch configuration to the client.
+
+## RSC and Server actions
+
+The `api` object exported from the auth instance contains all the actions that you can perform on the server. Every endpoint made inside better auth is a invokable as a function. Including plugins endpoints.
+
+**Example: Getting Session on a server action**
+
+```tsx twoslash title="server.ts"
+//@filename: @/lib/auth.ts
+import { betterAuth } from "better-auth"
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: "sqlite", //change this to your database provider
+ url: "./db.sqlite", // path to your database or connection string
+ }
+ // Refer to the api documentation for more configuration options
+})
+// ---cut---
+//@filename: server.ts
+//---cut---
+import { api } from "@/lib/auth"
+import { headers } from "next/headers"
+
+const someAuthenticatedAction = async () => {
+ "use server";
+ const session = await api.getSession({
+ headers: headers()
+ })
+};
+```
+
+**Example: Getting Session on a RSC**
+
+```tsx
+import { api } from "@/lib/auth"
+import { headers } from "next/headers"
+
+export async function ServerComponent() {
+ const session = await api.getSession({
+ headers: headers()
+ })
+ if(!session) {
+ return
Not authenticated
+ }
+ return (
+
+
Welcome {session.user.name}
+
+ )
+}
+```
\ No newline at end of file
diff --git a/docs/content/docs/integrations/nuxt.mdx b/docs/content/docs/integrations/nuxt.mdx
new file mode 100644
index 0000000000..32c8fc48fa
--- /dev/null
+++ b/docs/content/docs/integrations/nuxt.mdx
@@ -0,0 +1,111 @@
+---
+title: Nuxt.js
+description: Learn how to integrate Better Auth with Nuxt.js
+---
+
+
+## Installation
+
+First, install Better Auth
+
+```package-install
+npm install better-auth
+```
+
+## Set Environment Variables
+
+Create a `.env` file in the root of your project and add the following environment variables:
+
+**Set Base URL**
+```txt title=".env"
+BETTER_AUTH_URL=http://localhost:3000 # Base URL of your Next.js app
+```
+
+**Set Secret**
+
+Random value used by the library for encryption and generating hashes. You can generate one using the button below or you can use something like openssl.
+```txt title=".env"
+BETTER_AUTH_SECRET=
+```
+
+
+
+## Configure Server
+
+### Create Better Auth instance
+
+We recommend to create `auth.ts` file inside your `lib/` directory. This file will contain your Better Auth instance.
+
+```ts twoslash title="auth.ts"
+import { betterAuth } from "better-auth"
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: "sqlite", //change this to your database provider
+ url: "./db.sqlite", // path to your database or connection string
+ }
+ // Refer to the api documentation for more configuration options
+})
+```
+
+
+Better Auth currently supports only SQLite, MySQL, and PostgreSQL. It uses Kysely under the hood, so you can also pass any Kysely dialect directly to the database object.
+
+
+### Create API Route
+
+We need to mount the handler to an API route. Create a file inside `/server/api` called `[...auth].ts` and add the following code:
+
+```ts title="server/api/[...auth].ts"
+import { handler } from "~/utils/auth.config";
+
+export default defineEventHandler((event) => {
+ return handler(toWebRequest(event));
+});
+```
+
+ You can change the path on your better-auth configuration but it's recommended to keep it as `/api/[...auth]`
+
+
+### Migrate the database
+Run the following command to create the necessary tables in your database:
+
+```bash
+npx better-auth migrate
+```
+
+## Create a client
+
+Create a client instance. You can name the file anything you want. Here we are creating `client.ts` file inside the `lib/` directory.
+
+```ts twoslash title="client.ts"
+import { createAuthClient } from "better-auth/vue" // make sure to import from better-auth/vue
+
+export const client = createAuthClient({
+ //you can pass client configuration here
+})
+```
+
+Once you have created the client, you can use it to sign up, sign in, and perform other actions.
+Some of the actinos are reactive. The client use [nano-store](https://github.com/nanostores/nanostores) to store the state and re-render the components when the state changes.
+
+### Example usage
+
+```vue title="index.vue"
+
+
+
+
+
{{ client.useSession().value }}
+
+
+
+
+```
+
diff --git a/docs/content/docs/integrations/solid-start.mdx b/docs/content/docs/integrations/solid-start.mdx
new file mode 100644
index 0000000000..08cb313a74
--- /dev/null
+++ b/docs/content/docs/integrations/solid-start.mdx
@@ -0,0 +1,64 @@
+---
+title: Solid Start
+description: Solid Start integratons guide
+---
+
+
+## Installation
+
+First, install Better Auth
+
+```package-install
+npm install better-auth
+```
+
+## Set Environment Variables
+
+Create a `.env` file in the root of your project and add the following environment variables:
+
+**Set Base URL**
+```txt title=".env"
+BETTER_AUTH_URL=http://localhost:3000 # Base URL of your Next.js app
+```
+
+**Set Secret**
+
+Random value used by the library for encryption and generating hashes. You can generate one using the button below or you can use something like openssl.
+```txt title=".env"
+BETTER_AUTH_SECRET=
+```
+
+
+
+## Configure Server
+
+### Create Better Auth instance
+
+We recommend to create `auth.ts` file inside your `lib/` directory. This file will contain your Better Auth instance.
+
+```ts twoslash title="auth.ts"
+import { betterAuth } from "better-auth"
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: "sqlite", //change this to your database provider
+ url: "./db.sqlite", // path to your database or connection string
+ }
+ // Refer to the api documentation for more configuration options
+})
+```
+
+
+Better Auth currently supports only SQLite, MySQL, and PostgreSQL. It uses Kysely under the hood, so you can also pass any Kysely dialect directly to the database object.
+
+
+### Mount the handler
+
+We need to mount the handler to Solid Start server. Put the following code in your `*auth.ts` file inside `/routes/api/auth` folder.
+
+```ts title="*auth.ts"
+import { auth } from "~/lib/auth";
+import { toSolidStartHandler } from "better-auth/solid-start";
+
+export const { GET, POST } = toSolidStartHandler(auth);
+```
\ No newline at end of file
diff --git a/docs/content/docs/integrations/svelte-kit.mdx b/docs/content/docs/integrations/svelte-kit.mdx
new file mode 100644
index 0000000000..d18fde0931
--- /dev/null
+++ b/docs/content/docs/integrations/svelte-kit.mdx
@@ -0,0 +1,148 @@
+---
+title: Svelte Kit
+description: Learn how to integrate Better Auth with Svelte Kit
+---
+
+Better Auth has first class support for Svelte Kit. It provides utilities to make it easier to use Better Auth with Svelte Kit.
+
+## Installation
+
+First, install Better Auth
+
+```package-install
+npm install better-auth
+```
+
+## Set Environment Variables
+
+Create a `.env` file in the root of your project and add the following environment variables:
+
+**Set Base URL**
+```txt title=".env"
+BETTER_AUTH_URL=http://localhost:3000 # Base URL of your Next.js app
+```
+
+**Set Secret**
+
+Random value used by the library for encryption and generating hashes. You can generate one using the button below or you can use something like openssl.
+```txt title=".env"
+BETTER_AUTH_SECRET=
+```
+
+
+
+## Configure Server
+
+### Create Better Auth instance
+
+We recommend to create `auth.ts` file inside your `lib/` directory. This file will contain your Better Auth instance.
+
+```ts twoslash title="auth.ts"
+import { betterAuth } from "better-auth"
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: "sqlite", //change this to your database provider
+ url: "./db.sqlite", // path to your database or connection string
+ }
+ // Refer to the api documentation for more configuration options
+})
+```
+
+
+Better Auth currently supports only SQLite, MySQL, and PostgreSQL. It uses Kysely under the hood, so you can also pass any Kysely dialect directly to the database object.
+
+
+### Mount the handler
+
+We need to mount the handler to svelte kit server hook.
+
+```ts
+import { auth } from "$lib/auth";
+import { svelteKitHandler } from "better-auth/svelte-kit";
+
+export async function handle({ event, resolve }) {
+ return svelteKitHandler({ event, resolve, auth });
+}
+```
+
+### Migrate the database
+Run the following command to create the necessary tables in your database:
+
+```bash
+npx better-auth migrate
+```
+
+
+## Create a client
+
+Create a client instance. You can name the file anything you want. Here we are creating `client.ts` file inside the `lib/` directory.
+
+```ts twoslash title="client.ts"
+import { createAuthClient } from "better-auth/svelte" // make sure to import from better-auth/svlete
+
+export const client = createAuthClient({
+ //you can pass client configuration here
+})
+```
+
+Once you have created the client, you can use it to sign up, sign in, and perform other actions.
+Some of the actinos are reactive. The client use [nano-store](https://github.com/nanostores/nanostores) to store the state and refelct changes when there is a change like a user signing in or out affecting the session state.
+
+### Example usage
+```svelte
+
+
+ {#if $session}
+
+
+ {$session?.user.name}
+
+
+
+ {:else}
+
+ {/if}
+
+```
+
+### Example: Getting Session on a ServerComponent
+
+```ts title="+page.ts"
+import { auth } from "$lib/auth";
+
+export async function load(request: Request) {
+ const session = await auth.api.getSession({
+ headers: request.headers,
+ });
+ if (!session) {
+ return {
+ status: 401,
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ error: "Unauthorized",
+ }),
+ };
+ }
+ return session;
+}
+```
\ No newline at end of file
diff --git a/docs/content/docs/introduction.mdx b/docs/content/docs/introduction.mdx
index 75f3c9ca1f..d5595097fb 100644
--- a/docs/content/docs/introduction.mdx
+++ b/docs/content/docs/introduction.mdx
@@ -3,8 +3,16 @@ title: Introduction
description: Introduction to Better Auth.
---
-Better Auth is comprehnsive, batteries included, framework-agnostic and extensible auth library and auth ecosystem for typescript.
+Better Auth is a type-safe, framework-agnostic authentication library for TypeScript. It provides a comprehensive set of features out of the box and includes a plugin ecosystem that simplifies adding advanced functionalities with minimal code. Whether you need 2FA, multi-tenant support, or other complex features. It lets you focus on building your app instead of reinventing the wheel.
## Why Better Auth?
-Auth libraries in the TypeScript ecosystem typically handle basic authentication but often require significant additional code for any additional functionality. Better Auth addresses this gap by providing a comprehensive set of features out of the box and supporting easy extension through plugins for any additional auth-related requirements. It’s designed to be framework-agnostic, allowing integration with any framework backend or frontend, and it's built with typesaftey in mind.
+*Hi there, I’m Beka, the creator of Better Auth. I’ve often found that working with TypeScript auth libraries means dealing with a ton of additional code for anything beyond basic authentication, which is just a huge time sink. I thought we could do better than pushing third-party providers, so I built Better Auth.*
+
+## Features
+
+Better auth is aims to be the most comprehensive auth library. It provides a wide range of features out of the box and allows you to extend it with plugins. Here are some of the features:
+
+
+
+and much more...
diff --git a/docs/content/docs/plugins/bearer.mdx b/docs/content/docs/plugins/bearer.mdx
new file mode 100644
index 0000000000..9799703d5a
--- /dev/null
+++ b/docs/content/docs/plugins/bearer.mdx
@@ -0,0 +1,21 @@
+---
+title: Bearer
+description: The Bearer plugin allows you to authenticate with a Bearer token instead of a browser cookie.
+---
+
+The Bearer plugin allows you to authenticate with a Bearer token instead of a browser cookie. It proxies the request and set the bearer token in the Authorization header to a cookie request internally.
+
+## Add the Bearer plugin
+
+```ts title="auth.ts" twoslash
+import { betterAuth } from "better-auth";
+import { bearer } from "better-auth/plugins";
+
+export const { api, handler } = betterAuth({
+ database: {
+ provider: 'sqlite',
+ url: './db.sqlite'
+ },
+ plugins: [bearer()]
+});
+```
\ No newline at end of file
diff --git a/docs/content/docs/plugins/introduction.mdx b/docs/content/docs/plugins/introduction.mdx
deleted file mode 100644
index 1245a29648..0000000000
--- a/docs/content/docs/plugins/introduction.mdx
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: Introduction
-description: Introduction to better auth plugins
----
-
-Better Auth comes with a plugin system. It provides a set of built-in plugins that you can use to authenticate users using different methods. You can also create your own custom plugins to extend the functionality of Better Auth.
-
-## What are plugins?
-
-Plugins can be used to extend the functionality of Better Auth. They allow you to add new features or modify existing features of Better Auth. Plugins can be used to authenticate users using different methods, store user data in a databases, hook into existing authentication methods, and more.
\ No newline at end of file
diff --git a/docs/content/docs/plugins/organization.mdx b/docs/content/docs/plugins/organization.mdx
index cfe70c4685..d1bbdaac2f 100644
--- a/docs/content/docs/plugins/organization.mdx
+++ b/docs/content/docs/plugins/organization.mdx
@@ -25,8 +25,6 @@ Organizations Plugin offer a versatile and scalable approach to controlling user
] // [!code highlight]
})
```
-
- Now you have all the endpoints that are required to manage organizations and members. You can call them on the serer using the `api` object. Let's see how to use them on the client.
### Migarate database
diff --git a/docs/mdx-components.tsx b/docs/mdx-components.tsx
index 146af6ad3a..366a65025f 100644
--- a/docs/mdx-components.tsx
+++ b/docs/mdx-components.tsx
@@ -7,6 +7,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
import { GenerateSecret } from './components/generate-secret';
import { Popup, PopupContent, PopupTrigger } from "fumadocs-ui/twoslash/popup";
import { TypeTable } from 'fumadocs-ui/components/type-table';
+import { FeaturesSectionDemo } from './components/blocks/features-section-demo-3';
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
...defaultComponents,
@@ -26,5 +27,6 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
PopupTrigger,
PopupContent,
TypeTable,
+ Features: FeaturesSectionDemo
};
}
diff --git a/docs/next.config.mjs b/docs/next.config.mjs
index c449e224c8..d2d19f1bc7 100644
--- a/docs/next.config.mjs
+++ b/docs/next.config.mjs
@@ -43,6 +43,16 @@ const config = {
},
];
},
+ images: {
+ remotePatterns: [
+ {
+ hostname: 'images.unsplash.com'
+ },
+ {
+ hostname: 'assets.aceternity.com'
+ },
+ ]
+ }
};
export default withMDX(config);
diff --git a/docs/package.json b/docs/package.json
index 4a944ff525..dd038a8ff4 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -37,10 +37,15 @@
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
+ "@tabler/icons-react": "^3.12.0",
+ "@tsparticles/engine": "^3.5.0",
+ "@tsparticles/react": "^3.0.0",
+ "@tsparticles/slim": "^3.5.0",
"better-auth": "workspace:0.0.2-beta.8",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "1.0.0",
+ "cobe": "^0.6.3",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.2.0",
"framer-motion": "^11.3.30",
@@ -52,6 +57,7 @@
"geist": "^1.3.1",
"input-otp": "^1.2.4",
"lucide-react": "^0.435.0",
+ "mini-svg-data-uri": "^1.4.4",
"next": "^14.2.5",
"next-themes": "^0.3.0",
"prism-react-renderer": "^2.4.0",
@@ -63,7 +69,7 @@
"recharts": "^2.12.7",
"rehype-mermaid": "^2.1.0",
"sonner": "^1.5.0",
- "tailwind-merge": "^2.5.0",
+ "tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7",
"unist-util-visit": "^5.0.0",
"vaul": "^0.9.1",
diff --git a/docs/tailwind.config.js b/docs/tailwind.config.js
index 9669bafed7..e53c9cc0f6 100644
--- a/docs/tailwind.config.js
+++ b/docs/tailwind.config.js
@@ -1,5 +1,11 @@
import { createPreset } from 'fumadocs-ui/tailwind-plugin';
import defaultTheme from "tailwindcss/defaultTheme";
+const colors = require("tailwindcss/colors");
+const {
+ default: flattenColorPalette,
+} = require("tailwindcss/lib/util/flattenColorPalette");
+
+const svgToDataUri = require("mini-svg-data-uri");
/** @type {import('tailwindcss').Config} */
export default {
@@ -12,7 +18,28 @@ export default {
'./node_modules/fumadocs-ui/dist/**/*.js',
],
presets: [createPreset()],
- plugins: [require("tailwindcss-animate")],
+ plugins: [require("tailwindcss-animate"), addVariablesForColors, function ({ matchUtilities, theme }) {
+ matchUtilities(
+ {
+ "bg-grid": (value) => ({
+ backgroundImage: `url("${svgToDataUri(
+ ``
+ )}")`,
+ }),
+ "bg-grid-small": (value) => ({
+ backgroundImage: `url("${svgToDataUri(
+ ``
+ )}")`,
+ }),
+ "bg-dot": (value) => ({
+ backgroundImage: `url("${svgToDataUri(
+ ``
+ )}")`,
+ }),
+ },
+ { values: flattenColorPalette(theme("backgroundColor")), type: "color" }
+ );
+ }],
theme: {
extend: {
fontFamily: {
@@ -90,5 +117,17 @@ export default {
'accordion-up': 'accordion-up 0.2s ease-out'
}
}
- }
+ },
+
};
+
+function addVariablesForColors({ addBase, theme }) {
+ let allColors = flattenColorPalette(theme("colors"));
+ let newVars = Object.fromEntries(
+ Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
+ );
+
+ addBase({
+ ":root": newVars,
+ });
+}
\ No newline at end of file
diff --git a/packages/better-auth/src/api/index.ts b/packages/better-auth/src/api/index.ts
index a1cedb2e53..6719fc1921 100644
--- a/packages/better-auth/src/api/index.ts
+++ b/packages/better-auth/src/api/index.ts
@@ -189,7 +189,7 @@ export const router = (
});
},
onError(e) {
- // console.log(e);
+ console.log(e);
},
});
};
diff --git a/packages/better-auth/src/api/routes/credential.test.ts b/packages/better-auth/src/api/routes/credential.test.ts
index 1cf26b1f25..f1f43551ab 100644
--- a/packages/better-auth/src/api/routes/credential.test.ts
+++ b/packages/better-auth/src/api/routes/credential.test.ts
@@ -16,7 +16,7 @@ const testCredential2 = {
describe("credential", async () => {
it("should sign up with email and password", async () => {
- const res = await client.signUp.credential({
+ const res = await client.signUp.email({
email: testCredential1.email,
password: testCredential1.password,
name: testCredential1.name,
@@ -39,7 +39,7 @@ describe("credential", async () => {
},
});
- const res2 = await auth.api.signUpCredential({
+ const res2 = await auth.api.signUpEmail({
method: "POST",
body: {
email: testCredential2.email,
@@ -69,7 +69,7 @@ describe("credential", async () => {
describe("sign-in credential", async () => {
it("should sign in with email and password", async () => {
- const res = await client.signIn.credential({
+ const res = await client.signIn.email({
email: testCredential1.email,
password: testCredential1.password,
});
@@ -91,7 +91,7 @@ describe("sign-in credential", async () => {
},
});
- const res2 = await auth.api.signInCredential({
+ const res2 = await auth.api.signInEmail({
method: "POST",
body: {
email: testCredential2.email,
@@ -121,7 +121,7 @@ describe("sign-in credential", async () => {
});
it("should't remember me", async () => {
- const res = await client.signIn.credential({
+ const res = await client.signIn.email({
email: testCredential1.email,
password: testCredential1.password,
dontRememberMe: true,
diff --git a/packages/better-auth/src/auth.ts b/packages/better-auth/src/auth.ts
index de96310cbe..5b49eec6b5 100644
--- a/packages/better-auth/src/auth.ts
+++ b/packages/better-auth/src/auth.ts
@@ -9,12 +9,15 @@ export const betterAuth = (options: O) => {
type PluginEndpoint = UnionToIntersection<
O["plugins"] extends Array
? T extends BetterAuthPlugin
- ? T["endpoints"]
+ ? {
+ [key in T["id"]]: T["endpoints"];
+ }
: {}
: {}
>;
const { handler, endpoints } = router(authContext);
type Endpoint = typeof endpoints;
+
return {
handler,
api: endpoints as Endpoint & PluginEndpoint,
diff --git a/packages/better-auth/src/cli/utils/get-migration.ts b/packages/better-auth/src/cli/utils/get-migration.ts
index cd47754b03..78abea5bde 100644
--- a/packages/better-auth/src/cli/utils/get-migration.ts
+++ b/packages/better-auth/src/cli/utils/get-migration.ts
@@ -154,7 +154,9 @@ export async function getMigrations(config: BetterAuthOptions) {
if (toBeCreated.length) {
for (const table of toBeCreated) {
- let dbT = db.schema.createTable(table.table);
+ let dbT = db.schema
+ .createTable(table.table)
+ .addColumn("id", "text", (col) => col.primaryKey());
for (const [fieldName, field] of Object.entries(table.fields)) {
const type = typeMap[field.type];
dbT = dbT.addColumn(fieldName, type, (col) => {
diff --git a/packages/better-auth/src/client/client.test.ts b/packages/better-auth/src/client/client.test.ts
index a27e3b207b..b6ea4270bc 100644
--- a/packages/better-auth/src/client/client.test.ts
+++ b/packages/better-auth/src/client/client.test.ts
@@ -1,21 +1,13 @@
import { describe, it } from "vitest";
-
import { getTestInstance } from "../test-utils/test-instance";
-import { createAuthClient } from "./base";
import { createAuthClient as createReactClient } from "./react";
-import { twoFactorClient } from "../plugins";
-import { usernameClient } from "../plugins/username/client";
+import { organization } from "../plugins";
import { organizationClient } from "./plugins";
import { createAccessControl } from "../plugins/organization/access";
describe("client path to object", async () => {
const auth = await getTestInstance({
- plugins: [
- // passkey({
- // rpID: "test",
- // rpName: "test",
- // }),
- ],
+ plugins: [organization()],
});
it("should return a path to object", async () => {
@@ -41,6 +33,5 @@ describe("client path to object", async () => {
],
csrfPlugin: false,
});
- client.organization.useActiveOrganization();
});
});
diff --git a/packages/better-auth/src/plugins/bearer/bearer.test.ts b/packages/better-auth/src/plugins/bearer/bearer.test.ts
index b330e161b8..6020bd719b 100644
--- a/packages/better-auth/src/plugins/bearer/bearer.test.ts
+++ b/packages/better-auth/src/plugins/bearer/bearer.test.ts
@@ -6,8 +6,8 @@ describe("bearer", async () => {
const { client, createTestUser } = await getTestInstance({
plugins: [bearer()],
});
- await createTestUser();
it("should get session", async () => {
+ await createTestUser();
const res = await client.$fetch<{ session: { id: string } }>(
"/sign-in/credential",
{
diff --git a/packages/better-auth/src/test-utils/test-instance.ts b/packages/better-auth/src/test-utils/test-instance.ts
index caa2136796..7947651993 100644
--- a/packages/better-auth/src/test-utils/test-instance.ts
+++ b/packages/better-auth/src/test-utils/test-instance.ts
@@ -5,6 +5,7 @@ import { betterAuth } from "../auth";
import { createAuthClient } from "../client";
import { github, google } from "../social-providers";
import type { BetterAuthOptions } from "../types";
+import { getMigrations } from "../cli/utils/get-migration";
export async function getTestInstance>(
options?: O,
@@ -31,7 +32,6 @@ export async function getTestInstance>(
database: {
provider: "sqlite",
url: dbName,
- autoMigrate: true,
},
emailAndPassword: {
enabled: true,
@@ -44,7 +44,7 @@ export async function getTestInstance>(
} as O extends undefined ? typeof opts : O & typeof opts);
async function createTestUser() {
- await auth.api.signUpCredential({
+ await auth.api.signUpEmail({
body: {
email: "test@test.com",
password: "test123456",
@@ -57,11 +57,16 @@ export async function getTestInstance>(
};
}
+ beforeAll(async () => {
+ const { runMigrations } = await getMigrations(opts);
+ await runMigrations();
+ });
+
afterAll(async () => {
await fs.unlink(dbName);
});
- const client = createAuthClient({
+ const client = createAuthClient({
customFetchImpl: async (url, init) => {
const req = new Request(url.toString(), init);
return auth.handler(req);
diff --git a/packages/better-auth/src/utils/shim.ts b/packages/better-auth/src/utils/shim.ts
index 0a6f12c5f8..c99e3ada94 100644
--- a/packages/better-auth/src/utils/shim.ts
+++ b/packages/better-auth/src/utils/shim.ts
@@ -1,9 +1,11 @@
+import type { AuthContext } from "../init";
+
export const shimContext = >(
- organizationObject: T,
+ originalObject: T,
newContext: Record,
) => {
const shimmedObj: Record = {};
- for (const [key, value] of Object.entries(organizationObject)) {
+ for (const [key, value] of Object.entries(originalObject)) {
shimmedObj[key] = (ctx: Record) => {
return value({
...ctx,
@@ -20,3 +22,54 @@ export const shimContext = >(
}
return shimmedObj as T;
};
+
+export const shimEndpoint = (ctx: AuthContext, value: any) => {
+ return async (context: any) => {
+ for (const plugin of ctx.options.plugins || []) {
+ if (plugin.hooks?.before) {
+ for (const hook of plugin.hooks.before) {
+ const match = hook.matcher({
+ ...context,
+ ...value,
+ });
+ if (match) {
+ const hookRes = await hook.handler(context);
+ if (hookRes && "context" in hookRes) {
+ context = {
+ ...context,
+ ...hookRes.context,
+ ...value,
+ };
+ }
+ }
+ }
+ }
+ }
+ //@ts-ignore
+ const endpointRes = value({
+ ...context,
+ context: {
+ ...ctx,
+ ...context.context,
+ },
+ });
+ let response = endpointRes;
+ for (const plugin of ctx.options.plugins || []) {
+ if (plugin.hooks?.after) {
+ for (const hook of plugin.hooks.after) {
+ const match = hook.matcher(context);
+ if (match) {
+ const obj = Object.assign(context, {
+ returned: endpointRes,
+ });
+ const hookRes = await hook.handler(obj);
+ if (hookRes && "response" in hookRes) {
+ response = hookRes.response as any;
+ }
+ }
+ }
+ }
+ }
+ return response;
+ };
+};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c0d6afeb30..4cac44cec6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -379,6 +379,18 @@ importers:
'@radix-ui/react-tooltip':
specifier: ^1.1.2
version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@tabler/icons-react':
+ specifier: ^3.12.0
+ version: 3.12.0(react@18.3.1)
+ '@tsparticles/engine':
+ specifier: ^3.5.0
+ version: 3.5.0
+ '@tsparticles/react':
+ specifier: ^3.0.0
+ version: 3.0.0(@tsparticles/engine@3.5.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@tsparticles/slim':
+ specifier: ^3.5.0
+ version: 3.5.0
better-auth:
specifier: workspace:0.0.2-beta.8
version: link:../packages/better-auth
@@ -391,6 +403,9 @@ importers:
cmdk:
specifier: 1.0.0
version: 1.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ cobe:
+ specifier: ^0.6.3
+ version: 0.6.3
date-fns:
specifier: ^3.6.0
version: 3.6.0
@@ -424,6 +439,9 @@ importers:
lucide-react:
specifier: ^0.435.0
version: 0.435.0(react@18.3.1)
+ mini-svg-data-uri:
+ specifier: ^1.4.4
+ version: 1.4.4
next:
specifier: ^14.2.5
version: 14.2.5(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -458,7 +476,7 @@ importers:
specifier: ^1.5.0
version: 1.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
tailwind-merge:
- specifier: ^2.5.0
+ specifier: ^2.5.2
version: 2.5.2
tailwindcss-animate:
specifier: ^1.0.7
@@ -3087,6 +3105,112 @@ packages:
'@ts-morph/common@0.24.0':
resolution: {integrity: sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==}
+ '@tsparticles/basic@3.5.0':
+ resolution: {integrity: sha512-oty33TxM2aHWrzcwWRic1bQ04KBCdpnvzv8JXEkx5Uyp70vgVegUbtKmwGki3shqKZIt3v2qE4I8NsK6onhLrA==}
+
+ '@tsparticles/engine@3.5.0':
+ resolution: {integrity: sha512-RCwrJ2SvSYdhXJ24oUCjSUKEZQ9lXwObOWMvfMC9vS6/bk+Qo0N7Xx8AfumqzP/LebB1YJdlCvuoJMauAon0Pg==}
+
+ '@tsparticles/interaction-external-attract@3.5.0':
+ resolution: {integrity: sha512-BQYjoHtq7yaETSvPtzKt93OO9MZ1WuDZj7cFPG+iujNekXiwhLRQ89a+QMcsTrCLx70KLJ7SuTzQL5MT1/kb2Q==}
+
+ '@tsparticles/interaction-external-bounce@3.5.0':
+ resolution: {integrity: sha512-H/0//dn4zwKes8zWIjolfeokL0VAlj+EkK7LUhznPhPu+Gt+h6aJqPlwC2MdI5Rvcnps8dT7YoCBWBQ4tJH6zg==}
+
+ '@tsparticles/interaction-external-bubble@3.5.0':
+ resolution: {integrity: sha512-xTS4PQDMC5j9qOAFTC1M9DfBTJl8P8M41ySGtZHnCvVqG0oLlLSw15msniamjXyaoA4tZvBPM6G+GmFdgE9w1A==}
+
+ '@tsparticles/interaction-external-connect@3.5.0':
+ resolution: {integrity: sha512-VSpyZ0P8Hu4nq6C917X3tnwEROfGjrm0ivWJmbBv/lFJ9euZ2VeezeITNZNtNvt/hS5vLI8npDetB/wtd994HQ==}
+
+ '@tsparticles/interaction-external-grab@3.5.0':
+ resolution: {integrity: sha512-WOTWSGVerlfJZ9zwq8Eyutq1h0LAr1hI/Fs8j7s5qabZjxPzUBV8rhgghZ/nGrHEiB6j8SW4XMHkN6XR0VM9Ww==}
+
+ '@tsparticles/interaction-external-pause@3.5.0':
+ resolution: {integrity: sha512-Hnj1mBH5X3d3zwTP6R+tYn45uTq5XGLDINhEzl30EAjXK30LQe8/RgE91O4CsMSrlTmouG0OuHYGC3nyrn/dcw==}
+
+ '@tsparticles/interaction-external-push@3.5.0':
+ resolution: {integrity: sha512-8UNt5lYRhydDJCK7AznR3s1nJj3OCeLcDknARoq7hATdI+G151QAubD9NUUURCZ1GdXpftT5Bh0Bl1YtiZwOhg==}
+
+ '@tsparticles/interaction-external-remove@3.5.0':
+ resolution: {integrity: sha512-+qiVRnR8xywg++gn8fagwpuQVh0WWKxIMkY6l6lMw9UoXz8L6MUVgvWaT632EVmkrTgM43pZ1m0W3m9aBY9rZw==}
+
+ '@tsparticles/interaction-external-repulse@3.5.0':
+ resolution: {integrity: sha512-lTF7iLqCCQ3AbQSDVTpE3TihoVvI322/5QTqQmwylrrmjbDxGu4Hym4BHK5GqDHOdodOnwU2DWjRF5cRx3aPPg==}
+
+ '@tsparticles/interaction-external-slow@3.5.0':
+ resolution: {integrity: sha512-KYp1GWbXdnLunFvHJt2YMZMMITebAt0XkzisKoSe+rfvoCbcMGXI2XvDYb0UkGvd8sKTSnHcn7cGH8dhVXXYaQ==}
+
+ '@tsparticles/interaction-particles-attract@3.5.0':
+ resolution: {integrity: sha512-ICnT9+9ZxINh5ZijyxjFXOOMC/jNQgOXPe+5MxgK/WYXE8mRbRzsOdaxiS3zK5PSFlqtztn189anDbfqcHDutQ==}
+
+ '@tsparticles/interaction-particles-collisions@3.5.0':
+ resolution: {integrity: sha512-KrfyXy4l6nW2z0An2FE4z5R4rEiIONYPcDpkBhWqQK+pyLkHhtGYmqmP7Pb22IC9noFzjOCaR5CNVjWP7B+1vA==}
+
+ '@tsparticles/interaction-particles-links@3.5.0':
+ resolution: {integrity: sha512-ZdIixcGcRJMxCq4zxeRAzzbbuN5vVoy3pDDLaO3mnWnfJWywkYZToV0XvOUaHUT2AkUuKa9ZuQKx0LO3z1AO+w==}
+
+ '@tsparticles/move-base@3.5.0':
+ resolution: {integrity: sha512-9oDk7zTxyhUCstj3lHTNTiWAgqIBzWa2o1tVQFK63Qwq+/WxzJCSwZOocC9PAHGM1IP6nA4zYJSfjbMBTrUocA==}
+
+ '@tsparticles/move-parallax@3.5.0':
+ resolution: {integrity: sha512-1NC2OGsbdLc5T4uiRqq7i24b9FIhfaLnx4wVtOQjX48jWfy/ZKOdIEYLFKOPHnaMI0MjinJTNXLi9i6zVNCobg==}
+
+ '@tsparticles/plugin-easing-quad@3.5.0':
+ resolution: {integrity: sha512-Pd44hTiVlaaeQZwRlP+ih8jKmWuIQdkpPUJS0Qwzeck2nfK01IAflDJoxXxGF53vA8QOrz/K6VdVQJShD8yCsg==}
+
+ '@tsparticles/react@3.0.0':
+ resolution: {integrity: sha512-hjGEtTT1cwv6BcjL+GcVgH++KYs52bIuQGW3PWv7z3tMa8g0bd6RI/vWSLj7p//NZ3uTjEIeilYIUPBh7Jfq/Q==}
+ peerDependencies:
+ '@tsparticles/engine': ^3.0.2
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
+ '@tsparticles/shape-circle@3.5.0':
+ resolution: {integrity: sha512-59TmXkeeI6Jzv5vt/D3TkclglabaoEXQi2kbDjSCBK68SXRHzlQu29mSAL41Y5S0Ft5ZJKkAQHX1IqEnm8Hyjg==}
+
+ '@tsparticles/shape-emoji@3.5.0':
+ resolution: {integrity: sha512-cxWHxQxnG5vLDltkoxdo7KS87uKPwQgf4SDWy/WCxW4Psm1TEeeSGYMJPVed+wWPspOKmLb7u8OaEexgE2pHHQ==}
+
+ '@tsparticles/shape-image@3.5.0':
+ resolution: {integrity: sha512-lWYg7DTv74dSOnXy+4dr7t1/OSuUmxDpIo12Lbxgx/QBN7A5I/HoqbKcs13TSA0RS1hcuMgtti07BcDTEYW3Dw==}
+
+ '@tsparticles/shape-line@3.5.0':
+ resolution: {integrity: sha512-Qc4jwFEi/VnwmGwQBO/kCJEfNYdKHpeXfrdcqmm9c1B4iYHHDoaXJp6asMTggEfeAWu7fyPaO/7MURiPEqg7Hg==}
+
+ '@tsparticles/shape-polygon@3.5.0':
+ resolution: {integrity: sha512-sqYL+YXpnq3nSWcOEGZaJ4Z7Cb7x8M0iORSLpPdNEIvwDKdPczYyQM95D8ep19Pv1CV5L0uRthV36wg7UpnJ9Q==}
+
+ '@tsparticles/shape-square@3.5.0':
+ resolution: {integrity: sha512-rPHpA4Pzm1W5DIIow+lQS+VS7D2thSBQQbV9eHxb933Wh0/QC3me3w4vovuq7hdtVANhsUVO04n44Gc/2TgHkw==}
+
+ '@tsparticles/shape-star@3.5.0':
+ resolution: {integrity: sha512-EDEJc4MYv3UbOeA3wrZjuJVtZ08PdCzzBij3T/7Tp3HUCf/p9XnfHBd/CPR5Mo6X0xpGfrein8UQN9CjGLHwUA==}
+
+ '@tsparticles/slim@3.5.0':
+ resolution: {integrity: sha512-CKx3VtzsY0fs/dQc41PYtL3edm1z2sBROTgvz3adwqMyTWkQGnjLQhsM777Ebb6Yjf5Jxu4TzWOBc2HO7Cstkg==}
+
+ '@tsparticles/updater-color@3.5.0':
+ resolution: {integrity: sha512-TGGgiLixIg37sst2Fj9IV4XbdMwkT6PYanM7qEqyfmv4hJ/RHMQlCznEe6b7OhChQVBg5ov5EMl/BT4/fIWEYw==}
+
+ '@tsparticles/updater-life@3.5.0':
+ resolution: {integrity: sha512-jlMEq16dwN+rZmW/UmLdqaCe4W0NFrVdmXkZV8QWYgu06a+Ucslz337nHYaP89/9rZWpNua/uq1JDjDzaVD5Jg==}
+
+ '@tsparticles/updater-opacity@3.5.0':
+ resolution: {integrity: sha512-T2YfqdIFV/f5VOg1JQsXu6/owdi9g9K2wrJlBfgteo+IboVp6Lcuo4PGAfilWVkWrTdp1Nz4mz39NrLHfOce2g==}
+
+ '@tsparticles/updater-out-modes@3.5.0':
+ resolution: {integrity: sha512-y6NZe2OSk5SrYdaLwUIQnHICsNEDIdPPJHQ2nAWSvAuPJphlSKjUknc7OaGiFwle6l0OkhWoZZe1rV1ktbw/lA==}
+
+ '@tsparticles/updater-rotate@3.5.0':
+ resolution: {integrity: sha512-j4qPHQd1eUmDoGnIJOsVswHLqtTof1je+b2GTOLB3WIoKmlyUpzQYjVc7PNfLMuCEUubwpZCfcd/vC80VZeWkg==}
+
+ '@tsparticles/updater-size@3.5.0':
+ resolution: {integrity: sha512-TnWlOChBsVZffT2uO0S4ALGSzxT6UAMIVlhGMGFgSeIlktKMqM+dxDGAPrYa1n8IS2dkVGisiXzsV0Ss6Ceu1A==}
+
+ '@tsparticles/updater-stroke-color@3.5.0':
+ resolution: {integrity: sha512-29X1zER+W9IBDv0nTD/jRXnu5rEU7uv7+W1N0B6leBipjAY24sg7Kub2SvXAaBKz6kHHWuCeccBOwIiiTpDqMA==}
+
'@tybys/wasm-util@0.8.3':
resolution: {integrity: sha512-Z96T/L6dUFFxgFJ+pQtkPpne9q7i6kIPYCFnQBHSgSPV9idTsKfIhCss0h5iM9irweZCatkrdeP8yi5uM1eX6Q==}
@@ -3854,6 +3978,9 @@ packages:
react: ^18.0.0
react-dom: ^18.0.0
+ cobe@0.6.3:
+ resolution: {integrity: sha512-WHr7X4o1ym94GZ96h7b1pNemZJacbOzd02dZtnVwuC4oWBaLg96PBmp2rIS1SAhUDhhC/QyS9WEqkpZIs/ZBTg==}
+
code-block-writer@13.0.2:
resolution: {integrity: sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==}
@@ -6170,6 +6297,9 @@ packages:
pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
+ phenomenon@1.6.0:
+ resolution: {integrity: sha512-7h9/fjPD3qNlgggzm88cY58l9sudZ6Ey+UmZsizfhtawO6E3srZQXywaNm2lBwT72TbpHYRPy7ytIHeBUD/G0A==}
+
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
@@ -10407,6 +10537,173 @@ snapshots:
mkdirp: 3.0.1
path-browserify: 1.0.1
+ '@tsparticles/basic@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+ '@tsparticles/move-base': 3.5.0
+ '@tsparticles/shape-circle': 3.5.0
+ '@tsparticles/updater-color': 3.5.0
+ '@tsparticles/updater-opacity': 3.5.0
+ '@tsparticles/updater-out-modes': 3.5.0
+ '@tsparticles/updater-size': 3.5.0
+
+ '@tsparticles/engine@3.5.0': {}
+
+ '@tsparticles/interaction-external-attract@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-bounce@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-bubble@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-connect@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-grab@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-pause@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-push@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-remove@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-repulse@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-external-slow@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-particles-attract@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-particles-collisions@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/interaction-particles-links@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/move-base@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/move-parallax@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/plugin-easing-quad@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/react@3.0.0(@tsparticles/engine@3.5.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
+ '@tsparticles/shape-circle@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/shape-emoji@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/shape-image@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/shape-line@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/shape-polygon@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/shape-square@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/shape-star@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/slim@3.5.0':
+ dependencies:
+ '@tsparticles/basic': 3.5.0
+ '@tsparticles/engine': 3.5.0
+ '@tsparticles/interaction-external-attract': 3.5.0
+ '@tsparticles/interaction-external-bounce': 3.5.0
+ '@tsparticles/interaction-external-bubble': 3.5.0
+ '@tsparticles/interaction-external-connect': 3.5.0
+ '@tsparticles/interaction-external-grab': 3.5.0
+ '@tsparticles/interaction-external-pause': 3.5.0
+ '@tsparticles/interaction-external-push': 3.5.0
+ '@tsparticles/interaction-external-remove': 3.5.0
+ '@tsparticles/interaction-external-repulse': 3.5.0
+ '@tsparticles/interaction-external-slow': 3.5.0
+ '@tsparticles/interaction-particles-attract': 3.5.0
+ '@tsparticles/interaction-particles-collisions': 3.5.0
+ '@tsparticles/interaction-particles-links': 3.5.0
+ '@tsparticles/move-parallax': 3.5.0
+ '@tsparticles/plugin-easing-quad': 3.5.0
+ '@tsparticles/shape-emoji': 3.5.0
+ '@tsparticles/shape-image': 3.5.0
+ '@tsparticles/shape-line': 3.5.0
+ '@tsparticles/shape-polygon': 3.5.0
+ '@tsparticles/shape-square': 3.5.0
+ '@tsparticles/shape-star': 3.5.0
+ '@tsparticles/updater-life': 3.5.0
+ '@tsparticles/updater-rotate': 3.5.0
+ '@tsparticles/updater-stroke-color': 3.5.0
+
+ '@tsparticles/updater-color@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/updater-life@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/updater-opacity@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/updater-out-modes@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/updater-rotate@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/updater-size@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
+ '@tsparticles/updater-stroke-color@3.5.0':
+ dependencies:
+ '@tsparticles/engine': 3.5.0
+
'@tybys/wasm-util@0.8.3':
dependencies:
tslib: 2.6.3
@@ -11393,6 +11690,10 @@ snapshots:
- '@types/react'
- '@types/react-dom'
+ cobe@0.6.3:
+ dependencies:
+ phenomenon: 1.6.0
+
code-block-writer@13.0.2: {}
code-red@1.0.4:
@@ -14451,6 +14752,8 @@ snapshots:
dependencies:
split2: 4.2.0
+ phenomenon@1.6.0: {}
+
picocolors@1.0.1: {}
picomatch@2.3.1: {}