From 5205d276ae26ff9d8348f9a9bcf58d847a2cb001 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Thu, 9 Apr 2026 17:29:33 -0500 Subject: [PATCH 1/3] feat(react): add react integration package (@aura-stack/react) --- .vscode/settings.json | 24 +++- apps/astro/package.json | 1 + apps/astro/src/@types/types.ts | 2 +- apps/astro/src/components/auth-client.tsx | 12 +- apps/astro/src/components/header.tsx | 10 +- apps/astro/src/contexts/auth.tsx | 64 +-------- .../src/lib/{client.ts => auth-client.ts} | 0 apps/nextjs/app-router/package.json | 1 + apps/nextjs/app-router/src/app/layout.tsx | 4 +- .../app-router/src/components/auth-client.tsx | 15 +- .../app-router/src/components/header.tsx | 7 +- apps/nextjs/app-router/src/contexts/auth.tsx | 75 +--------- apps/nextjs/pages-router/package.json | 1 + .../src/components/auth-client.tsx | 9 +- .../pages-router/src/components/header.tsx | 7 +- .../nextjs/pages-router/src/contexts/auth.tsx | 76 +---------- apps/nextjs/pages-router/src/pages/_app.tsx | 2 +- .../app/components/auth-client.tsx | 9 +- apps/react-router/app/components/header.tsx | 7 +- apps/react-router/app/contexts/auth.tsx | 62 +-------- apps/react-router/app/routes/auth-layout.tsx | 2 +- apps/react-router/package.json | 1 + apps/react-router/tsconfig.json | 1 - apps/tanstack-start/package.json | 1 + .../src/components/auth-client.tsx | 9 +- apps/tanstack-start/src/components/header.tsx | 5 +- apps/tanstack-start/src/contexts/auth.tsx | 62 +-------- apps/tanstack-start/tsconfig.json | 1 - packages/core/src/@types/utility.ts | 5 +- packages/core/src/index.ts | 2 + packages/jose/tsconfig.json | 1 - packages/react/package.json | 67 +++++++++ packages/react/src/context.tsx | 128 ++++++++++++++++++ packages/react/src/hooks.ts | 82 +++++++++++ packages/react/src/index.ts | 3 + packages/react/src/types.ts | 60 ++++++++ packages/react/tsconfig.json | 13 ++ packages/react/tsup.config.ts | 10 ++ pnpm-lock.yaml | 36 ++++- 39 files changed, 506 insertions(+), 371 deletions(-) rename apps/astro/src/lib/{client.ts => auth-client.ts} (100%) create mode 100644 packages/react/package.json create mode 100644 packages/react/src/context.tsx create mode 100644 packages/react/src/hooks.ts create mode 100644 packages/react/src/index.ts create mode 100644 packages/react/src/types.ts create mode 100644 packages/react/tsconfig.json create mode 100644 packages/react/tsup.config.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 985e77b2..7c85b364 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,27 @@ { "editor.formatOnSave": true, "oxc.fmt.configPath": ".oxfmtrc.json", - "editor.defaultFormatter": "oxc.oxc-vscode" + "editor.defaultFormatter": "oxc.oxc-vscode", + "editor.formatOnSaveMode": "file", + "[javascript]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[json]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[mdx]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[md]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + } } diff --git a/apps/astro/package.json b/apps/astro/package.json index d0297381..dc7213f3 100644 --- a/apps/astro/package.json +++ b/apps/astro/package.json @@ -17,6 +17,7 @@ "@astrojs/node": "^10.0.2", "@astrojs/react": "^5.0.0", "@aura-stack/auth": "workspace:*", + "@aura-stack/react": "workspace:*", "@radix-ui/react-slot": "^1.2.4", "astro": "^6.0.5", "lucide-react": "catalog:lucide-react", diff --git a/apps/astro/src/@types/types.ts b/apps/astro/src/@types/types.ts index 63d2ea67..5fad8d84 100644 --- a/apps/astro/src/@types/types.ts +++ b/apps/astro/src/@types/types.ts @@ -1,4 +1,4 @@ -import type { authClient } from "@/lib/client" +import type { authClient } from "@/lib/auth-client" import type { Session } from "@aura-stack/auth" export interface AuthContextValue { diff --git a/apps/astro/src/components/auth-client.tsx b/apps/astro/src/components/auth-client.tsx index 2aae38d9..dcac798e 100644 --- a/apps/astro/src/components/auth-client.tsx +++ b/apps/astro/src/components/auth-client.tsx @@ -1,10 +1,12 @@ import { LayoutDashboard } from "lucide-react" -import { useAuth, AuthProvider } from "@/contexts/auth" import { Button } from "@/components/ui/button" +import { useAuth } from "@aura-stack/react" +import { AuthProvider } from "@/contexts/auth" import type { Session } from "@aura-stack/auth" const AuthClientContent = () => { - const { session, isAuthenticated, isLoading, signIn, signOut } = useAuth() + const { session, status, isPending, signIn, signOut } = useAuth() + const isAuthenticated = status === "authenticated" return (
@@ -34,7 +36,7 @@ const AuthClientContent = () => { {session?.user?.sub}
- @@ -54,7 +56,7 @@ const AuthClientContent = () => { className="w-full rounded-none" variant="outline" size="sm" - disabled={isLoading} + disabled={isPending} onClick={() => signIn(provider.toLowerCase())} > Sign In with {provider} @@ -72,7 +74,7 @@ const AuthClientContent = () => { export const AuthClient = (props: { session?: Session | null }) => { return ( - + ) diff --git a/apps/astro/src/components/header.tsx b/apps/astro/src/components/header.tsx index a025a7a8..5e9541a5 100644 --- a/apps/astro/src/components/header.tsx +++ b/apps/astro/src/components/header.tsx @@ -1,12 +1,14 @@ import { useState } from "react" import { Menu, X } from "lucide-react" import { Button } from "@/components/ui/button" -import { useAuth, AuthProvider } from "@/contexts/auth" +import { useAuth } from "@aura-stack/react" +import { AuthProvider } from "@/contexts/auth" import type { Session } from "@aura-stack/auth" const HeaderContent = () => { const [mobileMenuOpen, setMobileMenuOpen] = useState(false) - const { isAuthenticated, isLoading, signOut, signIn } = useAuth() + const { status, isPending, signOut, signIn } = useAuth() + const isAuthenticated = status === "authenticated" const handleSignOut = async () => { await signOut() @@ -103,7 +105,7 @@ const HeaderContent = () => { Discord
- {!isLoading && !isAuthenticated && ( + {!isPending && !isAuthenticated && ( @@ -125,7 +127,7 @@ const HeaderContent = () => { export const Header = (props: { session?: Session }) => { return ( - + ) diff --git a/apps/astro/src/contexts/auth.tsx b/apps/astro/src/contexts/auth.tsx index eff695ea..4975fa94 100644 --- a/apps/astro/src/contexts/auth.tsx +++ b/apps/astro/src/contexts/auth.tsx @@ -1,62 +1,6 @@ -import { createContext, use, useState, useEffect } from "react" -import { authClient } from "@/lib/client" -import type { Session, LiteralUnion, BuiltInOAuthProvider, SignInOptions, SignOutOptions } from "@aura-stack/auth" -import type { AuthProviderProps } from "@/@types/props" -import type { AuthContextValue } from "@/@types/types" +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" +import { authClient } from "@/lib/auth-client" -export const AuthContext = createContext(undefined) - -export const AuthProvider = ({ children, session: defaultSession }: AuthProviderProps) => { - const [isLoading, setIsLoading] = useState(defaultSession === undefined) - const [session, setSession] = useState(defaultSession ?? null) - const isAuthenticated = Boolean(session?.user) - - const signIn = async (provider: LiteralUnion, options?: SignInOptions) => { - setIsLoading(true) - try { - return await authClient.signIn(provider, options) - } finally { - setIsLoading(false) - } - } - - const signOut = async (options?: SignOutOptions) => { - setIsLoading(true) - try { - const value = await authClient.signOut(options) - setSession(null) - return value - } finally { - setIsLoading(false) - } - } - - useEffect(() => { - if (defaultSession !== undefined) { - setSession(defaultSession) - setIsLoading(false) - return - } - const fetchSession = async () => { - try { - const session = await authClient.getSession() - setSession(session) - } catch { - setSession(null) - } finally { - setIsLoading(false) - } - } - fetchSession() - }, [defaultSession]) - - return {children} -} - -export const useAuth = () => { - const ctx = use(AuthContext) - if (!ctx) { - throw new Error("useAuth must be used within an AuthProvider") - } - return ctx +export const AuthProvider = ({ children }: Omit) => { + return {children} } diff --git a/apps/astro/src/lib/client.ts b/apps/astro/src/lib/auth-client.ts similarity index 100% rename from apps/astro/src/lib/client.ts rename to apps/astro/src/lib/auth-client.ts diff --git a/apps/nextjs/app-router/package.json b/apps/nextjs/app-router/package.json index 06b631d4..aa4195d8 100644 --- a/apps/nextjs/app-router/package.json +++ b/apps/nextjs/app-router/package.json @@ -13,6 +13,7 @@ }, "dependencies": { "@aura-stack/auth": "workspace:*", + "@aura-stack/react": "workspace:*", "@radix-ui/react-slot": "^1.2.4", "lucide-react": "catalog:lucide-react", "next": "catalog:next", diff --git a/apps/nextjs/app-router/src/app/layout.tsx b/apps/nextjs/app-router/src/app/layout.tsx index 88274311..bb429dea 100644 --- a/apps/nextjs/app-router/src/app/layout.tsx +++ b/apps/nextjs/app-router/src/app/layout.tsx @@ -1,9 +1,9 @@ import { Geist, Geist_Mono } from "next/font/google" import { Header } from "@/components/header" -import { AuthProvider } from "@/contexts/auth" import { Footer } from "@/components/footer" import { metadataInfo } from "@/lib/metadata" -import "./globals.css" +import { AuthProvider } from "@/contexts/auth" +import "@/app/globals.css" const geistSans = Geist({ variable: "--font-geist-sans", diff --git a/apps/nextjs/app-router/src/components/auth-client.tsx b/apps/nextjs/app-router/src/components/auth-client.tsx index 1dd2de99..4c2c0ab2 100644 --- a/apps/nextjs/app-router/src/components/auth-client.tsx +++ b/apps/nextjs/app-router/src/components/auth-client.tsx @@ -1,11 +1,12 @@ "use client" -import { useAuth } from "@/contexts/auth" import { LayoutDashboard } from "lucide-react" import { Button } from "./ui/button" +import { useAuth } from "@aura-stack/react/hooks" export const AuthClient = () => { - const { session, isAuthenticated, isLoading, signIn, signOut } = useAuth() + const { status, session, signIn, signOut } = useAuth() + const isAuthenticated = status === "authenticated" return (
@@ -35,7 +36,13 @@ export const AuthClient = () => { {session?.user?.sub}
- @@ -55,7 +62,7 @@ export const AuthClient = () => { className="w-full rounded-none" variant="outline" size="sm" - disabled={isLoading} + //disabled={isLoading} onClick={() => signIn(provider.toLowerCase())} > Sign In with {provider} diff --git a/apps/nextjs/app-router/src/components/header.tsx b/apps/nextjs/app-router/src/components/header.tsx index d91067fe..cfc8f191 100644 --- a/apps/nextjs/app-router/src/components/header.tsx +++ b/apps/nextjs/app-router/src/components/header.tsx @@ -3,12 +3,13 @@ import Link from "next/link" import { useState } from "react" import { Menu, X } from "lucide-react" -import { useAuth } from "@/contexts/auth" import { Button } from "@/components/ui/button" +import { useAuth } from "@aura-stack/react" export const Header = () => { const [mobileMenuOpen, setMobileMenuOpen] = useState(false) - const { isAuthenticated, isLoading, signOut, signIn } = useAuth() + const { status, isPending, signOut, signIn } = useAuth() + const isAuthenticated = status === "authenticated" const handleSignOut = async () => { await signOut() @@ -102,7 +103,7 @@ export const Header = () => { Discord
- {!isLoading && !isAuthenticated && ( + {!isPending && !isAuthenticated && ( diff --git a/apps/nextjs/app-router/src/contexts/auth.tsx b/apps/nextjs/app-router/src/contexts/auth.tsx index eccf52df..a44c5644 100644 --- a/apps/nextjs/app-router/src/contexts/auth.tsx +++ b/apps/nextjs/app-router/src/contexts/auth.tsx @@ -1,76 +1,7 @@ "use client" - -import { createContext, use, useState, useEffect } from "react" +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" import { authClient } from "@/lib/auth-client" -import type { Session, LiteralUnion, BuiltInOAuthProvider, SignInOptions, SignOutOptions } from "@aura-stack/auth" -import type { AuthContextValue } from "@/@types/types" -import type { AuthProviderProps } from "@/@types/props" - -export const AuthContext = createContext(undefined) - -export const AuthProvider = ({ children, session: defaultSession }: AuthProviderProps) => { - const [isLoading, setIsLoading] = useState(defaultSession === undefined) - const [session, setSession] = useState(defaultSession ?? null) - const isAuthenticated = Boolean(session?.user) - - const signIn = async (provider: LiteralUnion, options?: SignInOptions) => { - setIsLoading(true) - try { - return await authClient.signIn(provider, { redirect: true, ...options }) - } finally { - setIsLoading(false) - } - } - - const signOut = async (options?: SignOutOptions) => { - setIsLoading(true) - try { - const value = await authClient.signOut(options) - setSession(null) - return value - } finally { - setIsLoading(false) - } - } - - useEffect(() => { - if (defaultSession !== undefined) { - setSession(defaultSession) - setIsLoading(false) - return - } - const fetchSession = async () => { - try { - const session = await authClient.getSession() - setSession(session) - } catch { - setSession(null) - } finally { - setIsLoading(false) - } - } - fetchSession() - }, [defaultSession]) - - return ( - - {children} - - ) -} -export const useAuth = () => { - const ctx = use(AuthContext) - if (!ctx) { - throw new Error("useAuth must be used within an AuthProvider") - } - return ctx +export const AuthProvider = ({ children }: Omit) => { + return {children} } diff --git a/apps/nextjs/pages-router/package.json b/apps/nextjs/pages-router/package.json index a1b8aa8e..d28b8691 100644 --- a/apps/nextjs/pages-router/package.json +++ b/apps/nextjs/pages-router/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@aura-stack/auth": "workspace:*", + "@aura-stack/react": "workspace:*", "@radix-ui/react-slot": "^1.2.4", "lucide-react": "catalog:lucide-react", "next": "catalog:next", diff --git a/apps/nextjs/pages-router/src/components/auth-client.tsx b/apps/nextjs/pages-router/src/components/auth-client.tsx index c7a4e994..365d97c1 100644 --- a/apps/nextjs/pages-router/src/components/auth-client.tsx +++ b/apps/nextjs/pages-router/src/components/auth-client.tsx @@ -1,9 +1,10 @@ -import { useAuth } from "@/contexts/auth" import { LayoutDashboard } from "lucide-react" import { Button } from "./ui/button" +import { useAuth } from "@aura-stack/react" export const AuthClient = () => { - const { session, isAuthenticated, isLoading, signIn, signOut } = useAuth() + const { session, status, isPending, signIn, signOut } = useAuth() + const isAuthenticated = status === "authenticated" return (
@@ -33,7 +34,7 @@ export const AuthClient = () => { {session?.user?.sub}
- @@ -53,7 +54,7 @@ export const AuthClient = () => { className="w-full rounded-none" variant="outline" size="sm" - disabled={isLoading} + disabled={isPending} onClick={() => signIn(provider.toLowerCase())} > Sign In with {provider} diff --git a/apps/nextjs/pages-router/src/components/header.tsx b/apps/nextjs/pages-router/src/components/header.tsx index 34ccc0b9..9e23838a 100644 --- a/apps/nextjs/pages-router/src/components/header.tsx +++ b/apps/nextjs/pages-router/src/components/header.tsx @@ -2,13 +2,14 @@ import Link from "next/link" import { useRouter } from "next/router" import { useState } from "react" import { Menu, X } from "lucide-react" -import { useAuth } from "@/contexts/auth" import { Button } from "@/components/ui/button" +import { useAuth } from "@aura-stack/react" export const Header = () => { const router = useRouter() const [mobileMenuOpen, setMobileMenuOpen] = useState(false) - const { isAuthenticated, isLoading, signOut, signIn } = useAuth() + const { status, isPending, signOut, signIn } = useAuth() + const isAuthenticated = status === "authenticated" const handleSignOut = async () => { await signOut() @@ -100,7 +101,7 @@ export const Header = () => { Discord
- {!isLoading && !isAuthenticated && ( + {!isPending && !isAuthenticated && ( <>
- @@ -55,7 +56,7 @@ export const AuthClient = () => { className="w-full rounded-none" variant="outline" size="sm" - disabled={isLoading} + disabled={isPending} onClick={() => signIn(provider.toLowerCase())} > Sign In with {provider} diff --git a/apps/react-router/app/components/header.tsx b/apps/react-router/app/components/header.tsx index 690dd0a3..25ab72a2 100644 --- a/apps/react-router/app/components/header.tsx +++ b/apps/react-router/app/components/header.tsx @@ -1,13 +1,14 @@ import { useState } from "react" import { Menu, X } from "lucide-react" -import { useAuth } from "~/contexts/auth" import { Button } from "~/components/ui/button" import { Link, useRevalidator } from "react-router" +import { useAuth } from "@aura-stack/react" export const Header = () => { const revalidator = useRevalidator() const [mobileMenuOpen, setMobileMenuOpen] = useState(false) - const { isAuthenticated, isLoading, signOut, signIn } = useAuth() + const { status, isPending, signOut, signIn } = useAuth() + const isAuthenticated = status === "authenticated" const handleSignOut = async () => { await signOut() @@ -98,7 +99,7 @@ export const Header = () => { Discord
- {!isLoading && !isAuthenticated && ( + {!isPending && !isAuthenticated && ( <>
- @@ -62,7 +56,7 @@ export const AuthClient = () => { className="w-full rounded-none" variant="outline" size="sm" - //disabled={isLoading} + disabled={isPending} onClick={() => signIn(provider.toLowerCase())} > Sign In with {provider} diff --git a/apps/nextjs/app-router/src/contexts/auth.tsx b/apps/nextjs/app-router/src/contexts/auth.tsx index a44c5644..c1c0a750 100644 --- a/apps/nextjs/app-router/src/contexts/auth.tsx +++ b/apps/nextjs/app-router/src/contexts/auth.tsx @@ -1,7 +1,11 @@ -"use client" -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" -import { authClient } from "@/lib/auth-client" +"use client"; +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; +import { authClient } from "@/lib/auth-client"; -export const AuthProvider = ({ children }: Omit) => { - return {children} -} +export const AuthProvider = ({ children, initialSession }: Omit) => { + return ( + + {children} + + ); +}; diff --git a/apps/nextjs/pages-router/src/contexts/auth.tsx b/apps/nextjs/pages-router/src/contexts/auth.tsx index ecb5bc59..5494dc9a 100644 --- a/apps/nextjs/pages-router/src/contexts/auth.tsx +++ b/apps/nextjs/pages-router/src/contexts/auth.tsx @@ -1,6 +1,10 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" -import { authClient } from "@/lib/client" +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; +import { authClient } from "@/lib/client"; -export const AuthProvider = ({ children }: Omit) => { - return {children} -} +export const AuthProvider = ({ children, initialSession }: Omit) => { + return ( + + {children} + + ); +}; diff --git a/apps/react-router/app/contexts/auth.tsx b/apps/react-router/app/contexts/auth.tsx index 31387d77..d43ce2ab 100644 --- a/apps/react-router/app/contexts/auth.tsx +++ b/apps/react-router/app/contexts/auth.tsx @@ -1,6 +1,10 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" -import { authClient } from "~/actions/auth.client" +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; +import { authClient } from "~/actions/auth.client"; -export const AuthProvider = ({ children }: Omit) => { - return {children} -} +export const AuthProvider = ({ children, initialSession }: Omit) => { + return ( + + {children} + + ); +}; diff --git a/apps/tanstack-start/src/contexts/auth.tsx b/apps/tanstack-start/src/contexts/auth.tsx index 4975fa94..e1539052 100644 --- a/apps/tanstack-start/src/contexts/auth.tsx +++ b/apps/tanstack-start/src/contexts/auth.tsx @@ -1,6 +1,10 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" -import { authClient } from "@/lib/auth-client" +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; +import { authClient } from "@/lib/auth-client"; -export const AuthProvider = ({ children }: Omit) => { - return {children} -} +export const AuthProvider = ({ children, initialSession }: Omit) => { + return ( + + {children} + + ); +}; diff --git a/packages/core/README.md b/packages/core/README.md index 6b8fc86f..51aede04 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -5,6 +5,7 @@ **Core authentication library for the Aura Stack ecosystem** [![npm version](https://img.shields.io/npm/v/@aura-stack/auth.svg)](https://www.npmjs.com/package/@aura-stack/auth) +[![JSR version](https://jsr.io/badges/@aura-stack/auth)](https://jsr.io/@aura-stack/auth) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [Official Docs](https://aura-stack-auth.vercel.app/docs) · [Core Package Docs](https://aura-stack-auth.vercel.app/docs/packages/core) diff --git a/packages/jose/README.md b/packages/jose/README.md index db5db25d..58e1452c 100644 --- a/packages/jose/README.md +++ b/packages/jose/README.md @@ -5,6 +5,7 @@ **Type-safe JOSE utilities for JWT signing, verification, and encryption** [![npm version](https://img.shields.io/npm/v/@aura-stack/jose.svg)](https://www.npmjs.com/package/@aura-stack/jose) +[![JSR version](https://jsr.io/badges/@aura-stack/jose)](https://jsr.io/@aura-stack/jose) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [Official Docs](https://aura-stack-auth.vercel.app/docs) · [JOSE Package Docs](https://aura-stack-auth.vercel.app/docs/packages/jose) diff --git a/packages/rate-limiter/README.md b/packages/rate-limiter/README.md index e69de29b..41e38cae 100644 --- a/packages/rate-limiter/README.md +++ b/packages/rate-limiter/README.md @@ -0,0 +1,73 @@ +
+ +

@aura-stack/rate-limiter

+ +**Rate limiting utilities for the Aura Stack ecosystem** + +[![npm version](https://img.shields.io/npm/v/@aura-stack/rate-limiter.svg)](https://www.npmjs.com/package/@aura-stack/rate-limiter) +[![JSR version](https://jsr.io/badges/@aura-stack/rate-limiter)](https://jsr.io/@aura-stack/rate-limiter) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) + +[Official Docs](https://aura-stack-auth.vercel.app/docs) · [Rate Limiter Package Docs](https://aura-stack-auth.vercel.app/docs/packages/rate-limiter) + +
+ +## Overview + +`@aura-stack/rate-limiter` provides flexible and performant rate limiting solutions designed for the **Aura Stack** ecosystem but usable in any TypeScript project. + +It offers pluggable storage backends and algorithms to protect your APIs and authentication endpoints from brute-force attacks and abuse. + +## Features + +- **Token Bucket Algorithm** — Precise control over request rates with burst support. +- **In-Memory Store** — Fast, built-in memory storage for single-instance applications. +- **Framework Agnostic** — Works in Node.js, Bun, Deno, and Edge runtimes. +- **Type-Safe** — Comprehensive TypeScript definitions for all algorithms and stores. +- **Extensible** — Easily implement custom storage backends (Redis, Database, etc.). + +## Installation + +```bash +pnpm add @aura-stack/rate-limiter +``` + +## Quick Start + +### Basic Usage with Token Bucket + +```tsx +import { createRateLimiter } from "@aura-stack/rate-limiter" +import { TokenBucket } from "@aura-stack/rate-limiter/algorithms" + +const limiter = createRateLimiter({ + algorithm: new TokenBucket({ + capacity: 10, + refillRate: 1, // 1 token per second + }), +}) + +async function handleRequest(userId: string) { + const result = await limiter.consume(userId) + + if (!result.success) { + throw new Error("Too many requests. Try again later.") + } + + // Proceed with request +} +``` + +## Documentation + +Visit the [**official documentation website**](https://aura-stack-auth.vercel.app) for more detailed guides and API references. + +## License + +Licensed under the [MIT License](LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) + +--- + +

+ Made with ❤️ by Aura Stack team +

diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md new file mode 100644 index 00000000..465837dc --- /dev/null +++ b/packages/react/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog - `@aura-stack/react` + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- + +## [Unreleased] + +### Added + +- Introduced seamless React integration package that encapsulates the core authentication logic into a single React context, exposing powerful and easy-to-use hooks for session management and authentication flows. [#137](https://github.com/aura-stack-ts/auth/pull/137) diff --git a/packages/react/README.md b/packages/react/README.md new file mode 100644 index 00000000..ad1c4f0a --- /dev/null +++ b/packages/react/README.md @@ -0,0 +1,96 @@ +
+ +

@aura-stack/react

+ +**React context and hooks for the Aura Stack authentication library** + +[![npm version](https://img.shields.io/npm/v/@aura-stack/react.svg)](https://www.npmjs.com/package/@aura-stack/react) +[![JSR version](https://jsr.io/badges/@aura-stack/react)](https://jsr.io/@aura-stack/react) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) + +[Official Docs](https://aura-stack-auth.vercel.app/docs) · [React Package Docs](https://aura-stack-auth.vercel.app/docs/packages/react) + +
+ +## Overview + +`@aura-stack/react` provides a seamless integration layer for **React** applications using **Aura Auth**. It encapsulates the core authentication logic into a single React context, exposing powerful and easy-to-use hooks for session management and authentication flows. + +It ensures that session state is synchronized across your entire component tree, reducing redundant network requests and providing a smooth developer experience. + +## Features + +- **Context-driven** — Single source of truth for session state and auth methods. +- **Custom Hooks** — `useAuth`, `useSession`, `useSignIn`, `useSignOut`, and `useUpdateSession`. +- **Type-safe** — Full TypeScript support for session objects and provider options. +- **Optimistic Updates** — Built-in support for session refreshes and status transitions. +- **Seamless Integration** — Works with any Aura Auth client configuration. + +## Installation + +```bash +pnpm add @aura-stack/react @aura-stack/auth +``` + +> [!NOTE] +> Ensure you have `react` (>= 19.x) installed. + +## Quick Start + +### 1. Configure the Provider + +Wrap your application with the `AuthProvider` and pass it a configured Aura Auth client. + +```tsx +import { createAuthClient } from "@aura-stack/auth/client" +import { AuthProvider } from "@aura-stack/react" + +const client = createAuthClient({ + /* your config */ +}) + +export const App = ({ children }) => { + return {children} +} +``` + +### 2. Use the Hooks + +Access the session or authentication methods from any component in the tree. + +```tsx +import { useSession, useSignIn, useSignOut } from "@aura-stack/react" + +export const UserProfile = () => { + const { session, status } = useSession() + const signIn = useSignIn() + const signOut = useSignOut() + + if (status === "loading") return
Loading...
+ + if (!session) { + return + } + + return ( +
+

Welcome, {session.user.name}!

+ +
+ ) +} +``` + +## Documentation + +Visit the [**official documentation website**](https://aura-stack-auth.vercel.app) for more detailed guides and API references. + +## License + +Licensed under the [MIT License](LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) + +--- + +

+ Made with ❤️ by Aura Stack team +

diff --git a/packages/react/deno.json b/packages/react/deno.json new file mode 100644 index 00000000..798f9149 --- /dev/null +++ b/packages/react/deno.json @@ -0,0 +1,21 @@ +{ + "name": "@aura-stack/react", + "version": "0.0.0", + "license": "MIT", + "tasks": { + "dev": "deno run --watch src/index.tsx" + }, + "exports": { + ".": "./src/index.tsx", + "./hooks": "./src/hooks.ts", + "./context": "./src/context.ts", + "./types": "./src/types.ts" + }, + "imports": { + "@/": "./src/" + }, + "publish": { + "include": ["src/**/*.ts", "src/**/*.tsx", "README.md", "CHANGELOG.md"] + }, + "exclude": ["dist", "node_modules"] +} diff --git a/packages/react/package.json b/packages/react/package.json index 477259e0..88762b44 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -57,11 +57,13 @@ }, "devDependencies": { "@aura-stack/tsconfig": "workspace:*", - "@aura-stack/tsup-config": "workspace:*" + "@aura-stack/tsup-config": "workspace:*", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.2" }, "peerDependencies": { - "react": ">=19.0.0", - "@types/react": ">=19.0.0" + "@types/react": ">=19.0.0", + "react": ">=19.0.0" }, "packageManager": "pnpm@10.15.0" } diff --git a/packages/react/src/index.ts b/packages/react/src/index.tsx similarity index 100% rename from packages/react/src/index.ts rename to packages/react/src/index.tsx diff --git a/packages/react/test/hooks.test.tsx b/packages/react/test/hooks.test.tsx new file mode 100644 index 00000000..df36a397 --- /dev/null +++ b/packages/react/test/hooks.test.tsx @@ -0,0 +1,153 @@ +import { act, renderHook, waitFor } from "@testing-library/react" +import { describe, expect, test, vi } from "vitest" +import { AuthProvider } from "@/context.tsx" +import { useAuth, useSession, useSignIn, useSignInCredentials, useSignOut, useUpdateSession } from "@/hooks.ts" +import type { ReactNode } from "react" +import type { AuthClientInstance } from "@/types.ts" + +const mockUser = { id: "1", email: "test@example.com", name: "Test User" } +const mockSession = { user: mockUser, expires: new Date(Date.now() + 3600 * 1000).toISOString() } + +const createMockClient = () => + ({ + getSession: vi.fn().mockResolvedValue(mockSession), + signIn: vi.fn().mockResolvedValue({ url: "/api/auth/signin" }), + signInCredentials: vi.fn().mockResolvedValue({ url: "/api/auth/signin" }), + signOut: vi.fn().mockResolvedValue({ url: "/api/auth/signout" }), + updateSession: vi.fn().mockResolvedValue(mockSession), + }) as unknown as AuthClientInstance + +const wrapper = ({ children, client, initialSession }: { children: ReactNode; client: any; initialSession?: any }) => ( + + {children} + +) + +describe("@aura-stack/react hooks", () => { + test("useSession with initialSession", async () => { + const client = createMockClient() + const { result } = renderHook(() => useSession(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: mockSession }), + }) + + expect(result.current.session).toEqual(mockSession) + expect(result.current.status).toBe("authenticated") + expect(client.getSession).not.toHaveBeenCalled() + }) + + test("useSignIn with redirect: false", async () => { + const client = createMockClient() + const { result } = renderHook(() => useSignIn(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: null }), + }) + + await act(async () => { + await result.current("github", { redirect: false }) + }) + + expect(client.signIn).toHaveBeenCalledWith("github", { redirect: false }) + await waitFor(() => expect(client.getSession).toHaveBeenCalledTimes(1)) + }) + + test("useSignIn with redirectTo", async () => { + const client = createMockClient() + const { result } = renderHook(() => useSignIn(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: null }), + }) + + await act(async () => { + await result.current("github", { redirectTo: "/dashboard", redirect: true }) + }) + + expect(client.signIn).toHaveBeenCalledWith("github", { + redirectTo: "/dashboard", + redirect: true, + }) + }) + + test("useSignInCredentials with redirect: false", async () => { + const client = createMockClient() + const { result } = renderHook(() => useSignInCredentials(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: null }), + }) + + const credentials = { username: "test@example.com", password: "password" } + await act(async () => { + await result.current(credentials, { redirect: false }) + }) + + expect(client.signInCredentials).toHaveBeenCalledWith(credentials, { redirect: false }) + await waitFor(() => expect(client.getSession).toHaveBeenCalledTimes(1)) + }) + + test("useSignOut calls client.signOut and refreshes session when redirect is false", async () => { + const client = createMockClient() + client.getSession = vi.fn().mockResolvedValueOnce(mockSession).mockResolvedValueOnce(null) + + const { result } = renderHook(() => useSignOut(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: mockSession }), + }) + + await act(async () => { + await result.current({ redirect: false }) + }) + + expect(client.signOut).toHaveBeenCalledWith({ redirect: false }) + await waitFor(() => expect(client.getSession).toHaveBeenCalledTimes(1)) + }) + + test("useUpdateSession with refresh", async () => { + const client = createMockClient() + const { result } = renderHook(() => useUpdateSession(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: mockSession }), + }) + + const partial = { user: { name: "New Name" } } + await act(async () => { + await result.current(partial) + }) + + expect(client.updateSession).toHaveBeenCalledWith(partial) + await waitFor(() => expect(client.getSession).toHaveBeenCalledTimes(1)) + }) + + test("useUpdateSession with skipRefresh", async () => { + const client = createMockClient() + const { result } = renderHook(() => useUpdateSession(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: mockSession }), + }) + + const partial = { user: { name: "New Name" } } + await act(async () => { + await result.current(partial, { skipRefresh: true }) + }) + + expect(client.updateSession).toHaveBeenCalledWith(partial) + expect(client.getSession).not.toHaveBeenCalled() + }) + + test("useAuth returns full context value", async () => { + const client = createMockClient() + const { result } = renderHook(() => useAuth(), { + wrapper: ({ children }) => wrapper({ children, client, initialSession: mockSession }), + }) + + expect(result.current.session).toEqual(mockSession) + expect(result.current.status).toBe("authenticated") + expect(typeof result.current.signIn).toBe("function") + expect(typeof result.current.signOut).toBe("function") + expect(result.current.client).toBe(client) + }) + + test("context status transitions from loading to authenticated on mount", async () => { + const client = createMockClient() + const { result } = renderHook(() => useAuth(), { + wrapper: ({ children }) => wrapper({ children, client }), + }) + + expect(result.current.status).toBe("loading") + + await waitFor(() => expect(result.current.status).toBe("authenticated")) + expect(result.current.session).toEqual(mockSession) + }) +}) diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json index 8d4eae3d..683985e3 100644 --- a/packages/react/tsconfig.json +++ b/packages/react/tsconfig.json @@ -5,9 +5,10 @@ "allowImportingTsExtensions": true, "noEmit": true, "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@test/*": ["./test/*"] } }, - "include": ["src"], + "include": ["src", "test"], "exclude": ["dist", "node_modules"] } diff --git a/packages/react/tsup.config.ts b/packages/react/tsup.config.ts index 6dbaa98b..d970bafe 100644 --- a/packages/react/tsup.config.ts +++ b/packages/react/tsup.config.ts @@ -5,6 +5,5 @@ export default defineConfig({ ...tsupConfig, banner: { js: `"use client"`, - css: undefined, }, }) diff --git a/packages/react/vitest.config.ts b/packages/react/vitest.config.ts new file mode 100644 index 00000000..214b3724 --- /dev/null +++ b/packages/react/vitest.config.ts @@ -0,0 +1,16 @@ +import path from "path" +import { defineConfig } from "vitest/config" + +export default defineConfig({ + test: { + include: ["test/**/*.test.tsx", "test/**/*.test.ts"], + environment: "jsdom", + globals: true, + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + "@test": path.resolve(__dirname, "./test"), + }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f98e1a2e..4b44bc28 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -493,7 +493,7 @@ importers: version: 0.561.0(react@19.2.4) nitro: specifier: npm:nitro-nightly@latest - version: nitro-nightly@3.0.1-20260402-182549-a5a3389c(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(ioredis@5.10.0)(jiti@2.6.1)(lru-cache@11.2.7)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) + version: nitro-nightly@3.0.1-20260409-145609-ab30376e(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(ioredis@5.10.0)(jiti@2.6.1)(lru-cache@11.2.7)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)) react: specifier: catalog:react version: 19.2.4 @@ -718,6 +718,12 @@ importers: '@aura-stack/tsup-config': specifier: workspace:* version: link:../../configs/tsup-config + '@testing-library/dom': + specifier: ^10.4.1 + version: 10.4.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) packages: @@ -6847,8 +6853,8 @@ packages: nf3@0.3.16: resolution: {integrity: sha512-Gs0xRPpUm2nDkqbi40NJ9g7qDIcjcJzgExiydnq6LAyqhI2jfno8wG3NKTL+IiJsx799UHOb1CnSd4Wg4SG4Pw==} - nitro-nightly@3.0.1-20260402-182549-a5a3389c: - resolution: {integrity: sha512-FlUsSGgM0DMMl+N8pdWqpAllNguCgj983LUmWpio7HQsDv+mhX0JUc7WMwszBW+d1e+gb2pe6rjrMlJeFFiFUw==} + nitro-nightly@3.0.1-20260409-145609-ab30376e: + resolution: {integrity: sha512-q1nEIMbzn+kqei7nVJ0RnC/EAEaBqQZVeScrni8Ndw1Ztt9HH1GHTH3TdHg7F6NoHV3uphMRtlcCQmmTbAGm0A==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -15866,7 +15872,7 @@ snapshots: nf3@0.3.16: {} - nitro-nightly@3.0.1-20260402-182549-a5a3389c(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(ioredis@5.10.0)(jiti@2.6.1)(lru-cache@11.2.7)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)): + nitro-nightly@3.0.1-20260409-145609-ab30376e(chokidar@5.0.0)(dotenv@17.3.1)(giget@3.1.2)(ioredis@5.10.0)(jiti@2.6.1)(lru-cache@11.2.7)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: consola: 3.4.2 crossws: 0.4.4(srvx@0.11.15) From 59f12362a7cf713088b8ba30883c7da2795ecfcb Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Thu, 9 Apr 2026 20:48:21 -0500 Subject: [PATCH 3/3] chore: apply coderabbit --- .vscode/settings.json | 14 +++++++------- apps/astro/src/@types/types.ts | 14 +++++++------- apps/astro/src/contexts/auth.tsx | 16 ++++++++-------- apps/astro/tsconfig.json | 6 +++--- apps/nextjs/app-router/src/contexts/auth.tsx | 18 +++++++++--------- apps/nextjs/pages-router/src/contexts/auth.tsx | 16 ++++++++-------- apps/react-router/app/contexts/auth.tsx | 16 ++++++++-------- apps/tanstack-start/src/contexts/auth.tsx | 16 ++++++++-------- package.json | 2 +- packages/core/README.md | 2 +- packages/core/package.json | 1 + packages/core/src/index.ts | 4 ++++ packages/jose/README.md | 2 +- packages/rate-limiter/README.md | 8 ++++---- packages/react/README.md | 4 ++-- packages/react/package.json | 4 ++-- packages/react/src/context.tsx | 2 +- packages/react/test/hooks.test.tsx | 2 +- packages/react/vitest.config.ts | 5 ++++- turbo.json | 3 +++ 20 files changed, 83 insertions(+), 72 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 08743c5d..1196cf94 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,21 +3,21 @@ "oxc.fmt.configPath": "./.oxfmtrc.json", "editor.defaultFormatter": "oxc.oxc-vscode", "[javascript]": { - "editor.defaultFormatter": "oxc.oxc-vscode", + "editor.defaultFormatter": "oxc.oxc-vscode" }, "[typescript]": { - "editor.defaultFormatter": "oxc.oxc-vscode", + "editor.defaultFormatter": "oxc.oxc-vscode" }, "[javascriptreact]": { - "editor.defaultFormatter": "oxc.oxc-vscode", + "editor.defaultFormatter": "oxc.oxc-vscode" }, "[typescriptreact]": { - "editor.defaultFormatter": "oxc.oxc-vscode", + "editor.defaultFormatter": "oxc.oxc-vscode" }, "[json]": { - "editor.defaultFormatter": "oxc.oxc-vscode", + "editor.defaultFormatter": "oxc.oxc-vscode" }, "[markdown]": { - "editor.defaultFormatter": "oxc.oxc-vscode", - }, + "editor.defaultFormatter": "oxc.oxc-vscode" + } } diff --git a/apps/astro/src/@types/types.ts b/apps/astro/src/@types/types.ts index 563e595f..63d2ea67 100644 --- a/apps/astro/src/@types/types.ts +++ b/apps/astro/src/@types/types.ts @@ -1,10 +1,10 @@ -import type { authClient } from "@/lib/client"; -import type { Session } from "@aura-stack/auth"; +import type { authClient } from "@/lib/client" +import type { Session } from "@aura-stack/auth" export interface AuthContextValue { - session: Session | null; - isLoading: boolean; - isAuthenticated: boolean; - signIn: typeof authClient.signIn; - signOut: typeof authClient.signOut; + session: Session | null + isLoading: boolean + isAuthenticated: boolean + signIn: typeof authClient.signIn + signOut: typeof authClient.signOut } diff --git a/apps/astro/src/contexts/auth.tsx b/apps/astro/src/contexts/auth.tsx index 5494dc9a..3d9518e2 100644 --- a/apps/astro/src/contexts/auth.tsx +++ b/apps/astro/src/contexts/auth.tsx @@ -1,10 +1,10 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; -import { authClient } from "@/lib/client"; +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" +import { authClient } from "@/lib/client" export const AuthProvider = ({ children, initialSession }: Omit) => { - return ( - - {children} - - ); -}; + return ( + + {children} + + ) +} diff --git a/apps/astro/tsconfig.json b/apps/astro/tsconfig.json index c1167f5d..07c91c8e 100644 --- a/apps/astro/tsconfig.json +++ b/apps/astro/tsconfig.json @@ -6,7 +6,7 @@ "jsx": "react-jsx", "jsxImportSource": "react", "paths": { - "@/*": ["./src/*"], - }, - }, + "@/*": ["./src/*"] + } + } } diff --git a/apps/nextjs/app-router/src/contexts/auth.tsx b/apps/nextjs/app-router/src/contexts/auth.tsx index c1c0a750..d07de890 100644 --- a/apps/nextjs/app-router/src/contexts/auth.tsx +++ b/apps/nextjs/app-router/src/contexts/auth.tsx @@ -1,11 +1,11 @@ -"use client"; -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; -import { authClient } from "@/lib/auth-client"; +"use client" +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" +import { authClient } from "@/lib/auth-client" export const AuthProvider = ({ children, initialSession }: Omit) => { - return ( - - {children} - - ); -}; + return ( + + {children} + + ) +} diff --git a/apps/nextjs/pages-router/src/contexts/auth.tsx b/apps/nextjs/pages-router/src/contexts/auth.tsx index 5494dc9a..3d9518e2 100644 --- a/apps/nextjs/pages-router/src/contexts/auth.tsx +++ b/apps/nextjs/pages-router/src/contexts/auth.tsx @@ -1,10 +1,10 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; -import { authClient } from "@/lib/client"; +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" +import { authClient } from "@/lib/client" export const AuthProvider = ({ children, initialSession }: Omit) => { - return ( - - {children} - - ); -}; + return ( + + {children} + + ) +} diff --git a/apps/react-router/app/contexts/auth.tsx b/apps/react-router/app/contexts/auth.tsx index d43ce2ab..9f0084b7 100644 --- a/apps/react-router/app/contexts/auth.tsx +++ b/apps/react-router/app/contexts/auth.tsx @@ -1,10 +1,10 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; -import { authClient } from "~/actions/auth.client"; +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" +import { authClient } from "~/actions/auth.client" export const AuthProvider = ({ children, initialSession }: Omit) => { - return ( - - {children} - - ); -}; + return ( + + {children} + + ) +} diff --git a/apps/tanstack-start/src/contexts/auth.tsx b/apps/tanstack-start/src/contexts/auth.tsx index e1539052..63d05484 100644 --- a/apps/tanstack-start/src/contexts/auth.tsx +++ b/apps/tanstack-start/src/contexts/auth.tsx @@ -1,10 +1,10 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react"; -import { authClient } from "@/lib/auth-client"; +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" +import { authClient } from "@/lib/auth-client" export const AuthProvider = ({ children, initialSession }: Omit) => { - return ( - - {children} - - ); -}; + return ( + + {children} + + ) +} diff --git a/package.json b/package.json index a5b74ce9..1b9cb4c2 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "dev:core": "turbo run @aura-stack/auth#dev", "dev:docs": "turbo run docs#dev", "build": "turbo run build --filter=./packages/* --filter=./apps/*", - "build:prod": "turbo run build --filter=./packages/*", + "build:prod": "turbo run build --filter=./packages/* --continue", "test": "turbo run test --parallel", "format": "turbo run format format:root --parallel", "format:root": "oxfmt \"!packages\" \"!apps\" \"!configs\"", diff --git a/packages/core/README.md b/packages/core/README.md index 51aede04..518d665c 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -34,7 +34,7 @@ Visit the [**official documentation website**](https://aura-stack-auth.vercel.ap ## License -Licensed under the [MIT License](LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) +Licensed under the [MIT License](../../LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) --- diff --git a/packages/core/package.json b/packages/core/package.json index de88c2ef..6e3225fe 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,6 +27,7 @@ "access": "public", "registry": "https://registry.npmjs.org/@aura-stack/auth" }, + "sideEffects": false, "files": [ "dist" ], diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ead42c30..e350acd4 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -45,6 +45,10 @@ export type { UserShape, CredentialsPayload, DeepPartial, + UpdateSessionAPIOptions, + UpdateSessionReturn, + SignOutOptions, + SignInCredentialsOptions, } from "@/@types/index.ts" export type { Merge, ShapeToObject, EditableShape, InferShape, InferIdentity, InferAuthIdentity } from "@/@types/utility.ts" diff --git a/packages/jose/README.md b/packages/jose/README.md index 58e1452c..fe0e5aa1 100644 --- a/packages/jose/README.md +++ b/packages/jose/README.md @@ -35,7 +35,7 @@ Visit the [**official documentation website**](https://aura-stack-auth.vercel.ap ## License -Licensed under the [MIT License](LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) +Licensed under the [MIT License](../../LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) --- diff --git a/packages/rate-limiter/README.md b/packages/rate-limiter/README.md index 41e38cae..b4bc8455 100644 --- a/packages/rate-limiter/README.md +++ b/packages/rate-limiter/README.md @@ -8,7 +8,7 @@ [![JSR version](https://jsr.io/badges/@aura-stack/rate-limiter)](https://jsr.io/@aura-stack/rate-limiter) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) -[Official Docs](https://aura-stack-auth.vercel.app/docs) · [Rate Limiter Package Docs](https://aura-stack-auth.vercel.app/docs/packages/rate-limiter) +[Official Docs](https://aura-stack-auth.vercel.app/docs) @@ -49,11 +49,11 @@ const limiter = createRateLimiter({ async function handleRequest(userId: string) { const result = await limiter.consume(userId) - + if (!result.success) { throw new Error("Too many requests. Try again later.") } - + // Proceed with request } ``` @@ -64,7 +64,7 @@ Visit the [**official documentation website**](https://aura-stack-auth.vercel.ap ## License -Licensed under the [MIT License](LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) +Licensed under the [MIT License](../../LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) --- diff --git a/packages/react/README.md b/packages/react/README.md index ad1c4f0a..47613e52 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -8,7 +8,7 @@ [![JSR version](https://jsr.io/badges/@aura-stack/react)](https://jsr.io/@aura-stack/react) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) -[Official Docs](https://aura-stack-auth.vercel.app/docs) · [React Package Docs](https://aura-stack-auth.vercel.app/docs/packages/react) +[Official Docs](https://aura-stack-auth.vercel.app/docs) @@ -87,7 +87,7 @@ Visit the [**official documentation website**](https://aura-stack-auth.vercel.ap ## License -Licensed under the [MIT License](LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) +Licensed under the [MIT License](../../LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) --- diff --git a/packages/react/package.json b/packages/react/package.json index 88762b44..e8b0537c 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -62,8 +62,8 @@ "@testing-library/react": "^16.3.2" }, "peerDependencies": { - "@types/react": ">=19.0.0", - "react": ">=19.0.0" + "react": ">=19.0.0", + "@types/react": ">=19.0.0" }, "packageManager": "pnpm@10.15.0" } diff --git a/packages/react/src/context.tsx b/packages/react/src/context.tsx index d5d37734..3edf8ddd 100644 --- a/packages/react/src/context.tsx +++ b/packages/react/src/context.tsx @@ -10,7 +10,7 @@ import type { SignInOptions, SignOutOptions, User, -} from "@aura-stack/auth/types" +} from "@aura-stack/auth" import type { AuthProviderProps, AuthReactContextValue, UpdateSessionCallOptions } from "@/types.ts" /** diff --git a/packages/react/test/hooks.test.tsx b/packages/react/test/hooks.test.tsx index df36a397..3f6c6fc4 100644 --- a/packages/react/test/hooks.test.tsx +++ b/packages/react/test/hooks.test.tsx @@ -82,7 +82,7 @@ describe("@aura-stack/react hooks", () => { test("useSignOut calls client.signOut and refreshes session when redirect is false", async () => { const client = createMockClient() - client.getSession = vi.fn().mockResolvedValueOnce(mockSession).mockResolvedValueOnce(null) + client.getSession = vi.fn().mockResolvedValueOnce(null) const { result } = renderHook(() => useSignOut(), { wrapper: ({ children }) => wrapper({ children, client, initialSession: mockSession }), diff --git a/packages/react/vitest.config.ts b/packages/react/vitest.config.ts index 214b3724..696d778f 100644 --- a/packages/react/vitest.config.ts +++ b/packages/react/vitest.config.ts @@ -1,6 +1,9 @@ -import path from "path" +import path from "node:path" +import { fileURLToPath } from "node:url" import { defineConfig } from "vitest/config" +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + export default defineConfig({ test: { include: ["test/**/*.test.tsx", "test/**/*.test.ts"], diff --git a/turbo.json b/turbo.json index 9b121cea..613d71de 100644 --- a/turbo.json +++ b/turbo.json @@ -23,6 +23,9 @@ ".vercel/output/**" ] }, + "@aura-stack/react#build": { + "dependsOn": ["@aura-stack/auth#build"] + }, "test": { "dependsOn": ["^test"], "cache": false