From 98402835c29dff9930df9b04c87dfa55c7fe4752 Mon Sep 17 00:00:00 2001
From: Bereket Engida <86073083+Bekacru@users.noreply.github.com>
Date: Sun, 29 Sep 2024 20:00:47 +0300
Subject: [PATCH] feat: Database adapters (#29)
* feat: prisma adapter
* feat: drizzle adapter
* feat: mongod db adapter
---
.github/workflows/ci.yml | 15 +-
dev/express/tsconfig.json | 34 +--
docker-compose.yml | 40 +++
docs/components/mdx/database-tables.tsx | 75 ++++++
docs/content/docs/concepts/database.mdx | 140 ++++++++--
docs/content/docs/concepts/rate-limit.mdx | 30 +++
docs/content/docs/installation.mdx | 39 ++-
docs/content/docs/integrations/astro.mdx | 57 +---
docs/content/docs/integrations/hono.mdx | 47 +---
docs/content/docs/integrations/next.mdx | 54 +---
docs/content/docs/integrations/node.mdx | 71 +----
docs/content/docs/integrations/nuxt.mdx | 44 +--
.../content/docs/integrations/solid-start.mdx | 49 +---
docs/content/docs/integrations/svelte-kit.mdx | 51 +---
docs/content/docs/plugins/2fa.mdx | 10 +-
docs/content/docs/plugins/organization.mdx | 130 ++++++++-
docs/content/docs/plugins/passkey.mdx | 64 +++++
docs/content/docs/plugins/rate-limit.mdx | 212 ---------------
docs/content/docs/plugins/username.mdx | 15 ++
docs/mdx-components.tsx | 2 +
packages/better-auth/package.json | 7 +-
.../src/adapters/drizzzle-adapter/index.ts | 119 ++++++++
.../test/adapter.dirzzle.test.ts | 43 +++
.../adapters/drizzzle-adapter/test/schema.ts | 20 ++
packages/better-auth/src/adapters/index.ts | 1 +
.../mongodb-adpter/adapter.mongo-db.test.ts | 29 ++
.../src/adapters/mongodb-adpter/index.ts | 133 +++++++++
.../prisma-adapter/adapter.prisma.test.ts | 20 ++
.../src/adapters/prisma-adapter/client.ts | 4 +
.../src/adapters/prisma-adapter/index.ts | 111 ++++++++
.../src/adapters/prisma-adapter/schema.prisma | 17 ++
packages/better-auth/src/adapters/test.ts | 123 +++++++++
.../better-auth/src/db/internal-adapter.ts | 19 +-
packages/better-auth/src/db/kysely.ts | 6 +-
packages/better-auth/src/db/utils.ts | 5 +
packages/better-auth/src/init.ts | 8 +-
.../better-auth/src/plugins/admin/index.ts | 37 +++
packages/better-auth/src/types/options.ts | 4 +-
pnpm-lock.yaml | 254 ++++++++++++++----
39 files changed, 1424 insertions(+), 715 deletions(-)
create mode 100644 docker-compose.yml
create mode 100644 docs/components/mdx/database-tables.tsx
delete mode 100644 docs/content/docs/plugins/rate-limit.mdx
create mode 100644 packages/better-auth/src/adapters/drizzzle-adapter/index.ts
create mode 100644 packages/better-auth/src/adapters/drizzzle-adapter/test/adapter.dirzzle.test.ts
create mode 100644 packages/better-auth/src/adapters/drizzzle-adapter/test/schema.ts
create mode 100644 packages/better-auth/src/adapters/index.ts
create mode 100644 packages/better-auth/src/adapters/mongodb-adpter/adapter.mongo-db.test.ts
create mode 100644 packages/better-auth/src/adapters/mongodb-adpter/index.ts
create mode 100644 packages/better-auth/src/adapters/prisma-adapter/adapter.prisma.test.ts
create mode 100644 packages/better-auth/src/adapters/prisma-adapter/client.ts
create mode 100644 packages/better-auth/src/adapters/prisma-adapter/index.ts
create mode 100644 packages/better-auth/src/adapters/prisma-adapter/schema.prisma
create mode 100644 packages/better-auth/src/adapters/test.ts
create mode 100644 packages/better-auth/src/plugins/admin/index.ts
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7c0ccf52..b0e22438 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,11 +29,20 @@ jobs:
- name: Build
run: pnpm build
- - name: lint
+ - name: Start Docker Containers
+ run: |
+ docker compose up -d
+ # Wait for services to be ready (optional)
+ sleep 10
+
+ - name: Lint
run: pnpm lint
- - name: test
+ - name: Test
run: pnpm test
- - name: typecheck
+ - name: Typecheck
run: pnpm typecheck
+
+ - name: Stop Docker Containers
+ run: docker compose down
diff --git a/dev/express/tsconfig.json b/dev/express/tsconfig.json
index ffc08abf..e0abf845 100644
--- a/dev/express/tsconfig.json
+++ b/dev/express/tsconfig.json
@@ -1,27 +1,17 @@
{
"compilerOptions": {
- // Enable latest features
- "lib": ["ESNext", "DOM"],
- "target": "ESNext",
- "module": "ESNext",
- "moduleDetection": "force",
- "jsx": "react-jsx",
- "allowJs": true,
-
- // Bundler mode
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "verbatimModuleSyntax": true,
- "noEmit": true,
-
- // Best practices
- "strict": true,
+ "esModuleInterop": true,
"skipLibCheck": true,
- "noFallthroughCasesInSwitch": true,
-
- // Some stricter flags (disabled by default)
- "noUnusedLocals": false,
- "noUnusedParameters": false,
- "noPropertyAccessFromIndexSignature": false
+ "target": "es2022",
+ "allowJs": true,
+ "resolveJsonModule": true,
+ "moduleDetection": "force",
+ "isolatedModules": true,
+ "verbatimModuleSyntax": true,
+ "strict": true,
+ "moduleResolution": "Bundler",
+ "outDir": "dist",
+ "sourceMap": true,
+ "lib": ["es2022"]
}
}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..4114a658
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,40 @@
+version: '3.8'
+
+services:
+ mongodb:
+ image: mongo:latest
+ container_name: mongodb
+ ports:
+ - "27017:27017"
+ volumes:
+ - mongodb_data:/data/db
+
+ postgres:
+ image: postgres:latest
+ container_name: postgres
+ environment:
+ POSTGRES_USER: user
+ POSTGRES_PASSWORD: password
+ POSTGRES_DB: better_auth
+ ports:
+ - "5432:5432"
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+ mysql:
+ image: mysql:latest
+ container_name: mysql
+ environment:
+ MYSQL_ROOT_PASSWORD: root_password
+ MYSQL_DATABASE: better_auth
+ MYSQL_USER: user
+ MYSQL_PASSWORD: password
+ ports:
+ - "3306:3306"
+ volumes:
+ - mysql_data:/var/lib/mysql
+
+volumes:
+ mongodb_data:
+ postgres_data:
+ mysql_data:
\ No newline at end of file
diff --git a/docs/components/mdx/database-tables.tsx b/docs/components/mdx/database-tables.tsx
new file mode 100644
index 00000000..9b8b844b
--- /dev/null
+++ b/docs/components/mdx/database-tables.tsx
@@ -0,0 +1,75 @@
+import { Card, CardContent } from "@/components/ui/card";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table";
+import { Badge } from "@/components/ui/badge";
+import { Key, Link } from "lucide-react";
+import { Label } from "../ui/label";
+
+interface Field {
+ name: string;
+ type: string;
+ description: string;
+ isPrimaryKey?: boolean;
+ isForeignKey?: boolean;
+}
+
+interface DatabaseTableProps {
+ fields: Field[];
+}
+
+export default function DatabaseTable({ fields }: DatabaseTableProps) {
+ return (
+
+
+
+
+ Field Name
+ Type
+ Key
+ Description
+
+
+
+ {fields.map((field, index) => (
+
+ {field.name}
+
+ {field.type}
+
+
+ {field.isPrimaryKey && (
+
+
+ PK
+
+ )}
+ {field.isForeignKey && (
+
+
+ FK
+
+ )}
+ {!field.isPrimaryKey && !field.isForeignKey && (
+ -
+ )}
+
+ {field.description}
+
+ ))}
+
+
+
+ );
+}
diff --git a/docs/content/docs/concepts/database.mdx b/docs/content/docs/concepts/database.mdx
index 49222da3..22e1e7ed 100644
--- a/docs/content/docs/concepts/database.mdx
+++ b/docs/content/docs/concepts/database.mdx
@@ -74,31 +74,129 @@ If you prefer adding tables manually, you can do that as well. The core schema r
## Core Schema
-Better auth requires the following tables to be present in the database:
+Better auth requires the following tables to be present in the database. The types are in `typescript` format. You can use corresponding types in your database.
-**user**:
+### User
-- `id`: (string) - The unique identifier of the user.
-- `email`: (string) - The email address of the user.
-- `name`: (string) - The name of the user.
-- `image`: (string) - The image of the user. (optional)
+ Table Name: `user`
-**session**:
-- `id`: (string) - The unique identifier of the session. Also used as the session token.
-- `userId`: (foregin-key: `user.id`) - The id of the user.
-- `expiresAt`: (Date) - The time when the session expires.
-- `ipAddress`: (string) - The IP address of the device. (optional)
-- `userAgent`: (string) - The user agent information of the device. (optional)
+
-**account**:
-- `id`: (string) - The unique identifier of the account.
-- `userId`: (foregin-key: `user.id`) - The id of the user.
-- `accountId`: (string) - The id of the account. (optional)
-- `providerId`: (string) - The id of the provider. (optional)
-- `accessToken`: (string) - The access token of the account. Returned by the provider. (optional)
-- `refreshToken`: (string) - The refresh token of the account. Returned by the provider. (optional)
-- `expiresAt`: (Date) - The time when the access token expires. (optional)
-- `password`: (string) - The password of the account. Mainly used for email and password authentication. (optional)
+### Session
+
+Table Name: `session`
+
+
+
+### Account
+
+Table Name: `account`
+
+
## Plugins Schema
diff --git a/docs/content/docs/concepts/rate-limit.mdx b/docs/content/docs/concepts/rate-limit.mdx
index 3213af9f..526bafcb 100644
--- a/docs/content/docs/concepts/rate-limit.mdx
+++ b/docs/content/docs/concepts/rate-limit.mdx
@@ -141,3 +141,33 @@ await client.signIn.email({
})
```
+### Schema
+
+If you are using a database to store rate limit data you need this schema:
+
+Table Name: `rateLimit`
+
+
\ No newline at end of file
diff --git a/docs/content/docs/installation.mdx b/docs/content/docs/installation.mdx
index 388130de..bd34cbc3 100644
--- a/docs/content/docs/installation.mdx
+++ b/docs/content/docs/installation.mdx
@@ -67,8 +67,7 @@ export const auth = betterAuth({
### Configure Database
-Better Auth requires a database to store user data. It uses Kysely under the hood to connect to your database.
-`postgresql`, `mysql`, and `sqlite` are supported out of the box.
+Better Auth requires a database to store user data. By default, it uses Kysely under the hood to connect and query your database. `postgresql`, `mysql`, and `sqlite` are supported out of the box.
```ts title="auth.ts"
import { betterAuth } from "better-auth"
@@ -96,8 +95,32 @@ export const auth = betterAuth({
});
```
+**Adapters**
+
+If your database is not supported by Kysely, you can use an adapter to connect to your database.
+
+To use an adapter, import the adapter and pass it to the database option.
+
+Currently, 3 adapters are supported:
+- **Prisma**
+- **Drizzle**
+- **MongoDB**
+
+```ts title="auth.ts"
+import { prismaAdapter } from "better-auth/adapters"; // [!code highlight]
+import { PrismaClient } from "@prisma/client";
+
+const prisma = new PrismaClient();
+
+export const auth = betterAuth({
+ database: {
+ provider: prismaAdapter(prisma), // [!code highlight]
+ }
+})
+```
+
- Currently, Better Auth only support databases that are supported by Kysely. [vote this issue if you like to see non sql db support](https://github.com/better-auth/better-auth/issues/5)
+We highly recommend using the built-in option if your database is supported by Kysely, as we use optimized queries for Kysely.
@@ -105,16 +128,14 @@ export const auth = betterAuth({
### Migrate Schema
Better Auth includes a CLI tool to migrate the required schema to your database. It introspects the database and creates the required tables. Run the following command to perform the migration:
+
```bash title="Terminal"
npx better-auth migrate
```
- Better Auth automatically sets up the following tables in your database if they don't already exist:
- - `user`
- - `session`
- - `account`
-
- For more details head over to [schema](/docs/concepts/database#core-schema) section.
+
+ If you're using an adapter and your database is not supported by Kysely, you need to create required tables manually. You can find the core schema required in the [database section](/docs/concepts/database#core-schema).
+
diff --git a/docs/content/docs/integrations/astro.mdx b/docs/content/docs/integrations/astro.mdx
index 129088cf..e57c1ee7 100644
--- a/docs/content/docs/integrations/astro.mdx
+++ b/docs/content/docs/integrations/astro.mdx
@@ -5,60 +5,7 @@ description: Integrate Better Auth with Astro
Better auth comes with first class support for Astro. This guide will show you how to integrate better auth with Astro.
-## 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 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 Better Auth
-
-
-### Create Better Auth instance
-
-Create a `auth.ts` file in one of these directories:
-
-- `.` (root directory)
-- `lib/`
-- `src/`
-- `utils/`
-
-This file will contain your Better Auth instance.
-
-```ts title="auth.ts"
-import { BetterAuth } from "better-auth"
-
-export const auth = new BetterAuth({
- database: {
- provider: "sqlite", //change this to your database provider
- url: "./db.sqlite", // path to your database or connection string
- },
-})
-```
-
-### Migrate the database
-
-You'll need to run the migration command to create the necessary tables in the database.
-
-```bash
-npx better-auth migrate
-```
+Before you start, make sure you have a better auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
### Mount the handler
@@ -138,7 +85,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
});
```
-## Getting session on the server inside .astro file
+## Getting session on the server inside `.astro` file
You can use `auth.api` to call the API from the server side. Here is an example of how you can get the session inside an `.astro` file:
diff --git a/docs/content/docs/integrations/hono.mdx b/docs/content/docs/integrations/hono.mdx
index f973babd..9c9c6585 100644
--- a/docs/content/docs/integrations/hono.mdx
+++ b/docs/content/docs/integrations/hono.mdx
@@ -5,52 +5,7 @@ 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 auth = 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.
-
+Before you start, make sure you have a better auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
### Mount the handler
diff --git a/docs/content/docs/integrations/next.mdx b/docs/content/docs/integrations/next.mdx
index d42505c5..93b0972b 100644
--- a/docs/content/docs/integrations/next.mdx
+++ b/docs/content/docs/integrations/next.mdx
@@ -5,52 +5,7 @@ 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 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 auth = 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.
-
+Before you start, make sure you have a better auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
### Create API Route
@@ -80,13 +35,6 @@ export const { GET, POST } = toNextJsHandler(auth.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.
diff --git a/docs/content/docs/integrations/node.mdx b/docs/content/docs/integrations/node.mdx
index e20f5b5b..5a594954 100644
--- a/docs/content/docs/integrations/node.mdx
+++ b/docs/content/docs/integrations/node.mdx
@@ -5,76 +5,7 @@ description: Integrate Better Auth with Node backend
Better auth can be integrated with node based backed frameworks. The guide below will show you how to integrate better auth with express.
-## 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 application
-```
-
-
-if you're using a custom path other than `/api/auth` make sure to provider the full path in the `BETTER_AUTH_URL` variable. For example, if you're using `/custom-path` as the path, you should set `BETTER_AUTH_URL=http://localhost:3000/custom-path`. You can also provide path directly in the better auth options.
-
-
-
-**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=
-```
-
-
-
-## Configuring Better Auth
-
-### Create Better Auth instance
-
-Create a `auth.ts` file in one of these directories:
-
-- `.` (root directory)
-- `lib/`
-- `src/`
-- `utils/`
-
-This file will contain your Better Auth instance.
-
-```ts title="auth.ts"
-import { BetterAuth } from "better-auth"
-
-export const auth = new 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](/docs/api) on how to configure better auth.
-
-
-### Migrate the database
-
-You'll need to run the migration command to create the necessary tables in the database.
-
-
-```bash
-npx better-auth migrate
-```
+Before you start, make sure you have a better auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
### Mount the handler
diff --git a/docs/content/docs/integrations/nuxt.mdx b/docs/content/docs/integrations/nuxt.mdx
index 260c935c..a19d49ad 100644
--- a/docs/content/docs/integrations/nuxt.mdx
+++ b/docs/content/docs/integrations/nuxt.mdx
@@ -3,49 +3,7 @@ title: Nuxt.js Integration
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 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 auth = 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.
-
+Before you start, make sure you have a better auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
### Create API Route
diff --git a/docs/content/docs/integrations/solid-start.mdx b/docs/content/docs/integrations/solid-start.mdx
index 21afbe52..6845dddf 100644
--- a/docs/content/docs/integrations/solid-start.mdx
+++ b/docs/content/docs/integrations/solid-start.mdx
@@ -3,54 +3,7 @@ title: Solid Start Integration
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 auth = 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.
-
+Before you start, make sure you have a better auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
### Mount the handler
diff --git a/docs/content/docs/integrations/svelte-kit.mdx b/docs/content/docs/integrations/svelte-kit.mdx
index dcc49f5b..65b22524 100644
--- a/docs/content/docs/integrations/svelte-kit.mdx
+++ b/docs/content/docs/integrations/svelte-kit.mdx
@@ -2,56 +2,7 @@
title: Svelte Kit Integration
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 auth = 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.
-
+Before you start, make sure you have a better auth instance configured. If you haven't done that yet, check out the [installation](/docs/installation).
### Mount the handler
diff --git a/docs/content/docs/plugins/2fa.mdx b/docs/content/docs/plugins/2fa.mdx
index 5933ea11..a8462dcb 100644
--- a/docs/content/docs/plugins/2fa.mdx
+++ b/docs/content/docs/plugins/2fa.mdx
@@ -284,9 +284,13 @@ When `trustDevice` is set to `true`, the current device will be remembered for 6
The plugin requires 3 additional fields in the `user` table.
-- `twoFactorEnabled`: (boolean) - a boolean value that will be set `true` or `false` when authenticated user enable or disable two factor.
-- `twoFactorSecret`: (string) - Encrypted secret used to generate totp and otp.
-- `twoFactorBackupCodes`: (string) - Encrypted list of backup codes stored as a string separted by comma.
+
## Options
diff --git a/docs/content/docs/plugins/organization.mdx b/docs/content/docs/plugins/organization.mdx
index 1d1082e8..e229ccbd 100644
--- a/docs/content/docs/plugins/organization.mdx
+++ b/docs/content/docs/plugins/organization.mdx
@@ -502,6 +502,133 @@ the plugin providers easy way to define your own set of permission for each role
+## Schema
+
+The organization plugin adds the following tables to the database:
+
+### Organization
+
+Table Name: `organization`
+
+
+
+### Member
+
+Table Name: `member`
+
+
+
+### Invitation
+
+Table Name: `invitation`
+
+
+
## Options
**allowUserToCreateOrganization**: `boolean` | `((user: User) => Promise | boolean)` - A function that determines whether a user can create an organization. By default, it's `true`. You can set it to `false` to restrict users from creating organizations.
@@ -514,4 +641,5 @@ the plugin providers easy way to define your own set of permission for each role
**sendInvitationEmail**: `async (data) => Promise` - A function that sends an invitation email to the user.
-**invitationExpiresIn** : `number` - How long the invitation link is valid for in seconds. By default, it's 48 hours (2 days).
\ No newline at end of file
+**invitationExpiresIn** : `number` - How long the invitation link is valid for in seconds. By default, it's 48 hours (2 days).
+
diff --git a/docs/content/docs/plugins/passkey.mdx b/docs/content/docs/plugins/passkey.mdx
index 444acdc4..889e3c54 100644
--- a/docs/content/docs/plugins/passkey.mdx
+++ b/docs/content/docs/plugins/passkey.mdx
@@ -97,6 +97,70 @@ Signin method accepts:
const data = await client.signIn.passkey()
```
+## Schema
+
+The plugin require a new table in the database to store passkey data.
+
+Table Name: `passkey`
+
+
+
## Options
diff --git a/docs/content/docs/plugins/rate-limit.mdx b/docs/content/docs/plugins/rate-limit.mdx
deleted file mode 100644
index 5c4cad38..00000000
--- a/docs/content/docs/plugins/rate-limit.mdx
+++ /dev/null
@@ -1,212 +0,0 @@
----
-title: Rate Limiter
-description: better auth rate limit plugin
----
-
-The rate limit plugin allows you to limit the number of requests a user can make to the server in a given time period.
-
-## Installation
-
-
-
- ### Add the plugin to your auth config
-
- Add the rate limit plugin to your auth configuration and pass `enabled` to `true` to enable rate limiting.
-
- ```ts title="auth.ts"
- import { betterAuth } from "better-auth"
- import { rateLimiter } from "better-auth/plugins"
-
- export const auth = await betterAuth({
- //... other config options
- plugins: [
- rateLimit({ // [!code highlight]
- enabled: true, // [!code highlight]
- }), // [!code highlight]
- ],
- })
- ```
-
-
- ### Migrate your database (optional)
- If you are using the default database storage, you need to run the migration to add the required fields to the rate limit table.
-
- This will add the following fields to the **rateLimit** table:
- - `key`: The key used for rate limiting.
- - `count`: The number of requests made in the given time window.
- - `lastRequest`: The timestamp of the last request made.
-
-
- You can change the table name by providing table name on the storage configuration of the rate limit plugin.
-
-
- ```bash
- npx better-auth migrate
- ```
-
-
-
-## Configuration
-
-The rate limit plugin accepts the following options:
-
-### Enabled
-
-enable rate limiting. You can also pass a function to enable rate limiting for specific endpoints.
-
-```ts title="auth.ts"
-
-import { betterAuth } from "better-auth"
-import { rateLimiter } from "better-auth/plugins"
-
-export const auth = await betterAuth({
- //
- plugins: [
- rateLimit({
- enabled: true, // [!code highlight]
- }), // [!code highlight]
- ],
-})
-```
-
-### Window
-
-The time window in seconds for which the rate limit is enforced. Default is 15 minutes (15 * 60).
-
-```ts title="auth.ts"
-import { betterAuth } from "better-auth"
-import { rateLimiter } from "better-auth/plugins"
-
-export const auth = await betterAuth({
- //
- plugins: [
- rateLimit({
- enabled: true,
- window: 60 * 10, // [!code highlight]
- }),
- ],
-})
-```
-
-### Max
-
-The maximum number of requests a user can make in the given time window. Default is 100.
-
-```ts title="auth.ts"
-import { betterAuth } from "better-auth"
-import { rateLimiter } from "better-auth/plugins"
-
-export const auth = await betterAuth({
- //
- plugins: [
- rateLimit({
- enabled: true,
- window: 60 * 10,
- max: 50, // [!code highlight]
- }),
- ],
-})
-```
-
-### Get Key
-
-A function that returns the key to use for rate limiting. By default, it uses the user's IP address if the user is not authenticated and the user's ID if the user is authenticated.
-
-```ts title="auth.ts"
-import { betterAuth } from "better-auth"
-import { rateLimiter } from "better-auth/plugins"
-
-export const auth = await betterAuth({
- //
- plugins: [
- rateLimit({
- enabled: true,
- window: 60 * 10,
- max: 50,
- getKey: (req) => req.headers['x-forwarded-for'] || req.connection.remoteAddress, // [!code highlight]
- }),
- ],
-})
-```
-
-### Storage
-
-The storage to use for rate limiting. By default, it uses database storage.
-
-```ts title="auth.ts"
-import { betterAuth } from "better-auth"
-import { rateLimiter } from "better-auth/plugins"
-
-export const auth = await betterAuth({
- //
- plugins: [
- rateLimit({
- enabled: true,
- window: 60 * 10,
- max: 50,
- getKey: (req) => req.headers['x-forwarded-for'] || req.connection.remoteAddress,
- storage: { // [!code highlight]
- provider: "memeory" // [!code highlight]
- }, // [!code highlight]
- }),
- ],
-})
-```
-
-#### Custom Storage
-
-You can also pass a custom storage provider to the rate limit plugin.
-
-```ts title="auth.ts"
-import { betterAuth } from "better-auth"
-import { rateLimiter } from "better-auth/plugins"
-
-export const auth = await betterAuth({
- //
- plugins: [
- rateLimit({
- enabled: true,
- window: 60 * 10,
- max: 50,
- getKey: (req) => req.headers['x-forwarded-for'] || req.connection.remoteAddress,
- storage: { // [!code highlight]
- provider: "custom", // [!code highlight]
- customStorage: { // [!code highlight]
- get: async (key) => {}, // [!code highlight]
- set: async (key, value) => {}, // [!code highlight]
- }, // [!code highlight]
- }, // [!code highlight]
- }),
- ],
-})
-```
-
-### Sepcial Rules
-
-Special rules are rules that allows yous to define custom rate limit counter for specific paths.
-By default, `sign-in` and `sign-up` paths are rate limited have a count of `2` for each request as supposed to the default `1` for other paths.
-
-`matcher`: A function that returns a boolean value indicating whether the rule should be applied to the given path.
-
-`countValue`: The number of requests allowed for the given path.
-
-```ts title="auth.ts"
-import { betterAuth } from "better-auth"
-import { rateLimiter } from "better-auth/plugins"
-
-export const auth = await betterAuth({
- //
- plugins: [
- rateLimit({
- specialRules: specialRules: [
- {
- matcher(path) {
- return path.startsWith("/sign-in") || path.startsWith("/sign-up");
- },
- countValue: 2,
- },
- ],
- }),
- ],
-})
-```
\ No newline at end of file
diff --git a/docs/content/docs/plugins/username.mdx b/docs/content/docs/plugins/username.mdx
index f388e98a..2c89b583 100644
--- a/docs/content/docs/plugins/username.mdx
+++ b/docs/content/docs/plugins/username.mdx
@@ -111,6 +111,21 @@ const data = await client.signIn.username({
})
```
+## Schema
+
+The plugin requires 1 field to be added to the user table:
+
+
+
## Options
The username plugin doesn't require any configuration. It just needs to be added to the server and client.
diff --git a/docs/mdx-components.tsx b/docs/mdx-components.tsx
index 488a7c7a..4f1a6c83 100644
--- a/docs/mdx-components.tsx
+++ b/docs/mdx-components.tsx
@@ -10,6 +10,7 @@ import { Popup, PopupContent, PopupTrigger } from "fumadocs-ui/twoslash/popup";
import { TypeTable } from "fumadocs-ui/components/type-table";
import { Features } from "./components/blocks/features";
import { ForkButton } from "./components/fork-button";
+import DatabaseTable from "./components/mdx/database-tables";
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
@@ -33,6 +34,7 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
TypeTable,
Features,
ForkButton,
+ DatabaseTable,
iframe: (props) => ,
};
}
diff --git a/packages/better-auth/package.json b/packages/better-auth/package.json
index 8ab3095f..88dba5eb 100644
--- a/packages/better-auth/package.json
+++ b/packages/better-auth/package.json
@@ -6,7 +6,9 @@
"scripts": {
"build": "NODE_OPTIONS='--max-old-space-size=16384' tsup --clean --minify",
"dev": "NODE_OPTIONS='--max-old-space-size=16384' tsup --watch --sourcemap",
- "test": "pnpm typecheck && vitest",
+ "test": "pnpm prisma:push && pnpm typecheck && vitest",
+ "prisma:push": "prisma db push --schema src/adapters/prisma-adapter/schema.prisma",
+ "test:adapters": "pnpm prisma:push && vitest adapters",
"bump": "bumpp",
"typecheck": "tsc --noEmit"
},
@@ -53,10 +55,13 @@
"@types/pg": "^8.11.6",
"@types/prompts": "^2.4.9",
"@types/react": "^18.3.3",
+ "drizzle-orm": "^0.33.0",
"happy-dom": "^15.7.3",
"hono": "^4.5.4",
"listhen": "^1.7.2",
+ "mongodb": "^6.9.0",
"next": "^14.2.8",
+ "prisma": "^5.19.1",
"react": "^18.3.1",
"solid-js": "^1.8.18",
"tsup": "^8.2.4",
diff --git a/packages/better-auth/src/adapters/drizzzle-adapter/index.ts b/packages/better-auth/src/adapters/drizzzle-adapter/index.ts
new file mode 100644
index 00000000..c1346a0b
--- /dev/null
+++ b/packages/better-auth/src/adapters/drizzzle-adapter/index.ts
@@ -0,0 +1,119 @@
+import { and, eq, or, SQL } from "drizzle-orm";
+import type { Adapter, Where } from "../../types";
+
+export interface DrizzleAdapterOptions<
+ T extends Record = Record,
+> {
+ db: T;
+ schema: Record;
+}
+
+function getSchema(modelName: string, schema: Record) {
+ const key = Object.keys(schema).find((key) => {
+ const modelName = schema[key].name;
+ return modelName === modelName;
+ });
+ if (!key) {
+ throw new Error("Model not found");
+ }
+ return schema[key];
+}
+
+function whereConvertor(where: Where[], schemaModel: any) {
+ if (!where) return [];
+ if (where.length === 1) {
+ const w = where[0];
+ if (!w) {
+ return [];
+ }
+ return [eq(schemaModel[w.field], w.value)];
+ }
+ const andGroup = where.filter((w) => w.connector === "AND" || !w.connector);
+ const orGroup = where.filter((w) => w.connector === "OR");
+
+ const andClause = and(
+ ...andGroup.map((w) => {
+ return eq(schemaModel[w.field], w.value);
+ }),
+ );
+ const orClause = or(
+ ...orGroup.map((w) => {
+ return eq(schemaModel[w.field], w.value);
+ }),
+ );
+ const clause: SQL[] = [];
+
+ if (andGroup.length) clause.push(andClause!);
+ if (orGroup.length) clause.push(orClause!);
+ return clause;
+}
+
+export const drizzleAdapter = ({
+ db,
+ schema,
+}: DrizzleAdapterOptions): Adapter => {
+ return {
+ async create(data) {
+ const { model, data: val } = data;
+ const schemaModel = getSchema(model, schema);
+ const res = await db.insert(schemaModel).values(val).returning();
+ return res[0];
+ },
+ async findOne(data) {
+ const { model, where, select: included } = data;
+ const schemaModel = getSchema(model, schema);
+ const wheres = whereConvertor(where, schemaModel);
+
+ let res = null;
+ if (!!included?.length) {
+ res = await db
+ .select(
+ ...included.map((include) => {
+ return {
+ [include]: schemaModel[include],
+ };
+ }),
+ )
+ .from(schemaModel)
+ .where(...wheres);
+ } else {
+ res = await db
+ .select()
+ .from(schemaModel)
+ .where(...wheres);
+ }
+
+ if (!!res.length) return res[0];
+ else return null;
+ },
+ async findMany(data) {
+ const { model, where } = data;
+ const schemaModel = getSchema(model, schema);
+ const wheres = where ? whereConvertor(where, schemaModel) : [];
+
+ return await db
+ .select()
+ .from(schemaModel)
+ .findMany(...wheres);
+ },
+ async update(data) {
+ const { model, where, update } = data;
+ const schemaModel = getSchema(model, schema);
+ const wheres = whereConvertor(where, schemaModel);
+ const res = await db
+ .update(schemaModel)
+ .set(update)
+ .where(...wheres)
+ .returning();
+ return res[0];
+ },
+ async delete(data) {
+ const { model, where } = data;
+ const schemaModel = getSchema(model, schema);
+ const wheres = whereConvertor(where, schemaModel);
+ const res = await db.delete(schemaModel).where(...wheres);
+
+ return res[0];
+ },
+ };
+};
diff --git a/packages/better-auth/src/adapters/drizzzle-adapter/test/adapter.dirzzle.test.ts b/packages/better-auth/src/adapters/drizzzle-adapter/test/adapter.dirzzle.test.ts
new file mode 100644
index 00000000..7922298f
--- /dev/null
+++ b/packages/better-auth/src/adapters/drizzzle-adapter/test/adapter.dirzzle.test.ts
@@ -0,0 +1,43 @@
+import fs from "fs/promises";
+import { afterAll, beforeAll, beforeEach, describe, it } from "vitest";
+
+import { user } from "./schema";
+import { runAdapterTest } from "../../test";
+import { drizzleAdapter } from "..";
+import { getTestInstance } from "../../../test-utils/test-instance";
+import { getMigrations } from "../../../cli/utils/get-migration";
+import path from "path";
+import { drizzle } from "drizzle-orm/better-sqlite3";
+import Database from "better-sqlite3";
+
+describe("adapter test", async () => {
+ beforeEach(async () => {
+ const { runMigrations } = await getMigrations({
+ database: {
+ provider: "sqlite",
+ url: path.join(__dirname, "test.db"),
+ },
+ });
+ await runMigrations();
+ });
+
+ afterAll(async () => {
+ await fs.unlink(path.join(__dirname, "test.db"));
+ });
+ const sqlite = new Database(path.join(__dirname, "test.db"));
+ const db = drizzle(sqlite, {
+ schema: {
+ user,
+ },
+ });
+
+ const adapter = drizzleAdapter({
+ db: db,
+ schema: {
+ user,
+ },
+ });
+ await runAdapterTest({
+ adapter,
+ });
+});
diff --git a/packages/better-auth/src/adapters/drizzzle-adapter/test/schema.ts b/packages/better-auth/src/adapters/drizzzle-adapter/test/schema.ts
new file mode 100644
index 00000000..0f341634
--- /dev/null
+++ b/packages/better-auth/src/adapters/drizzzle-adapter/test/schema.ts
@@ -0,0 +1,20 @@
+import { int, text } from "drizzle-orm/sqlite-core";
+import { sqliteTable } from "drizzle-orm/sqlite-core";
+import { drizzle } from "drizzle-orm/better-sqlite3";
+import Database from "better-sqlite3";
+import path from "path";
+
+export var user = sqliteTable("user", {
+ id: text("id").primaryKey().default(new Date().toISOString()),
+ name: text("name"),
+ email: text("email").unique(),
+ emailVerified: int("emailVerified", {
+ mode: "boolean",
+ }),
+ createdAt: int("createdAt", {
+ mode: "timestamp",
+ }),
+ updatedAt: int("updatedAt", {
+ mode: "timestamp",
+ }),
+});
diff --git a/packages/better-auth/src/adapters/index.ts b/packages/better-auth/src/adapters/index.ts
new file mode 100644
index 00000000..2ac26946
--- /dev/null
+++ b/packages/better-auth/src/adapters/index.ts
@@ -0,0 +1 @@
+export * from "./prisma-adapter";
diff --git a/packages/better-auth/src/adapters/mongodb-adpter/adapter.mongo-db.test.ts b/packages/better-auth/src/adapters/mongodb-adpter/adapter.mongo-db.test.ts
new file mode 100644
index 00000000..67089aff
--- /dev/null
+++ b/packages/better-auth/src/adapters/mongodb-adpter/adapter.mongo-db.test.ts
@@ -0,0 +1,29 @@
+import { describe, beforeAll } from "vitest";
+
+import { MongoClient } from "mongodb";
+import { runAdapterTest } from "../test";
+import { mongodbAdapter } from ".";
+
+describe("adapter test", async () => {
+ const dbClient = async (connectionString: string, dbName: string) => {
+ const client = new MongoClient(connectionString);
+ await client.connect();
+ const db = client.db(dbName);
+ return db;
+ };
+
+ const user = "user";
+ const db = await dbClient("mongodb://127.0.0.1:27017", "better-auth");
+ async function clearDb() {
+ await db.collection(user).deleteMany({});
+ }
+
+ beforeAll(async () => {
+ await clearDb();
+ });
+
+ const adapter = mongodbAdapter(db);
+ await runAdapterTest({
+ adapter,
+ });
+});
diff --git a/packages/better-auth/src/adapters/mongodb-adpter/index.ts b/packages/better-auth/src/adapters/mongodb-adpter/index.ts
new file mode 100644
index 00000000..de9f2b41
--- /dev/null
+++ b/packages/better-auth/src/adapters/mongodb-adpter/index.ts
@@ -0,0 +1,133 @@
+import type { Adapter, Where } from "../../types";
+
+function whereConvertor(where?: Where[]) {
+ if (!where) return {};
+ if (where.length === 1) {
+ const w = where[0];
+ if (!w) {
+ return;
+ }
+ return {
+ [w.field]: w.value,
+ };
+ }
+ const and = where.filter((w) => w.connector === "AND" || !w.connector);
+ const or = where.filter((w) => w.connector === "OR");
+
+ const andClause = and.map((w) => {
+ return {
+ [w.field]:
+ w.operator === "eq" || !w.operator
+ ? w.value
+ : {
+ [w.field]: w.value,
+ },
+ };
+ });
+ const orClause = or.map((w) => {
+ return {
+ [w.field]: w.value,
+ };
+ });
+
+ let clause = {};
+ if (andClause.length) {
+ clause = { ...clause, $and: andClause };
+ }
+ if (orClause.length) {
+ clause = { ...clause, $or: orClause };
+ }
+ return clause;
+}
+
+function removeMongoId(data: any) {
+ const { _id, ...rest } = data;
+ return rest;
+}
+
+function selectConvertor(selects: string[]) {
+ const selectConstruct = selects.reduce((acc, field) => {
+ //@ts-expect-error
+ acc[field] = 1;
+ return acc;
+ }, {});
+
+ return selectConstruct;
+}
+
+interface MongoClient {
+ collection: (model: string) => {
+ insertOne: (data: any) => Promise;
+ find: (
+ where: any,
+ select: any,
+ ) => {
+ toArray: () => any;
+ };
+ findMany: (where: any) => Promise;
+ findOneAndUpdate: (where: any, update: any, config: any) => Promise;
+ findOneAndDelete: (where: any) => Promise;
+ };
+}
+
+export const mongodbAdapter = (mongo: any) => {
+ const db: MongoClient = mongo;
+ return {
+ async create(data) {
+ const { model, data: val } = data;
+ const res = await db.collection(model).insertOne({
+ ...val,
+ });
+ const id_ = res.insertedId;
+ const returned = { id: id_, ...val };
+ return removeMongoId(returned);
+ },
+ async findOne(data) {
+ const { model, where, select } = data;
+ const wheres = whereConvertor(where);
+ let selects = {};
+ if (select) {
+ selects = selectConvertor(select);
+ }
+
+ const res = await db
+ .collection(model)
+ .find({ ...wheres }, { projection: selects })
+ .toArray();
+
+ const result = res[0];
+ if (!result) {
+ return null;
+ }
+
+ return removeMongoId(result);
+ },
+ async findMany(data) {
+ const { model, where } = data;
+ const wheres = whereConvertor(where);
+ const toReturn = await db.collection(model).findMany(wheres);
+ return removeMongoId(toReturn);
+ },
+ async update(data) {
+ const { model, where, update } = data;
+ const wheres = whereConvertor(where);
+
+ const res = await db.collection(model).findOneAndUpdate(
+ wheres,
+ {
+ $set: update,
+ },
+ { returnDocument: "after" },
+ );
+
+ return removeMongoId(res);
+ },
+ async delete(data) {
+ const { model, where } = data;
+ const wheres = whereConvertor(where);
+ const res = await db.collection(model).findOneAndDelete(wheres);
+
+ return res;
+ },
+ } satisfies Adapter;
+};
diff --git a/packages/better-auth/src/adapters/prisma-adapter/adapter.prisma.test.ts b/packages/better-auth/src/adapters/prisma-adapter/adapter.prisma.test.ts
new file mode 100644
index 00000000..8be471fe
--- /dev/null
+++ b/packages/better-auth/src/adapters/prisma-adapter/adapter.prisma.test.ts
@@ -0,0 +1,20 @@
+import { beforeAll, describe, it } from "vitest";
+import { PrismaClient } from "@prisma/client";
+import { prismaAdapter } from ".";
+import { runAdapterTest } from "../test";
+
+const db = new PrismaClient();
+
+describe("adapter test", async () => {
+ beforeAll(async () => {
+ await clearDb();
+ });
+ const adapter = prismaAdapter(db);
+ await runAdapterTest({
+ adapter,
+ });
+});
+
+async function clearDb() {
+ await db.user.deleteMany();
+}
diff --git a/packages/better-auth/src/adapters/prisma-adapter/client.ts b/packages/better-auth/src/adapters/prisma-adapter/client.ts
new file mode 100644
index 00000000..63f8bbdf
--- /dev/null
+++ b/packages/better-auth/src/adapters/prisma-adapter/client.ts
@@ -0,0 +1,4 @@
+import { PrismaClient } from "@prisma/client";
+
+const prisma = new PrismaClient();
+export default prisma;
diff --git a/packages/better-auth/src/adapters/prisma-adapter/index.ts b/packages/better-auth/src/adapters/prisma-adapter/index.ts
new file mode 100644
index 00000000..f29c260d
--- /dev/null
+++ b/packages/better-auth/src/adapters/prisma-adapter/index.ts
@@ -0,0 +1,111 @@
+import type { Adapter, Where } from "../../types";
+
+function whereConvertor(where?: Where[]) {
+ if (!where) return {};
+ if (where.length === 1) {
+ const w = where[0];
+ if (!w) {
+ return;
+ }
+ return {
+ [w.field]: w.value,
+ };
+ }
+ const and = where.filter((w) => w.connector === "AND" || !w.connector);
+ const or = where.filter((w) => w.connector === "OR");
+ const andClause = and.map((w) => {
+ return {
+ [w.field]:
+ w.operator === "eq" || !w.operator
+ ? w.value
+ : {
+ [w.operator]: w.value,
+ },
+ };
+ });
+ const orClause = or.map((w) => {
+ return {
+ [w.field]: {
+ [w.operator || "eq"]: w.value,
+ },
+ };
+ });
+
+ return {
+ AND: andClause.length ? andClause : undefined,
+ OR: orClause.length ? orClause : undefined,
+ };
+}
+
+interface PrismaClient {
+ [model: string]: {
+ create: (data: any) => Promise;
+ findFirst: (data: any) => Promise;
+ findMany: (data: any) => Promise;
+ update: (data: any) => Promise;
+ delete: (data: any) => Promise;
+ [key: string]: any;
+ };
+}
+
+export const prismaAdapter = (prisma: any): Adapter => {
+ const db: PrismaClient = prisma;
+ return {
+ async create(data) {
+ const { model, data: val, select } = data;
+
+ return await db[model].create({
+ data: val,
+ ...(select?.length
+ ? {
+ select: select.reduce((prev, cur) => {
+ return {
+ ...prev,
+ [cur]: true,
+ };
+ }, {}),
+ }
+ : {}),
+ });
+ },
+ async findOne(data) {
+ const { model, where, select } = data;
+ const whereClause = whereConvertor(where);
+
+ return await db[model].findFirst({
+ where: whereClause,
+ ...(select?.length
+ ? {
+ select: select.reduce((prev, cur) => {
+ return {
+ ...prev,
+ [cur]: true,
+ };
+ }, {}),
+ }
+ : {}),
+ });
+ },
+ async findMany(data) {
+ const { model, where } = data;
+ const whereClause = whereConvertor(where);
+
+ return await db[model].findMany({ where: whereClause });
+ },
+ async update(data) {
+ const { model, where, update } = data;
+ const whereClause = whereConvertor(where);
+
+ return await db[model].update({
+ where: whereClause,
+ data: update,
+ });
+ },
+ async delete(data) {
+ const { model, where } = data;
+ const whereClause = whereConvertor(where);
+
+ return await db[model].delete({ where: whereClause });
+ },
+ };
+};
diff --git a/packages/better-auth/src/adapters/prisma-adapter/schema.prisma b/packages/better-auth/src/adapters/prisma-adapter/schema.prisma
new file mode 100644
index 00000000..14b5beae
--- /dev/null
+++ b/packages/better-auth/src/adapters/prisma-adapter/schema.prisma
@@ -0,0 +1,17 @@
+generator client {
+ provider = "prisma-client-js"
+}
+
+datasource db {
+ provider = "sqlite"
+ url = "file:.db/dev.db"
+}
+
+model User {
+ id String @id @default(cuid())
+ email String @unique
+ emailVerified Boolean @default(false)
+ name String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @default(now()) @updatedAt
+}
diff --git a/packages/better-auth/src/adapters/test.ts b/packages/better-auth/src/adapters/test.ts
new file mode 100644
index 00000000..8f272306
--- /dev/null
+++ b/packages/better-auth/src/adapters/test.ts
@@ -0,0 +1,123 @@
+import { expect, test } from "vitest";
+import type { Adapter, User } from "../types";
+
+interface AdapterTestOptions {
+ adapter: Adapter;
+}
+
+export async function runAdapterTest(opts: AdapterTestOptions) {
+ const { adapter } = opts;
+ const user = {
+ id: "1",
+ name: "user",
+ email: "user@email.com",
+ emailVerified: true,
+ createdAt: new Date(),
+ updatedAt: new Date(),
+ };
+
+ test("create model", async () => {
+ const res = await adapter.create({
+ model: "user",
+ data: user,
+ });
+ expect({
+ name: res.name,
+ email: res.email,
+ }).toEqual({
+ name: user.name,
+ email: user.email,
+ });
+ });
+
+ test("find model", async () => {
+ const res = await adapter.findOne({
+ model: "user",
+ where: [
+ {
+ field: "id",
+ value: user.id,
+ },
+ ],
+ });
+ expect({
+ name: res?.name,
+ email: res?.email,
+ }).toEqual({
+ name: user.name,
+ email: user.email,
+ });
+ });
+
+ test("find model without id", async () => {
+ const res = await adapter.findOne({
+ model: "user",
+ where: [
+ {
+ field: "email",
+ value: user.email,
+ },
+ ],
+ });
+ expect({
+ name: res?.name,
+ email: res?.email,
+ }).toEqual({
+ name: user.name,
+ email: user.email,
+ });
+ });
+
+ test("find model with select", async () => {
+ const res = await adapter.findOne({
+ model: "user",
+ where: [
+ {
+ field: "id",
+ value: user.id,
+ },
+ ],
+ select: ["email"],
+ });
+ expect(res).toEqual({ email: user.email });
+ });
+
+ test("update model", async () => {
+ const newEmail = "updated@email.com";
+ const res = await adapter.update({
+ model: "user",
+ where: [
+ {
+ field: "id",
+ value: user.id,
+ },
+ ],
+ update: {
+ email: newEmail,
+ },
+ });
+ expect(res?.email).toEqual(newEmail);
+ });
+
+ test("delete model", async () => {
+ await adapter.delete({
+ model: "user",
+ where: [
+ {
+ field: "id",
+ value: user.id,
+ },
+ ],
+ });
+ const findRes = await adapter.findOne({
+ model: "user",
+ where: [
+ {
+ field: "id",
+ value: user.id,
+ },
+ ],
+ });
+ expect(findRes).toBeNull();
+ });
+}
diff --git a/packages/better-auth/src/db/internal-adapter.ts b/packages/better-auth/src/db/internal-adapter.ts
index d2e116e1..750734a6 100644
--- a/packages/better-auth/src/db/internal-adapter.ts
+++ b/packages/better-auth/src/db/internal-adapter.ts
@@ -4,11 +4,9 @@ import type { Adapter } from "../types/adapter";
import { getDate } from "../utils/date";
import { getAuthTables } from "./get-tables";
import type { Account, Session, User } from "./schema";
-import type { Kysely } from "kysely";
export const createInternalAdapter = (
adapter: Adapter,
- db: Kysely,
options: BetterAuthOptions,
) => {
const sessionExpiration = options.session?.expiresIn || 60 * 60 * 24 * 7; // 7 days
@@ -146,15 +144,16 @@ export const createInternalAdapter = (
});
return session;
},
- /**
- * @requires
- */
deleteSessions: async (userId: string) => {
- const sessions = await db
- .deleteFrom(tables.session.tableName)
- .where("userId", "=", userId)
- .execute();
- return sessions;
+ return await adapter.delete({
+ model: tables.session.tableName,
+ where: [
+ {
+ field: "userId",
+ value: userId,
+ },
+ ],
+ });
},
findUserByEmail: async (email: string) => {
const user = await adapter.findOne({
diff --git a/packages/better-auth/src/db/kysely.ts b/packages/better-auth/src/db/kysely.ts
index fd887735..79a612b1 100644
--- a/packages/better-auth/src/db/kysely.ts
+++ b/packages/better-auth/src/db/kysely.ts
@@ -234,12 +234,12 @@ export const kyselyAdapter = (
export const getDialect = (config: BetterAuthOptions) => {
if (!config.database) {
- return null;
+ return undefined;
}
if ("createDriver" in config.database) {
return config.database;
}
- let dialect: Dialect | null = null;
+ let dialect: Dialect | undefined = undefined;
if ("provider" in config.database) {
const provider = config.database.provider;
const connectionString = config.database?.url?.trim();
@@ -281,7 +281,7 @@ export const getDialect = (config: BetterAuthOptions) => {
export const createKyselyAdapter = (config: BetterAuthOptions) => {
const dialect = getDialect(config);
if (!dialect) {
- return null;
+ return dialect;
}
const db = new Kysely({
dialect,
diff --git a/packages/better-auth/src/db/utils.ts b/packages/better-auth/src/db/utils.ts
index 6fc63c70..de00fe07 100644
--- a/packages/better-auth/src/db/utils.ts
+++ b/packages/better-auth/src/db/utils.ts
@@ -9,6 +9,11 @@ export function getAdapter(options: BetterAuthOptions): Adapter {
if (!options.database) {
throw new BetterAuthError("Database configuration is required");
}
+
+ if ("create" in options.database) {
+ return options.database;
+ }
+
const db = createKyselyAdapter(options);
if (!db) {
throw new BetterAuthError("Failed to initialize database adapter");
diff --git a/packages/better-auth/src/init.ts b/packages/better-auth/src/init.ts
index eedb710e..225c69e9 100644
--- a/packages/better-auth/src/init.ts
+++ b/packages/better-auth/src/init.ts
@@ -18,7 +18,6 @@ import {
} from "./utils/cookies";
import { createLogger, logger } from "./utils/logger";
import { oAuthProviderList, oAuthProviders } from "./social-providers";
-import { BetterAuthError } from "./error/better-auth-error";
import { crossSubdomainCookies } from "./internal-plugins";
export const init = (opts: BetterAuthOptions) => {
@@ -30,9 +29,6 @@ export const init = (opts: BetterAuthOptions) => {
const internalPlugins = getInternalPlugins(options);
const adapter = getAdapter(options);
const db = createKyselyAdapter(options);
- if (!db) {
- throw new BetterAuthError("No database adapter found");
- }
const baseURL = getBaseURL(options.baseURL, options.basePath) || "";
const secret =
@@ -97,7 +93,7 @@ export const init = (opts: BetterAuthOptions) => {
},
},
adapter: adapter,
- internalAdapter: createInternalAdapter(adapter, db, options),
+ internalAdapter: createInternalAdapter(adapter, options),
createAuthCookie: createCookieGetter(options),
...context,
};
@@ -110,7 +106,7 @@ export type AuthContext = {
socialProviders: OAuthProvider[];
authCookies: BetterAuthCookies;
logger: ReturnType;
- db: Kysely;
+ db?: Kysely;
rateLimit: {
enabled: boolean;
window: number;
diff --git a/packages/better-auth/src/plugins/admin/index.ts b/packages/better-auth/src/plugins/admin/index.ts
new file mode 100644
index 00000000..66c793fe
--- /dev/null
+++ b/packages/better-auth/src/plugins/admin/index.ts
@@ -0,0 +1,37 @@
+import { z } from "zod";
+import { createAuthEndpoint } from "../../api";
+import type { BetterAuthPlugin } from "../../types";
+
+export const admin = ({
+ trustedOrigins,
+}: {
+ trustedOrigins?: string[];
+}) => {
+ return {
+ id: "admin",
+ endpoints: {
+ getAllUsers: createAuthEndpoint(
+ "/user",
+ {
+ method: "GET",
+ },
+ async () => {
+ return [];
+ },
+ ),
+ signIn: createAuthEndpoint(
+ "/admin/sign-in",
+ {
+ method: "POST",
+ body: z.object({
+ email: z.string().email(),
+ password: z.string(),
+ }),
+ },
+ async () => {},
+ ),
+ },
+ } satisfies BetterAuthPlugin;
+};
+
+//next js fetch -> baseURL -> fetch("/users")
diff --git a/packages/better-auth/src/types/options.ts b/packages/better-auth/src/types/options.ts
index 5cf36e5d..21c2f06e 100644
--- a/packages/better-auth/src/types/options.ts
+++ b/packages/better-auth/src/types/options.ts
@@ -4,6 +4,7 @@ import type { BetterAuthPlugin } from "./plugins";
import type { OAuthProviderList } from "./provider";
import type { SocialProviders } from "../social-providers";
import type { RateLimit } from "./models";
+import type { Adapter } from "./adapter";
export interface BetterAuthOptions {
/**
@@ -63,7 +64,8 @@ export interface BetterAuthOptions {
provider: "postgres" | "sqlite" | "mysql";
url: string;
}
- | Dialect;
+ | Dialect
+ | Adapter;
/**
* Email and password authentication
*/
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ec3b6ace..558764c5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1264,6 +1264,9 @@ importers:
'@types/react':
specifier: ^18.3.3
version: 18.3.9
+ drizzle-orm:
+ specifier: ^0.33.0
+ version: 0.33.0(@prisma/client@5.20.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/react@18.3.9)(better-sqlite3@11.3.0)(kysely@0.27.4)(mysql2@3.11.3)(pg@8.13.0)(prisma@5.20.0)(react@18.3.1)
happy-dom:
specifier: ^15.7.3
version: 15.7.4
@@ -1273,9 +1276,15 @@ importers:
listhen:
specifier: ^1.7.2
version: 1.8.0
+ mongodb:
+ specifier: ^6.9.0
+ version: 6.9.0
next:
specifier: ^14.2.8
version: 14.2.13(@babel/core@7.25.2)(react-dom@18.3.1)(react@18.3.1)
+ prisma:
+ specifier: ^5.19.1
+ version: 5.20.0
react:
specifier: ^18.3.1
version: 18.3.1
@@ -3452,7 +3461,7 @@ packages:
peerDependencies:
react-hook-form: ^7.0.0
dependencies:
- react-hook-form: 7.53.0(react@18.3.1)
+ react-hook-form: 7.53.0(react@19.0.0-rc-7771d3a7-20240827)
dev: false
/@humanwhocodes/config-array@0.13.0:
@@ -4171,6 +4180,12 @@ packages:
svelte: 4.2.19
dev: false
+ /@mongodb-js/saslprep@1.1.9:
+ resolution: {integrity: sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==}
+ dependencies:
+ sparse-bitfield: 3.0.3
+ dev: true
+
/@motionone/animation@10.18.0:
resolution: {integrity: sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==}
dependencies:
@@ -10156,9 +10171,19 @@ packages:
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
dev: false
+ /@types/webidl-conversions@7.0.3:
+ resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==}
+ dev: true
+
/@types/webxr@0.5.20:
resolution: {integrity: sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==}
+ /@types/whatwg-url@11.0.5:
+ resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==}
+ dependencies:
+ '@types/webidl-conversions': 7.0.3
+ dev: true
+
/@types/ws@8.5.12:
resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==}
dependencies:
@@ -12297,7 +12322,6 @@ packages:
/aws-ssl-profiles@1.1.2:
resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
engines: {node: '>= 6.0.0'}
- dev: false
/axe-core@4.10.0:
resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==}
@@ -12396,7 +12420,6 @@ packages:
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
- dev: false
/better-auth@0.0.4(react@18.3.1)(solid-js@1.9.1)(typescript@5.6.2)(vue@3.5.10):
resolution: {integrity: sha512-PR1bR6zbgNRkSHZAPQQEqaHpHMyASXwBU2IbDY60gDWJO72d3wBSCiOKQcSGJRxJ55O9jitHVMHqHcAtC0++0A==}
@@ -12482,7 +12505,6 @@ packages:
dependencies:
bindings: 1.5.0
prebuild-install: 7.1.2
- dev: false
/big-integer@1.6.52:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
@@ -12502,7 +12524,6 @@ packages:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
dependencies:
file-uri-to-path: 1.0.0
- dev: false
/birpc@0.2.17:
resolution: {integrity: sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==}
@@ -12532,7 +12553,6 @@ packages:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
- dev: false
/bluebird@3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
@@ -12623,6 +12643,11 @@ packages:
node-releases: 2.0.18
update-browserslist-db: 1.1.0(browserslist@4.24.0)
+ /bson@6.8.0:
+ resolution: {integrity: sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==}
+ engines: {node: '>=16.20.1'}
+ dev: true
+
/buffer-alloc-unsafe@1.1.0:
resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==}
dev: false
@@ -12652,7 +12677,6 @@ packages:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
- dev: false
/buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
@@ -12941,7 +12965,6 @@ packages:
/chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
- dev: false
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
@@ -14151,7 +14174,6 @@ packages:
engines: {node: '>=10'}
dependencies:
mimic-response: 3.1.0
- dev: false
/deep-eql@4.1.4:
resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
@@ -14191,7 +14213,6 @@ packages:
/deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
- dev: false
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -14279,7 +14300,6 @@ packages:
/denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
- dev: false
/depd@1.1.2:
resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
@@ -14315,7 +14335,6 @@ packages:
/detect-libc@2.0.3:
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
engines: {node: '>=8'}
- dev: false
/detect-node-es@1.1.0:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
@@ -14440,6 +14459,107 @@ packages:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
+ /drizzle-orm@0.33.0(@prisma/client@5.20.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(@types/react@18.3.9)(better-sqlite3@11.3.0)(kysely@0.27.4)(mysql2@3.11.3)(pg@8.13.0)(prisma@5.20.0)(react@18.3.1):
+ resolution: {integrity: sha512-SHy72R2Rdkz0LEq0PSG/IdvnT3nGiWuRk+2tXZQ90GVq/XQhpCzu/EFT3V2rox+w8MlkBQxifF8pCStNYnERfA==}
+ peerDependencies:
+ '@aws-sdk/client-rds-data': '>=3'
+ '@cloudflare/workers-types': '>=3'
+ '@electric-sql/pglite': '>=0.1.1'
+ '@libsql/client': '*'
+ '@neondatabase/serverless': '>=0.1'
+ '@op-engineering/op-sqlite': '>=2'
+ '@opentelemetry/api': ^1.4.1
+ '@planetscale/database': '>=1'
+ '@prisma/client': '*'
+ '@tidbcloud/serverless': '*'
+ '@types/better-sqlite3': '*'
+ '@types/pg': '*'
+ '@types/react': '>=18'
+ '@types/sql.js': '*'
+ '@vercel/postgres': '>=0.8.0'
+ '@xata.io/client': '*'
+ better-sqlite3: '>=7'
+ bun-types: '*'
+ expo-sqlite: '>=13.2.0'
+ knex: '*'
+ kysely: '*'
+ mysql2: '>=2'
+ pg: '>=8'
+ postgres: '>=3'
+ prisma: '*'
+ react: '>=18'
+ sql.js: '>=1'
+ sqlite3: '>=5'
+ peerDependenciesMeta:
+ '@aws-sdk/client-rds-data':
+ optional: true
+ '@cloudflare/workers-types':
+ optional: true
+ '@electric-sql/pglite':
+ optional: true
+ '@libsql/client':
+ optional: true
+ '@neondatabase/serverless':
+ optional: true
+ '@op-engineering/op-sqlite':
+ optional: true
+ '@opentelemetry/api':
+ optional: true
+ '@planetscale/database':
+ optional: true
+ '@prisma/client':
+ optional: true
+ '@tidbcloud/serverless':
+ optional: true
+ '@types/better-sqlite3':
+ optional: true
+ '@types/pg':
+ optional: true
+ '@types/react':
+ optional: true
+ '@types/sql.js':
+ optional: true
+ '@vercel/postgres':
+ optional: true
+ '@xata.io/client':
+ optional: true
+ better-sqlite3:
+ optional: true
+ bun-types:
+ optional: true
+ expo-sqlite:
+ optional: true
+ knex:
+ optional: true
+ kysely:
+ optional: true
+ mysql2:
+ optional: true
+ pg:
+ optional: true
+ postgres:
+ optional: true
+ prisma:
+ optional: true
+ react:
+ optional: true
+ sql.js:
+ optional: true
+ sqlite3:
+ optional: true
+ dependencies:
+ '@prisma/client': 5.20.0(prisma@5.20.0)
+ '@types/better-sqlite3': 7.6.11
+ '@types/pg': 8.11.10
+ '@types/react': 18.3.9
+ better-sqlite3: 11.3.0
+ kysely: 0.27.4
+ mysql2: 3.11.3
+ pg: 8.13.0
+ prisma: 5.20.0
+ react: 18.3.1
+ dev: true
+
/dset@3.1.4:
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
engines: {node: '>=4'}
@@ -14600,7 +14720,6 @@ packages:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
dependencies:
once: 1.4.0
- dev: false
/enhanced-resolve@5.17.1:
resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==}
@@ -15504,7 +15623,6 @@ packages:
/expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
- dev: false
/expand-tilde@1.2.2:
resolution: {integrity: sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==}
@@ -15699,7 +15817,6 @@ packages:
/file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
- dev: false
/filesize@3.6.1:
resolution: {integrity: sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==}
@@ -15943,7 +16060,6 @@ packages:
/fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
- dev: false
/fs-exists-sync@0.1.0:
resolution: {integrity: sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==}
@@ -16190,7 +16306,6 @@ packages:
resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==}
dependencies:
is-property: 1.0.2
- dev: false
/genfun@4.0.1:
resolution: {integrity: sha512-48yv1eDS5Qrz6cbSDBBik0u7jCgC/eA9eZrl9MIN1LfKzFTuGt6EHgr31YM8yT9cjb5BplXb4Iz3VtOYmgt8Jg==}
@@ -16331,7 +16446,6 @@ packages:
/github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
- dev: false
/github-slugger@2.0.0:
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
@@ -17010,11 +17124,9 @@ packages:
engines: {node: '>=0.10.0'}
dependencies:
safer-buffer: 2.1.2
- dev: false
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
- dev: false
/iferr@0.1.5:
resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==}
@@ -17092,7 +17204,6 @@ packages:
/ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
- dev: false
/ini@4.1.1:
resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==}
@@ -17461,7 +17572,6 @@ packages:
/is-property@1.0.2:
resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
- dev: false
/is-redirect@1.0.0:
resolution: {integrity: sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==}
@@ -17999,7 +18109,6 @@ packages:
/kysely@0.27.4:
resolution: {integrity: sha512-dyNKv2KRvYOQPLCAOCjjQuCk4YFd33BvGdf/o5bC7FiW+BB6snA81Zt+2wT9QDFzKqxKa5rrOmvlK/anehCcgA==}
engines: {node: '>=14.0.0'}
- dev: false
/language-subtag-registry@0.3.23:
resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
@@ -18241,7 +18350,6 @@ packages:
/long@5.2.3:
resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==}
- dev: false
/longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -18282,12 +18390,10 @@ packages:
/lru-cache@7.18.3:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
engines: {node: '>=12'}
- dev: false
/lru.min@1.1.1:
resolution: {integrity: sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==}
engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'}
- dev: false
/lucide-react@0.428.0(react@18.3.1):
resolution: {integrity: sha512-rGrzslfEcgqwh+TLBC5qJ8wvVIXhLvAIXVFKNHndYyb1utSxxn9rXOC+1CNJLi6yNOooyPqIs6+3YCp6uSiEvg==}
@@ -18702,6 +18808,10 @@ packages:
resolution: {integrity: sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==}
dev: false
+ /memory-pager@1.5.0:
+ resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
+ dev: true
+
/merge-anything@5.1.7:
resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==}
engines: {node: '>=12.13'}
@@ -19342,7 +19452,6 @@ packages:
/mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
- dev: false
/mini-svg-data-uri@1.4.4:
resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==}
@@ -19435,7 +19544,6 @@ packages:
/mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
- dev: false
/mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
@@ -19470,6 +19578,45 @@ packages:
svelte: 4.2.19
dev: false
+ /mongodb-connection-string-url@3.0.1:
+ resolution: {integrity: sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==}
+ dependencies:
+ '@types/whatwg-url': 11.0.5
+ whatwg-url: 13.0.0
+ dev: true
+
+ /mongodb@6.9.0:
+ resolution: {integrity: sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==}
+ engines: {node: '>=16.20.1'}
+ peerDependencies:
+ '@aws-sdk/credential-providers': ^3.188.0
+ '@mongodb-js/zstd': ^1.1.0
+ gcp-metadata: ^5.2.0
+ kerberos: ^2.0.1
+ mongodb-client-encryption: '>=6.0.0 <7'
+ snappy: ^7.2.2
+ socks: ^2.7.1
+ peerDependenciesMeta:
+ '@aws-sdk/credential-providers':
+ optional: true
+ '@mongodb-js/zstd':
+ optional: true
+ gcp-metadata:
+ optional: true
+ kerberos:
+ optional: true
+ mongodb-client-encryption:
+ optional: true
+ snappy:
+ optional: true
+ socks:
+ optional: true
+ dependencies:
+ '@mongodb-js/saslprep': 1.1.9
+ bson: 6.8.0
+ mongodb-connection-string-url: 3.0.1
+ dev: true
+
/motion@10.18.0:
resolution: {integrity: sha512-MVAZZmwM/cp77BrNe1TxTMldxRPjwBNHheU5aPToqT4rJdZxLiADk58H+a0al5jKLxkB0OdgNq6DiVn11cjvIQ==}
dependencies:
@@ -19531,7 +19678,6 @@ packages:
named-placeholders: 1.1.3
seq-queue: 0.0.5
sqlstring: 2.3.3
- dev: false
/mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
@@ -19545,7 +19691,6 @@ packages:
engines: {node: '>=12.0.0'}
dependencies:
lru-cache: 7.18.3
- dev: false
/nanoassert@1.1.0:
resolution: {integrity: sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==}
@@ -19588,7 +19733,6 @@ packages:
/napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
- dev: false
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@@ -19825,7 +19969,6 @@ packages:
engines: {node: '>=10'}
dependencies:
semver: 7.6.3
- dev: false
/node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
@@ -20725,12 +20868,10 @@ packages:
/pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
requiresBuild: true
- dev: false
optional: true
/pg-connection-string@2.7.0:
resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==}
- dev: false
/pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
@@ -20747,7 +20888,6 @@ packages:
pg: '>=8.0'
dependencies:
pg: 8.13.0
- dev: false
/pg-protocol@1.7.0:
resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==}
@@ -20761,7 +20901,6 @@ packages:
postgres-bytea: 1.0.0
postgres-date: 1.0.7
postgres-interval: 1.2.0
- dev: false
/pg-types@4.0.2:
resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==}
@@ -20792,13 +20931,11 @@ packages:
pgpass: 1.0.5
optionalDependencies:
pg-cloudflare: 1.1.1
- dev: false
/pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
dependencies:
split2: 4.2.0
- dev: false
/phenomenon@1.6.0:
resolution: {integrity: sha512-7h9/fjPD3qNlgggzm88cY58l9sudZ6Ey+UmZsizfhtawO6E3srZQXywaNm2lBwT72TbpHYRPy7ytIHeBUD/G0A==}
@@ -21267,7 +21404,6 @@ packages:
/postgres-array@2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
- dev: false
/postgres-array@3.0.2:
resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==}
@@ -21277,7 +21413,6 @@ packages:
/postgres-bytea@1.0.0:
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
engines: {node: '>=0.10.0'}
- dev: false
/postgres-bytea@3.0.0:
resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==}
@@ -21289,7 +21424,6 @@ packages:
/postgres-date@1.0.7:
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
engines: {node: '>=0.10.0'}
- dev: false
/postgres-date@2.1.0:
resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==}
@@ -21301,7 +21435,6 @@ packages:
engines: {node: '>=0.10.0'}
dependencies:
xtend: 4.0.2
- dev: false
/postgres-interval@3.0.0:
resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==}
@@ -21333,7 +21466,6 @@ packages:
simple-get: 4.0.1
tar-fs: 2.1.1
tunnel-agent: 0.6.0
- dev: false
/preferred-pm@4.0.0:
resolution: {integrity: sha512-gYBeFTZLu055D8Vv3cSPox/0iTPtkzxpLroSYYA7WXgRi31WCJ51Uyl8ZiPeUUjyvs2MBzK+S8v9JVUgHU/Sqw==}
@@ -21516,7 +21648,6 @@ packages:
dependencies:
end-of-stream: 1.4.4
once: 1.4.0
- dev: false
/pumpify@1.5.1:
resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
@@ -21634,7 +21765,6 @@ packages:
ini: 1.3.8
minimist: 1.2.8
strip-json-comments: 2.0.1
- dev: false
/react-codesandboxer@3.1.5:
resolution: {integrity: sha512-gao6ydAfVI9DlmxvXJb1poqWDZt4jCSi2DWvfUCLUBmJAxH8+DkoGtjrO3VJDjdwcCFvumWb+ztg3WxsvrsWJw==}
@@ -22035,7 +22165,6 @@ packages:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
- dev: false
/readable-stream@4.5.2:
resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==}
@@ -22643,7 +22772,6 @@ packages:
/safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
- dev: false
/satori@0.10.9:
resolution: {integrity: sha512-XU9EELUEZuioT4acLIpCXxHcFzrsC8muvg0MY28d+TlqwxbkTzBmWbw+3+hnCzXT7YZ0Qm8k3eXktDaEu+qmEw==}
@@ -22750,7 +22878,6 @@ packages:
/seq-queue@0.0.5:
resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==}
- dev: false
/serialize-javascript@6.0.2:
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
@@ -22948,7 +23075,6 @@ packages:
/simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
- dev: false
/simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
@@ -22956,7 +23082,6 @@ packages:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
- dev: false
/simple-git-hooks@2.11.1:
resolution: {integrity: sha512-tgqwPUMDcNDhuf1Xf6KTUsyeqGdgKMhzaH4PAZZuzguOgTl5uuyeYe/8mWgAr6IBxB5V06uqEf6Dy37gIWDtDg==}
@@ -23162,6 +23287,12 @@ packages:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
dev: false
+ /sparse-bitfield@3.0.3:
+ resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
+ dependencies:
+ memory-pager: 1.5.0
+ dev: true
+
/spdx-correct@3.2.0:
resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
dependencies:
@@ -23192,7 +23323,6 @@ packages:
/split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
- dev: false
/sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
@@ -23201,7 +23331,6 @@ packages:
/sqlstring@2.3.3:
resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==}
engines: {node: '>= 0.6'}
- dev: false
/ssri@4.1.6:
resolution: {integrity: sha512-WUbCdgSAMQjTFZRWvSPpauryvREEA+Krn19rx67UlJEJx/M192ZHxMmJXjZ4tkdFm+Sb0SXGlENeQVlA5wY7kA==}
@@ -23400,7 +23529,6 @@ packages:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
- dev: false
/stringify-entities@4.0.4:
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
@@ -23460,7 +23588,6 @@ packages:
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
- dev: false
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
@@ -23833,7 +23960,6 @@ packages:
mkdirp-classic: 0.5.3
pump: 3.0.2
tar-stream: 2.2.0
- dev: false
/tar-stream@1.6.2:
resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==}
@@ -23857,7 +23983,6 @@ packages:
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
- dev: false
/tar-stream@3.1.7:
resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
@@ -24104,6 +24229,13 @@ packages:
punycode: 2.3.1
dev: true
+ /tr46@4.1.1:
+ resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
+ engines: {node: '>=14'}
+ dependencies:
+ punycode: 2.3.1
+ dev: true
+
/tr46@5.0.0:
resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
engines: {node: '>=18'}
@@ -24257,7 +24389,6 @@ packages:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
dependencies:
safe-buffer: 5.2.1
- dev: false
/turbo-darwin-64@2.1.2:
resolution: {integrity: sha512-3TEBxHWh99h2yIzkuIigMEOXt/ItYQp0aPiJjPd1xN4oDcsKK5AxiFKPH9pdtfIBzYsY59kQhZiFj0ELnSP7Bw==}
@@ -25916,6 +26047,14 @@ packages:
engines: {node: '>=18'}
dev: false
+ /whatwg-url@13.0.0:
+ resolution: {integrity: sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==}
+ engines: {node: '>=16'}
+ dependencies:
+ tr46: 4.1.1
+ webidl-conversions: 7.0.0
+ dev: true
+
/whatwg-url@14.0.0:
resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
engines: {node: '>=18'}
@@ -26121,7 +26260,6 @@ packages:
/xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
- dev: false
/xxhash-wasm@1.0.2:
resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==}