From e1f934884e92ebffe75813268700ca5e012af7e5 Mon Sep 17 00:00:00 2001 From: Bereket Engida Date: Mon, 2 Sep 2024 22:55:01 +0300 Subject: [PATCH] fix: tests --- dev/svelte/package.json | 2 +- dev/svelte/src/routes/+page.svelte | 79 ---- dev/svelte/src/routes/+page.ts | 3 + dev/svelte/src/routes/load/+page.svelte | 5 + dev/svelte/src/routes/load/+page.ts | 19 + dev/svelte/vite.config.ts | 3 + docs/app/page.tsx | 22 +- .../blocks/features-section-demo-3.tsx | 129 ++++++ docs/components/landing/hero.tsx | 247 +++++----- docs/components/sidebar-content.tsx | 30 +- docs/components/ui/background-beams.tsx | 141 ++++++ docs/components/ui/background-boxes.tsx | 76 +++ docs/components/ui/cover.tsx | 52 +++ docs/components/ui/sparkles.tsx | 435 ++++++++++++++++++ docs/content/docs/integrations/hono.mdx | 73 +++ docs/content/docs/integrations/next.mdx | 157 +++++++ docs/content/docs/integrations/nuxt.mdx | 111 +++++ .../content/docs/integrations/solid-start.mdx | 64 +++ docs/content/docs/integrations/svelte-kit.mdx | 148 ++++++ docs/content/docs/introduction.mdx | 12 +- docs/content/docs/plugins/bearer.mdx | 21 + docs/content/docs/plugins/introduction.mdx | 10 - docs/content/docs/plugins/organization.mdx | 2 - docs/mdx-components.tsx | 2 + docs/next.config.mjs | 10 + docs/package.json | 8 +- docs/tailwind.config.js | 43 +- packages/better-auth/src/api/index.ts | 2 +- .../src/api/routes/credential.test.ts | 10 +- packages/better-auth/src/auth.ts | 5 +- .../src/cli/utils/get-migration.ts | 4 +- .../better-auth/src/client/client.test.ts | 13 +- .../src/plugins/bearer/bearer.test.ts | 2 +- .../src/test-utils/test-instance.ts | 11 +- packages/better-auth/src/utils/shim.ts | 57 ++- pnpm-lock.yaml | 305 +++++++++++- 36 files changed, 2035 insertions(+), 278 deletions(-) create mode 100644 dev/svelte/src/routes/+page.ts create mode 100644 dev/svelte/src/routes/load/+page.svelte create mode 100644 dev/svelte/src/routes/load/+page.ts create mode 100644 docs/components/blocks/features-section-demo-3.tsx create mode 100644 docs/components/ui/background-beams.tsx create mode 100644 docs/components/ui/background-boxes.tsx create mode 100644 docs/components/ui/cover.tsx create mode 100644 docs/components/ui/sparkles.tsx create mode 100644 docs/content/docs/integrations/hono.mdx create mode 100644 docs/content/docs/integrations/next.mdx create mode 100644 docs/content/docs/integrations/nuxt.mdx create mode 100644 docs/content/docs/integrations/solid-start.mdx create mode 100644 docs/content/docs/integrations/svelte-kit.mdx create mode 100644 docs/content/docs/plugins/bearer.mdx delete mode 100644 docs/content/docs/plugins/introduction.mdx diff --git a/dev/svelte/package.json b/dev/svelte/package.json index 433c3edd85..32638505ac 100644 --- a/dev/svelte/package.json +++ b/dev/svelte/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "private": true, "scripts": { - "dev": "vite dev --port 3000", + "dev": "vite dev", "build": "vite build", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", diff --git a/dev/svelte/src/routes/+page.svelte b/dev/svelte/src/routes/+page.svelte index 9b900ffe49..e69de29bb2 100644 --- a/dev/svelte/src/routes/+page.svelte +++ b/dev/svelte/src/routes/+page.svelte @@ -1,79 +0,0 @@ - - -
-
-
- {#if $session} -
-

- {$session?.user.name} -

-

- {$session?.user.email} -

- -
- {:else} - - {/if} -
-
-
- - diff --git a/dev/svelte/src/routes/+page.ts b/dev/svelte/src/routes/+page.ts new file mode 100644 index 0000000000..db0f35a8f0 --- /dev/null +++ b/dev/svelte/src/routes/+page.ts @@ -0,0 +1,3 @@ +export async function load(request: Request) { + return null; +} diff --git a/dev/svelte/src/routes/load/+page.svelte b/dev/svelte/src/routes/load/+page.svelte new file mode 100644 index 0000000000..ab6f6fc100 --- /dev/null +++ b/dev/svelte/src/routes/load/+page.svelte @@ -0,0 +1,5 @@ + diff --git a/dev/svelte/src/routes/load/+page.ts b/dev/svelte/src/routes/load/+page.ts new file mode 100644 index 0000000000..2b20429392 --- /dev/null +++ b/dev/svelte/src/routes/load/+page.ts @@ -0,0 +1,19 @@ +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; +} diff --git a/dev/svelte/vite.config.ts b/dev/svelte/vite.config.ts index 6b9eb5d390..4eb71fc11c 100644 --- a/dev/svelte/vite.config.ts +++ b/dev/svelte/vite.config.ts @@ -3,4 +3,7 @@ import { defineConfig } from "vite"; export default defineConfig({ plugins: [sveltekit()], + optimizeDeps: { + exclude: ["@node-rs/argon2", "@node-rs/bcrypt"], + }, }); diff --git a/docs/app/page.tsx b/docs/app/page.tsx index a70ca4b61d..e5f8687259 100644 --- a/docs/app/page.tsx +++ b/docs/app/page.tsx @@ -3,17 +3,19 @@ import { } from "better-auth/client"; import Section from '@/components/landing/section'; import Hero from '@/components/landing/hero'; import { Separator } from '@/components/ui/separator'; +import { FeaturesSectionDemo } from '@/components/blocks/features-section-demo-3'; export default function HomePage() { return ( -
- - -
+
+
+ +
+
); } diff --git a/docs/components/blocks/features-section-demo-3.tsx b/docs/components/blocks/features-section-demo-3.tsx new file mode 100644 index 0000000000..3de211b31b --- /dev/null +++ b/docs/components/blocks/features-section-demo-3.tsx @@ -0,0 +1,129 @@ +import React from "react"; +import { useId } from "react"; + +export function FeaturesSectionDemo() { + return ( +
+
+ {grid.map((feature) => ( +
+ +

+ {feature.title} +

+

+ {feature.description} +

+
+ ))} +
+
+ ); +} + +const grid = [ + { + title: "Framework Agnostic", + description: + "Supports your favorite frontend, backend and meta frameworks, including React, Vue, Svelte, Solid, Next.js, Nuxt.js, Hono, and more.", + }, + { + title: "Email & Password Authentication", + description: + "Builtin support for email and password authentication, with secure password hashing and account management features.", + }, + { + title: "Social Sign-on", + description: + "Allow users to sign in with their accounts, including Github, Google, Discord, Twitter, and more.", + }, + { + title: "Two Factor", + description: + "Add an extra layer of security with two-factor authentication, including TOTP and SMS.", + }, + { + title: "Organization & Access Control", + description: + "Manage users and their access to resources within your application.", + }, + { + title: "Plugin Ecosystem", + description: + "Enhance your application with our official plugins and those created by the community.", + }, +]; + +export const Grid = ({ + pattern, + size, +}: { + pattern?: number[][]; + size?: number; +}) => { + const p = pattern ?? [ + [Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1], + [Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1], + [Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1], + [Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1], + [Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1], + ]; + return ( +
+
+ +
+
+ ); +}; + +export function GridPattern({ width, height, x, y, squares, ...props }: any) { + const patternId = useId(); + + return ( + + ); +} diff --git a/docs/components/landing/hero.tsx b/docs/components/landing/hero.tsx index ce72e64084..df45e54f2b 100644 --- a/docs/components/landing/hero.tsx +++ b/docs/components/landing/hero.tsx @@ -9,6 +9,7 @@ import { Highlight, themes } from "prism-react-renderer"; import { Fragment, useEffect, useId, useState } from "react"; import { LayoutGroup, motion } from "framer-motion" import { Icons } from "../icons"; +import { Cover } from "../ui/cover"; function Glow() { @@ -92,146 +93,148 @@ export default function Hero() { return (
-
-
-
-
-
-
-

- BETTER-AUTH. +

+
+
+
+
+ +

+ Better Auth.

-
+ +
-

- Framework agnostic, comprehensive authentication library and ecosystem for typescript. -

+

+ Framework agnostic, comprehensive authentication solution with a plugin ecosystem for typescript. +

+ + +
+ + -
- - - - -
+
-
-
- {/*
+
+
+ {/*
*/} - - + -
-
-
- + className="relative rounded-sm bg-gradient-to-tr from-stone-100 to-stone-200 dark:from-stone-950/70 dark:to-stone-900/90 ring-1 ring-white/10 backdrop-blur-lg"> +
+
+
+ -
+
- {tabs.map((tab) => ( - setActiveTab(tab.name)} + {tabs.map((tab) => ( + setActiveTab(tab.name)} + className={clsx( + "flex h-6 rounded-full cursor-pointer", + activeTab === tab.name + ? "bg-gradient-to-r from-stone-400/90 via-stone-400 to-orange-400/20 p-px font-medium text-stone-300" + : "text-slate-500", + )} + > +
-
- {tab.name} -
- - ))} + {tab.name} +
+
+ ))} -
- -
- - - {({ - className, - style, - tokens, - getLineProps, - getTokenProps, - }) => ( -
-                                                            
-                                                                {tokens.map((line, lineIndex) => (
-                                                                    
- {line.map((token, tokenIndex) => ( - - ))} -
- ))} -
-
- )} -
-
- - -
+
+ + + {({ + className, + style, + tokens, + getLineProps, + getTokenProps, + }) => ( +
+                                                        
+                                                            {tokens.map((line, lineIndex) => (
+                                                                
+ {line.map((token, tokenIndex) => ( + + ))} +
+ ))} +
+
+ )} +
+
+
+ + +
diff --git a/docs/components/sidebar-content.tsx b/docs/components/sidebar-content.tsx index a78b2c186b..2950445c1e 100644 --- a/docs/components/sidebar-content.tsx +++ b/docs/components/sidebar-content.tsx @@ -260,11 +260,6 @@ export const contents: Content[] = [ href: "/docs/integrations", icon: LucideAArrowDown }, - { - title: "Hono", - icon: Icons.hono, - href: "/docs/integrations/hono", - }, { title: "Next", icon: Icons.nextJS, @@ -280,16 +275,16 @@ export const contents: Content[] = [ icon: Icons.svelteKit, href: "/docs/integrations/svelte-kit", }, + { + title: "Hono", + icon: Icons.hono, + href: "/docs/integrations/hono", + }, { title: "Solid Start", icon: Icons.solidStart, href: "/docs/integrations/solid-start", }, - { - title: "React", - icon: Icons.react, - href: "/docs/integrations/react", - }, ] }, { @@ -311,13 +306,7 @@ export const contents: Content[] = [ ), list: [ - { - title: "Introduction", - icon: () => ( - - ), - href: "/docs/plugins/introduction", - }, + { title: "Authentication", group: true, @@ -361,12 +350,7 @@ export const contents: Content[] = [ { title: "Bearer", icon: Key, - href: "/docs/plugins/email-verifier", - }, - { - title: "Email Checker", - icon: MailCheck, - href: "/docs/plugins/email-verifier", + href: "/docs/plugins/bearer", }, ], }, diff --git a/docs/components/ui/background-beams.tsx b/docs/components/ui/background-beams.tsx new file mode 100644 index 0000000000..116c47ed3d --- /dev/null +++ b/docs/components/ui/background-beams.tsx @@ -0,0 +1,141 @@ +"use client"; +import React from "react"; +import { motion } from "framer-motion"; +import { cn } from "@/lib/utils"; + +export const BackgroundBeams = React.memo( + ({ className }: { className?: string }) => { + const paths = [ + "M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875", + "M-373 -197C-373 -197 -305 208 159 335C623 462 691 867 691 867", + "M-366 -205C-366 -205 -298 200 166 327C630 454 698 859 698 859", + "M-359 -213C-359 -213 -291 192 173 319C637 446 705 851 705 851", + "M-352 -221C-352 -221 -284 184 180 311C644 438 712 843 712 843", + "M-345 -229C-345 -229 -277 176 187 303C651 430 719 835 719 835", + "M-338 -237C-338 -237 -270 168 194 295C658 422 726 827 726 827", + "M-331 -245C-331 -245 -263 160 201 287C665 414 733 819 733 819", + "M-324 -253C-324 -253 -256 152 208 279C672 406 740 811 740 811", + "M-317 -261C-317 -261 -249 144 215 271C679 398 747 803 747 803", + "M-310 -269C-310 -269 -242 136 222 263C686 390 754 795 754 795", + "M-303 -277C-303 -277 -235 128 229 255C693 382 761 787 761 787", + "M-296 -285C-296 -285 -228 120 236 247C700 374 768 779 768 779", + "M-289 -293C-289 -293 -221 112 243 239C707 366 775 771 775 771", + "M-282 -301C-282 -301 -214 104 250 231C714 358 782 763 782 763", + "M-275 -309C-275 -309 -207 96 257 223C721 350 789 755 789 755", + "M-268 -317C-268 -317 -200 88 264 215C728 342 796 747 796 747", + "M-261 -325C-261 -325 -193 80 271 207C735 334 803 739 803 739", + "M-254 -333C-254 -333 -186 72 278 199C742 326 810 731 810 731", + "M-247 -341C-247 -341 -179 64 285 191C749 318 817 723 817 723", + "M-240 -349C-240 -349 -172 56 292 183C756 310 824 715 824 715", + "M-233 -357C-233 -357 -165 48 299 175C763 302 831 707 831 707", + "M-226 -365C-226 -365 -158 40 306 167C770 294 838 699 838 699", + "M-219 -373C-219 -373 -151 32 313 159C777 286 845 691 845 691", + "M-212 -381C-212 -381 -144 24 320 151C784 278 852 683 852 683", + "M-205 -389C-205 -389 -137 16 327 143C791 270 859 675 859 675", + "M-198 -397C-198 -397 -130 8 334 135C798 262 866 667 866 667", + "M-191 -405C-191 -405 -123 0 341 127C805 254 873 659 873 659", + "M-184 -413C-184 -413 -116 -8 348 119C812 246 880 651 880 651", + "M-177 -421C-177 -421 -109 -16 355 111C819 238 887 643 887 643", + "M-170 -429C-170 -429 -102 -24 362 103C826 230 894 635 894 635", + "M-163 -437C-163 -437 -95 -32 369 95C833 222 901 627 901 627", + "M-156 -445C-156 -445 -88 -40 376 87C840 214 908 619 908 619", + "M-149 -453C-149 -453 -81 -48 383 79C847 206 915 611 915 611", + "M-142 -461C-142 -461 -74 -56 390 71C854 198 922 603 922 603", + "M-135 -469C-135 -469 -67 -64 397 63C861 190 929 595 929 595", + "M-128 -477C-128 -477 -60 -72 404 55C868 182 936 587 936 587", + "M-121 -485C-121 -485 -53 -80 411 47C875 174 943 579 943 579", + "M-114 -493C-114 -493 -46 -88 418 39C882 166 950 571 950 571", + "M-107 -501C-107 -501 -39 -96 425 31C889 158 957 563 957 563", + "M-100 -509C-100 -509 -32 -104 432 23C896 150 964 555 964 555", + "M-93 -517C-93 -517 -25 -112 439 15C903 142 971 547 971 547", + "M-86 -525C-86 -525 -18 -120 446 7C910 134 978 539 978 539", + "M-79 -533C-79 -533 -11 -128 453 -1C917 126 985 531 985 531", + "M-72 -541C-72 -541 -4 -136 460 -9C924 118 992 523 992 523", + "M-65 -549C-65 -549 3 -144 467 -17C931 110 999 515 999 515", + "M-58 -557C-58 -557 10 -152 474 -25C938 102 1006 507 1006 507", + "M-51 -565C-51 -565 17 -160 481 -33C945 94 1013 499 1013 499", + "M-44 -573C-44 -573 24 -168 488 -41C952 86 1020 491 1020 491", + "M-37 -581C-37 -581 31 -176 495 -49C959 78 1027 483 1027 483", + ]; + return ( +
+ + + + {paths.map((path, index) => ( + + ))} + + {paths.map((path, index) => ( + + + + + + + ))} + + + + + + + + +
+ ); + } +); + +BackgroundBeams.displayName = "BackgroundBeams"; diff --git a/docs/components/ui/background-boxes.tsx b/docs/components/ui/background-boxes.tsx new file mode 100644 index 0000000000..6b7a868d6e --- /dev/null +++ b/docs/components/ui/background-boxes.tsx @@ -0,0 +1,76 @@ +"use client"; +import React from "react"; +import { motion } from "framer-motion"; +import { cn } from "@/lib/utils"; + +export const BoxesCore = ({ className, ...rest }: { className?: string }) => { + const rows = new Array(150).fill(1); + const cols = new Array(100).fill(1); + let colors = [ + "--sky-300", + "--pink-300", + "--green-300", + "--yellow-300", + "--red-300", + "--purple-300", + "--blue-300", + "--indigo-300", + "--violet-300", + ]; + const getRandomColor = () => { + return colors[Math.floor(Math.random() * colors.length)]; + }; + + return ( +
+ {rows.map((_, i) => ( + + {cols.map((_, j) => ( + + {j % 2 === 0 && i % 2 === 0 ? ( + + + + ) : null} + + ))} + + ))} +
+ ); +}; + +export const Boxes = React.memo(BoxesCore); diff --git a/docs/components/ui/cover.tsx b/docs/components/ui/cover.tsx new file mode 100644 index 0000000000..2cd4f000de --- /dev/null +++ b/docs/components/ui/cover.tsx @@ -0,0 +1,52 @@ +"use client"; +import React, { useEffect, useId, useState } from "react"; +import { AnimatePresence, motion } from "framer-motion"; +import { useRef } from "react"; +import { cn } from "@/lib/utils"; +import { SparklesCore } from "@/components/ui/sparkles"; + +export const Cover = ({ + children, + className, +}: { + children?: React.ReactNode; + className?: string; +}) => { + return ( +
+ + {children} + + + + + +
+ ); +}; + + + +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" + +``` + 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: {}