Merge branch 'canary' into feat/stripe-add-cancel-at

This commit is contained in:
Maxwell
2025-10-30 22:00:43 +10:00
committed by GitHub
717 changed files with 22479 additions and 8907 deletions
+325
View File
@@ -0,0 +1,325 @@
name: Cherry-pick to Main
on:
schedule:
# Run every 5 minutes
- cron: '*/5 * * * *'
workflow_dispatch:
jobs:
cherry-pick:
runs-on: ubuntu-latest
if: github.repository == 'better-auth/better-auth'
permissions:
contents: write
pull-requests: write
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.PAT_TOKEN }}
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Find PRs with merge-to-main label
id: find-prs
uses: actions/github-script@v7
with:
script: |
// Get all closed PRs targeting canary branch
const prs = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'closed',
base: 'canary',
per_page: 100,
sort: 'updated',
direction: 'desc'
});
// Filter for merged PRs with merge-to-main label
const prsToProcess = prs.data.filter(pr =>
pr.merged_at &&
pr.labels.some(label => label.name === 'merge-to-main')
);
console.log(`Found ${prsToProcess.length} PRs with merge-to-main label`);
if (prsToProcess.length === 0) {
console.log('No PRs to process');
core.setOutput('has_prs', 'false');
return;
}
core.setOutput('has_prs', 'true');
core.setOutput('prs_to_process', JSON.stringify(prsToProcess.map(pr => ({
number: pr.number,
merge_commit_sha: pr.merge_commit_sha,
title: pr.title
}))));
- name: Cherry-pick to main
id: cherry-pick
if: steps.find-prs.outputs.has_prs == 'true'
env:
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
run: |
# Fetch all branches
git fetch origin main
git fetch origin canary
# Checkout main branch
git checkout -B main origin/main
set +e # Don't exit on error
echo "Processing PRs with merge-to-main label..."
echo '${{ steps.find-prs.outputs.prs_to_process }}' > prs.json
success_prs=""
conflict_prs=""
skipped_prs=""
success_count=0
conflict_count=0
skipped_count=0
for row in $(jq -r '.[] | @base64' prs.json); do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
PR_NUM=$(_jq '.number')
MERGE_COMMIT=$(_jq '.merge_commit_sha')
PR_TITLE=$(_jq '.title')
echo "----------------------------------------"
echo "Processing PR #$PR_NUM: $PR_TITLE"
echo "Merge commit: $MERGE_COMMIT"
# Check if commit already exists in main
if git branch -r --contains "$MERGE_COMMIT" | grep -q "origin/main"; then
echo "✓ PR #$PR_NUM already in main, will remove label"
skipped_prs="$skipped_prs $PR_NUM"
skipped_count=$((skipped_count + 1))
continue
fi
# Attempt cherry-pick
if git cherry-pick -m 1 "$MERGE_COMMIT"; then
echo "✅ Successfully cherry-picked PR #$PR_NUM"
success_prs="$success_prs $PR_NUM"
success_count=$((success_count + 1))
else
echo "❌ Conflict in PR #$PR_NUM"
conflict_prs="$conflict_prs $PR_NUM"
git cherry-pick --abort
conflict_count=$((conflict_count + 1))
fi
done
set -e # Re-enable exit on error
echo "----------------------------------------"
echo "Summary:"
echo " Success: $success_count"
echo " Conflicts: $conflict_count"
echo " Already in main: $skipped_count"
# Push all successful cherry-picks
if [ $success_count -gt 0 ]; then
git push origin main
echo "✅ Pushed $success_count cherry-pick(s) to main"
fi
# Save results for next steps
echo "success_prs=$success_prs" >> $GITHUB_OUTPUT
echo "conflict_prs=$conflict_prs" >> $GITHUB_OUTPUT
echo "skipped_prs=$skipped_prs" >> $GITHUB_OUTPUT
echo "success_count=$success_count" >> $GITHUB_OUTPUT
echo "conflict_count=$conflict_count" >> $GITHUB_OUTPUT
echo "skipped_count=$skipped_count" >> $GITHUB_OUTPUT
- name: Remove label and comment on successful PRs
if: always() && steps.cherry-pick.outputs.success_prs != ''
uses: actions/github-script@v7
with:
script: |
const successPrs = '${{ steps.cherry-pick.outputs.success_prs }}'.trim().split(' ').filter(Boolean);
for (const prNumber of successPrs) {
console.log(`Processing successful PR #${prNumber}`);
// Remove merge-to-main label
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'merge-to-main'
});
console.log(`✅ Removed merge-to-main label from PR #${prNumber}`);
} catch (error) {
console.log(`⚠️ Could not remove merge-to-main label from PR #${prNumber}: ${error.message}`);
}
// Remove merge-to-main-failure label if it exists
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'merge-to-main-failure'
});
console.log(`✅ Removed merge-to-main-failure label from PR #${prNumber}`);
} catch (error) {
// Ignore if label doesn't exist
if (error.status !== 404) {
console.log(`⚠️ Could not remove merge-to-main-failure label from PR #${prNumber}: ${error.message}`);
}
}
// Add success comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: '✅ Successfully cherry-picked to `main` branch!'
});
}
- name: Remove label from skipped PRs
if: always() && steps.cherry-pick.outputs.skipped_prs != ''
uses: actions/github-script@v7
with:
script: |
const skippedPrs = '${{ steps.cherry-pick.outputs.skipped_prs }}'.trim().split(' ').filter(Boolean);
for (const prNumber of skippedPrs) {
console.log(`Processing skipped PR #${prNumber}`);
// Remove merge-to-main label
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'merge-to-main'
});
console.log(`✅ Removed merge-to-main label from PR #${prNumber}`);
} catch (error) {
console.log(`⚠️ Could not remove merge-to-main label from PR #${prNumber}: ${error.message}`);
}
// Remove merge-to-main-failure label if it exists
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'merge-to-main-failure'
});
console.log(`✅ Removed merge-to-main-failure label from PR #${prNumber}`);
} catch (error) {
// Ignore if label doesn't exist
if (error.status !== 404) {
console.log(`⚠️ Could not remove merge-to-main-failure label from PR #${prNumber}: ${error.message}`);
}
}
// Add info comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: '️ This commit already exists in the `main` branch. Removed `merge-to-main` label.'
});
}
- name: Comment on PRs with conflicts
if: always() && steps.cherry-pick.outputs.conflict_prs != ''
uses: actions/github-script@v7
with:
script: |
const conflictPrs = '${{ steps.cherry-pick.outputs.conflict_prs }}'.trim().split(' ').filter(Boolean);
for (const prNumber of conflictPrs) {
console.log(`Checking PR #${prNumber} for existing conflict comment`);
// Check if we've already commented about conflicts
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const hasConflictComment = comments.data.some(comment =>
comment.body.includes('Cherry-pick to `main` failed due to conflicts')
);
if (hasConflictComment) {
console.log(`⏭️ Skipping PR #${prNumber} - conflict comment already exists`);
continue;
}
console.log(`Adding conflict comment and label to PR #${prNumber}`);
// Add merge-to-main-failure label
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['merge-to-main-failure']
});
console.log(`✅ Added merge-to-main-failure label to PR #${prNumber}`);
} catch (error) {
console.log(`⚠️ Could not add label to PR #${prNumber}: ${error.message}`);
}
// Remove merge-to-main label to stop retry attempts
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'merge-to-main'
});
console.log(`✅ Removed merge-to-main label from PR #${prNumber}`);
} catch (error) {
console.log(`⚠️ Could not remove label from PR #${prNumber}: ${error.message}`);
}
// Add conflict comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `⚠️ **Cherry-pick to \`main\` failed due to conflicts!**\n\nPlease manually cherry-pick this commit to the \`main\` branch and resolve the conflicts.`
});
}
- name: Workflow Summary
if: always() && steps.find-prs.outputs.has_prs == 'true'
run: |
echo "### Cherry-pick Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Success: ${{ steps.cherry-pick.outputs.success_count }}" >> $GITHUB_STEP_SUMMARY
echo "- ⚠️ Conflicts: ${{ steps.cherry-pick.outputs.conflict_count }}" >> $GITHUB_STEP_SUMMARY
echo "- ️ Already in main: ${{ steps.cherry-pick.outputs.skipped_count }}" >> $GITHUB_STEP_SUMMARY
if [ -n "${{ steps.cherry-pick.outputs.success_prs }}" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Successful PRs:** ${{ steps.cherry-pick.outputs.success_prs }}" >> $GITHUB_STEP_SUMMARY
fi
if [ -n "${{ steps.cherry-pick.outputs.conflict_prs }}" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "**PRs with conflicts:** ${{ steps.cherry-pick.outputs.conflict_prs }}" >> $GITHUB_STEP_SUMMARY
fi
+21 -1
View File
@@ -39,7 +39,24 @@ When contributing to Better Auth:
cd better-auth
```
3. Install Node.js (LTS version recommended)
4. Install pnpm if you haven't already:
> **Note**: This project is configured to use [nvm](https://github.com/nvm-sh/nvm) to manage the local Node.js version, as such this is simplest way to get you up and running.
Once installed, use:
```bash
$ nvm install
$ nvm use
```
Alternatively, see Node.js [installation](https://nodejs.org/en/download) for other supported methods.
4. Install `pnpm` if you haven't already:
> **Note:** This project is configured to manage [pnpm](https://pnpm.io/) via [corepack](https://github.com/nodejs/corepack). Once installed, upon usage you'll be prompted to install the correct pnpm version
Alternatively, use `npm` to install it:
```bash
npm install -g pnpm
```
@@ -106,6 +123,9 @@ pnpm lint:fix
```bash
docker compose up -d
```
> Note: On MacOS, the **mssql** container will likely require Rosetta emulation and at least 2GB of RAM of allocated memory. See their [container requirements](https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-ver17&tabs=cli&pivots=cs1-bash#prerequisites).
5. Run the test suite:
```bash
# Run all tests
+1 -1
View File
@@ -9,7 +9,7 @@
</h2>
<p align="center">
The most comprehensive authentication library for TypeScript
The most comprehensive authentication framework for TypeScript
<br />
<a href="https://better-auth.com"><strong>Learn more »</strong></a>
<br />
+1 -1
View File
@@ -5,7 +5,7 @@
"enabled": true,
"indentStyle": "tab"
},
"assist": { "actions": { "source": { "organizeImports": "off" } } },
"assist": { "actions": { "source": { "organizeImports": "on" } } },
"linter": {
"enabled": true,
"rules": {
-7
View File
@@ -1,7 +0,0 @@
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
BETTER_AUTH_SECRET=
DATABASE_URL=
BETTER_AUTH_URL=http://localhost:8081
-3
View File
@@ -1,3 +0,0 @@
/// <reference types="expo/types" />
// NOTE: This file should not be edited and should be in your git ignore
+7
View File
@@ -0,0 +1,7 @@
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
BETTER_AUTH_SECRET=
DATABASE_URL=postgres://user:password@localhost:5432/better_auth
BETTER_AUTH_URL=http://localhost:8081

Before

Width:  |  Height:  |  Size: 155 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

@@ -1,6 +1,5 @@
{
"name": "expo-example",
"main": "index.ts",
"name": "@better-auth/expo-example",
"private": true,
"version": "1.0.0",
"scripts": {
@@ -15,7 +14,7 @@
"dependencies": {
"@better-auth/expo": "workspace:*",
"@expo/metro-runtime": "^6.1.2",
"@expo/vector-icons": "^15.0.2",
"@expo/vector-icons": "^15.0.3",
"@nanostores/react": "^1.0.0",
"@react-native-async-storage/async-storage": "2.2.0",
"@react-navigation/native": "^7.1.17",
@@ -27,23 +26,25 @@
"babel-plugin-transform-import-meta": "^2.2.1",
"better-auth": "workspace:*",
"better-sqlite3": "^11.6.0",
"expo": "~54.0.10",
"expo-constants": "~18.0.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"expo": "~54.0.21",
"expo-constants": "~18.0.10",
"expo-crypto": "^15.0.7",
"expo-font": "~14.0.8",
"expo-font": "~14.0.9",
"expo-linking": "~8.0.8",
"expo-router": "~6.0.8",
"expo-router": "~6.0.14",
"expo-secure-store": "~15.0.7",
"expo-splash-screen": "~31.0.10",
"expo-status-bar": "~3.0.8",
"expo-system-ui": "~6.0.7",
"expo-web-browser": "~15.0.7",
"expo-system-ui": "~6.0.8",
"expo-web-browser": "~15.0.8",
"nanostores": "^0.11.3",
"nativewind": "^4.1.23",
"pg": "^8.13.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-native": "~0.81.4",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-native": "~0.81.5",
"react-native-css-interop": "^0.2.1",
"react-native-gesture-handler": "~2.28.0",
"react-native-reanimated": "~4.1.2",
@@ -52,6 +53,7 @@
"react-native-svg": "^15.12.1",
"react-native-web": "~0.21.1",
"react-native-worklets": "^0.5.1",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^3.4.16"
},
"devDependencies": {
@@ -59,6 +61,6 @@
"@babel/preset-env": "^7.26.0",
"@babel/runtime": "^7.26.0",
"@types/babel__core": "^7.20.5",
"@types/react": "^19.2.2"
"@types/react": "^19.1.17"
}
}
@@ -1,8 +1,7 @@
import { Slot } from "expo-router";
import "../global.css";
import { ImageBackground, StyleSheet, View } from "react-native";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { ImageBackground, View } from "react-native";
import { StyleSheet } from "react-native";
export default function RootLayout() {
return (
@@ -1,13 +1,13 @@
import Ionicons from "@expo/vector-icons/AntDesign";
import { useStore } from "@nanostores/react";
import { router } from "expo-router";
import { useEffect } from "react";
import { View } from "react-native";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Card, CardFooter, CardHeader } from "@/components/ui/card";
import { Text } from "@/components/ui/text";
import { authClient } from "@/lib/auth-client";
import { View } from "react-native";
import Ionicons from "@expo/vector-icons/AntDesign";
import { router } from "expo-router";
import { useEffect } from "react";
import { useStore } from "@nanostores/react";
export default function Dashboard() {
const { data: session, isPending } = useStore(authClient.useSession);
@@ -1,3 +1,7 @@
import Icons from "@expo/vector-icons/AntDesign";
import { router } from "expo-router";
import { useState } from "react";
import { View } from "react-native";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -9,10 +13,6 @@ import {
import { Input } from "@/components/ui/input";
import { Text } from "@/components/ui/text";
import { authClient } from "@/lib/auth-client";
import { useState } from "react";
import { View } from "react-native";
import Icons from "@expo/vector-icons/AntDesign";
import { router } from "expo-router";
export default function ForgetPassword() {
const [email, setEmail] = useState("");
@@ -1,14 +1,14 @@
import Ionicons from "@expo/vector-icons/AntDesign";
import { useStore } from "@nanostores/react";
import { router, useNavigationContainerRef } from "expo-router";
import { useEffect, useState } from "react";
import { Image, View } from "react-native";
import { Button } from "@/components/ui/button";
import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { Text } from "@/components/ui/text";
import { authClient } from "@/lib/auth-client";
import { Image, View } from "react-native";
import { Separator } from "@/components/ui/separator";
import { Input } from "@/components/ui/input";
import { useEffect, useState } from "react";
import { router, useNavigationContainerRef } from "expo-router";
import { useStore } from "@nanostores/react";
export default function Index() {
const { data: isAuthenticated } = useStore(authClient.useSession);
@@ -1,12 +1,11 @@
import { useRouter } from "expo-router";
import { useState } from "react";
import { Image, KeyboardAvoidingView, View } from "react-native";
import { Button } from "@/components/ui/button";
import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Text } from "@/components/ui/text";
import { authClient } from "@/lib/auth-client";
import { KeyboardAvoidingView, View } from "react-native";
import { Image } from "react-native";
import { useRouter } from "expo-router";
import { useState } from "react";
export default function SignUp() {
const router = useRouter();
@@ -1,8 +1,8 @@
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { Pressable } from "react-native";
import { cn } from "@/lib/utils";
import { TextClassContext } from "@/components/ui/text";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"group flex items-center justify-center rounded-md web:ring-offset-background web:transition-colors web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2",
@@ -16,7 +16,7 @@ const buttonVariants = cva(
secondary: "bg-secondary web:hover:opacity-80 active:opacity-80",
ghost:
"web:hover:bg-accent web:hover:text-accent-foreground active:bg-accent",
link: "web:underline-offset-4 web:hover:underline web:focus:underline ",
link: "web:underline-offset-4 web:hover:underline web:focus:underline",
},
size: {
default: "h-10 px-4 py-2 native:h-12 native:px-5 native:py-3",
@@ -1,8 +1,8 @@
import { TextRef, ViewRef } from "@rn-primitives/types";
import * as React from "react";
import { Text, type TextProps, View, type ViewProps } from "react-native";
import { cn } from "@/lib/utils";
import { TextClassContext } from "@/components/ui/text";
import { cn } from "@/lib/utils";
const Card = React.forwardRef<ViewRef, ViewProps>(
({ className, ...props }, ref) => (
@@ -1,5 +1,5 @@
import { createAuthClient } from "better-auth/client";
import { expoClient } from "@better-auth/expo/client";
import { createAuthClient } from "better-auth/client";
import * as SecureStore from "expo-secure-store";
export const authClient = createAuthClient({
@@ -1,5 +1,5 @@
import { betterAuth } from "better-auth";
import { expo } from "@better-auth/expo";
import { betterAuth } from "better-auth";
import { Pool } from "pg";
export const auth = betterAuth({
@@ -1,4 +1,5 @@
import { X } from "lucide-react-native";
import { iconWithClassName } from "./iconWithClassName";
iconWithClassName(X);
export { X };
@@ -1,5 +1,8 @@
"use client";
import { AlertCircle, ArrowLeft, CheckCircle2 } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
@@ -13,9 +16,6 @@ import {
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { client } from "@/lib/auth-client";
import { AlertCircle, ArrowLeft, CheckCircle2 } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
export default function Component() {
const [email, setEmail] = useState("");
@@ -1,5 +1,9 @@
"use client";
import { AlertCircle } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
@@ -12,10 +16,6 @@ import {
import { Label } from "@/components/ui/label";
import { PasswordInput } from "@/components/ui/password-input";
import { client } from "@/lib/auth-client";
import { AlertCircle } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
export default function ResetPassword() {
const [password, setPassword] = useState("");
+3 -3
View File
@@ -1,12 +1,12 @@
"use client";
import { useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react";
import { toast } from "sonner";
import SignIn from "@/components/sign-in";
import { SignUp } from "@/components/sign-up";
import { Tabs } from "@/components/ui/tabs2";
import { client } from "@/lib/auth-client";
import { useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react";
import { toast } from "sonner";
import { getCallbackURL } from "@/lib/shared";
export default function Page() {
@@ -1,5 +1,8 @@
"use client";
import { AlertCircle, CheckCircle2, Mail } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -11,9 +14,6 @@ import {
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { client } from "@/lib/auth-client";
import { AlertCircle, CheckCircle2, Mail } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function Component() {
const [otp, setOtp] = useState("");
+3 -3
View File
@@ -1,5 +1,8 @@
"use client";
import { AlertCircle, CheckCircle2 } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -12,9 +15,6 @@ import {
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { client } from "@/lib/auth-client";
import { AlertCircle, CheckCircle2 } from "lucide-react";
import Link from "next/link";
import { useState } from "react";
export default function Component() {
const [totpCode, setTotpCode] = useState("");
@@ -1,14 +1,14 @@
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { AlertCircle } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
export function InvitationError() {
return (
@@ -1,5 +1,8 @@
"use client";
import { CheckIcon, XIcon } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -9,9 +12,6 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { CheckIcon, XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { Skeleton } from "@/components/ui/skeleton";
import { client, organization } from "@/lib/auth-client";
import { InvitationError } from "./invitation-error";
+27 -27
View File
@@ -1,9 +1,36 @@
"use client";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { format } from "date-fns";
import {
Calendar as CalendarIcon,
Loader2,
Plus,
RefreshCw,
Trash,
UserCircle,
} from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { Toaster, toast } from "sonner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import {
Select,
SelectContent,
@@ -19,35 +46,8 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
import { toast, Toaster } from "sonner";
import { client } from "@/lib/auth-client";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
import {
Loader2,
Plus,
Trash,
RefreshCw,
UserCircle,
Calendar as CalendarIcon,
} from "lucide-react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { format } from "date-fns";
import { cn } from "@/lib/utils";
import { Badge } from "@/components/ui/badge";
type User = {
id: string;
+1 -1
View File
@@ -1,4 +1,4 @@
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
import { auth } from "@/lib/auth";
export const { GET, POST } = toNextJsHandler(auth);
+4 -4
View File
@@ -1,7 +1,10 @@
"use client";
import { useState } from "react";
import { AlertCircle, Loader2 } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
@@ -11,9 +14,6 @@ import {
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { AlertCircle, Loader2 } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { client } from "@/lib/auth-client";
export default function RegisterOAuthClient() {
+4 -4
View File
@@ -1,20 +1,20 @@
"use client";
import { Loader2 } from "lucide-react";
import { useState, useTransition } from "react";
import { signIn, client } from "@/lib/auth-client";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
CardFooter,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { toast } from "sonner";
import { Loader2 } from "lucide-react";
import { client, signIn } from "@/lib/auth-client";
export default function ClientTest() {
const [email, setEmail] = useState("");
+3 -3
View File
@@ -1,3 +1,6 @@
import { ArrowUpFromLine, CreditCard, RefreshCcw } from "lucide-react";
import { useId, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
Dialog,
@@ -11,9 +14,6 @@ import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { client } from "@/lib/auth-client";
import { cn } from "@/lib/utils";
import { ArrowUpFromLine, CreditCard, RefreshCcw } from "lucide-react";
import { useId, useState } from "react";
import { toast } from "sonner";
function Component(props: { currentPlan?: string; isTrial?: boolean }) {
const [selectedPlan, setSelectedPlan] = useState("plus");
@@ -1,8 +1,15 @@
"use client";
import { ChevronDownIcon, PlusIcon } from "@radix-ui/react-icons";
import { AnimatePresence, motion } from "framer-motion";
import { Loader2, MailPlus } from "lucide-react";
import Image from "next/image";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import CopyButton from "@/components/ui/copy-button";
import {
Dialog,
DialogClose,
@@ -34,13 +41,6 @@ import {
useSession,
} from "@/lib/auth-client";
import { ActiveOrganization, Session } from "@/lib/auth-types";
import { ChevronDownIcon, PlusIcon } from "@radix-ui/react-icons";
import { Loader2, MailPlus } from "lucide-react";
import { useState, useEffect } from "react";
import { toast } from "sonner";
import { AnimatePresence, motion } from "framer-motion";
import CopyButton from "@/components/ui/copy-button";
import Image from "next/image";
export function OrganizationCard(props: {
session: Session | null;
@@ -82,7 +82,7 @@ export function OrganizationCard(props: {
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem
className=" py-1"
className="py-1"
onClick={async () => {
organization.setActive({
organizationId: null,
@@ -94,7 +94,7 @@ export function OrganizationCard(props: {
</DropdownMenuItem>
{organizations.data?.map((org) => (
<DropdownMenuItem
className=" py-1"
className="py-1"
key={org.id}
onClick={async () => {
if (org.id === optimisticOrg?.id) {
+3 -3
View File
@@ -1,9 +1,9 @@
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import UserCard from "./user-card";
import { OrganizationCard } from "./organization-card";
import AccountSwitcher from "@/components/account-switch";
import { auth } from "@/lib/auth";
import { OrganizationCard } from "./organization-card";
import UserCard from "./user-card";
export default async function DashboardPage() {
const [session, activeSessions, deviceSessions, organization, subscriptions] =
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import { useState } from "react";
import { motion } from "framer-motion";
import { Sparkles } from "lucide-react";
import { useState } from "react";
export default function UpgradeButton() {
const [isHovered, setIsHovered] = useState(false);
+32 -32
View File
@@ -1,31 +1,8 @@
"use client";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
import { Checkbox } from "@/components/ui/checkbox";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { PasswordInput } from "@/components/ui/password-input";
import { client, signOut, useSession } from "@/lib/auth-client";
import { Session } from "@/lib/auth-types";
import { Subscription } from "@better-auth/stripe";
import { MobileIcon } from "@radix-ui/react-icons";
import { useQuery } from "@tanstack/react-query";
import {
Edit,
Fingerprint,
@@ -43,8 +20,35 @@ import {
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useState, useTransition } from "react";
import QRCode from "react-qr-code";
import { toast } from "sonner";
import { UAParser } from "ua-parser-js";
import { SubscriptionTierLabel } from "@/components/tier-labels";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import CopyButton from "@/components/ui/copy-button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { PasswordInput } from "@/components/ui/password-input";
import {
Table,
TableBody,
@@ -53,13 +57,9 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table";
import QRCode from "react-qr-code";
import CopyButton from "@/components/ui/copy-button";
import { Badge } from "@/components/ui/badge";
import { useQuery } from "@tanstack/react-query";
import { SubscriptionTierLabel } from "@/components/tier-labels";
import { client, signOut, useSession } from "@/lib/auth-client";
import { Session } from "@/lib/auth-types";
import { Component } from "./change-plan";
import { Subscription } from "@better-auth/stripe";
export default function UserCard(props: {
session: Session | null;
@@ -212,7 +212,7 @@ export default function UserCard(props: {
session.userAgent}
, {new UAParser(session.userAgent || "").getBrowser().name}
<button
className="text-red-500 opacity-80 cursor-pointer text-xs border-muted-foreground border-red-600 underline "
className="text-red-500 opacity-80 cursor-pointer text-xs border-muted-foreground border-red-600 underline"
onClick={async () => {
setIsTerminating(session.id);
const res = await client.revokeSession({
+5 -5
View File
@@ -1,12 +1,12 @@
"use client";
import { useState, useTransition } from "react";
import { Check, Loader2, X } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { client, useSession } from "@/lib/auth-client";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { useState, useTransition } from "react";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Loader2, Check, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { client, useSession } from "@/lib/auth-client";
export default function DeviceApprovalPage() {
const router = useRouter();
+2 -2
View File
@@ -1,9 +1,9 @@
"use client";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { X } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
export default function DeviceDeniedPage() {
return (
+1 -1
View File
@@ -1,6 +1,6 @@
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { auth } from "@/lib/auth";
export default async function DevicePage({
children,
+5 -5
View File
@@ -1,14 +1,14 @@
"use client";
import { useState, useTransition } from "react";
import { Loader2 } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { client } from "@/lib/auth-client";
import { useState, useTransition } from "react";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Loader2 } from "lucide-react";
import { client } from "@/lib/auth-client";
export default function DeviceAuthorizationPage() {
const router = useRouter();
+2 -2
View File
@@ -1,9 +1,9 @@
"use client";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Check } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
export default function DeviceSuccessPage() {
return (
+2 -2
View File
@@ -1,14 +1,14 @@
"use client";
import React from "react";
import { AnimatePresence, motion } from "framer-motion";
import React from "react";
import { Logo } from "@/components/logo";
export function Features() {
return (
<>
<div className="flex flex-col lg:flex-row bg-white dark:bg-black w-full gap-4 mx-auto px-8">
<Card title="Better Auth" icon={<Logo className=" w-44" />}></Card>
<Card title="Better Auth" icon={<Logo className="w-44" />}></Card>
</div>
</>
);
+3 -3
View File
@@ -1,8 +1,8 @@
import "./globals.css";
import { Toaster } from "@/components/ui/sonner";
import { ThemeProvider } from "@/components/theme-provider";
import { GeistMono } from "geist/font/mono";
import { GeistSans } from "geist/font/sans";
import { ThemeProvider } from "@/components/theme-provider";
import { Toaster } from "@/components/ui/sonner";
import { Wrapper, WrapperWithQuery } from "@/components/wrapper";
import { createMetadata } from "@/lib/metadata";
@@ -11,7 +11,7 @@ export const metadata = createMetadata({
template: "%s | Better Auth",
default: "Better Auth",
},
description: "The most comprehensive authentication library for typescript",
description: "The most comprehensive authentication framework for TypeScript",
metadataBase: new URL("https://demo.better-auth.com"),
});
@@ -1,11 +1,11 @@
"use client";
import { Button } from "@/components/ui/button";
import { CardFooter } from "@/components/ui/card";
import { client } from "@/lib/auth-client";
import { Loader2 } from "lucide-react";
import { useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { CardFooter } from "@/components/ui/card";
import { client } from "@/lib/auth-client";
export function ConsentBtns() {
const [loading, setLoading] = useState(false);
+6 -6
View File
@@ -1,11 +1,11 @@
import { Metadata } from "next";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { ArrowLeftRight, ArrowUpRight, Mail, Users } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Logo } from "@/components/logo";
import { Metadata } from "next";
import { headers } from "next/headers";
import Image from "next/image";
import { Logo } from "@/components/logo";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Card, CardContent } from "@/components/ui/card";
import { auth } from "@/lib/auth";
import { ConsentBtns } from "./concet-buttons";
export const metadata: Metadata = {
+2 -2
View File
@@ -1,5 +1,5 @@
import { SignInButton, SignInFallback } from "@/components/sign-in-btn";
import { Suspense } from "react";
import { SignInButton, SignInFallback } from "@/components/sign-in-btn";
const features = [
{
@@ -63,7 +63,7 @@ export default async function Home() {
<div className="md:w-10/12 w-full flex flex-col gap-4">
<div className="flex flex-col gap-3 pt-2 flex-wrap">
<div className="border-y py-2 border-dotted bg-secondary/60 opacity-80">
<div className="text-xs flex items-center gap-2 justify-center text-muted-foreground ">
<div className="text-xs flex items-center gap-2 justify-center text-muted-foreground">
<span className="text-center">
All features on this demo are implemented with Better Auth
without any custom backend code
+9 -9
View File
@@ -1,13 +1,10 @@
"use client";
import { ChevronDown, PlusCircle } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import {
Command,
CommandGroup,
@@ -15,10 +12,13 @@ import {
CommandList,
CommandSeparator,
} from "@/components/ui/command";
import { ChevronDown, PlusCircle } from "lucide-react";
import { Session } from "@/lib/auth-types";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { client, useSession } from "@/lib/auth-client";
import { useRouter } from "next/navigation";
import { Session } from "@/lib/auth-types";
export default function AccountSwitcher({ sessions }: { sessions: Session[] }) {
const { data: currentUser } = useSession();
+7 -8
View File
@@ -1,17 +1,16 @@
"use client";
import NumberFlow from "@number-flow/react";
import { CheckIcon } from "@radix-ui/react-icons";
import confetti from "canvas-confetti";
import { motion } from "framer-motion";
import { Star } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { Button, buttonVariants } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { cn } from "@/lib/utils";
import { motion } from "framer-motion";
import { Star } from "lucide-react";
import { useState, useRef, useEffect } from "react";
import confetti from "canvas-confetti";
import NumberFlow from "@number-flow/react";
import { CheckIcon } from "@radix-ui/react-icons";
import { client } from "@/lib/auth-client";
import { cn } from "@/lib/utils";
function useMediaQuery(query: string) {
const [matches, setMatches] = useState(false);
+9 -9
View File
@@ -1,7 +1,13 @@
"use client";
import { client, signIn } from "@/lib/auth-client";
import { Key, Loader2 } from "lucide-react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { client, signIn } from "@/lib/auth-client";
import { Button } from "./ui/button";
import { Checkbox } from "./ui/checkbox";
import {
Dialog,
DialogContent,
@@ -10,14 +16,8 @@ import {
DialogTitle,
} from "./ui/dialog";
import { Input } from "./ui/input";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { PasswordInput } from "./ui/password-input";
import { Checkbox } from "./ui/checkbox";
import { Button } from "./ui/button";
import { Key, Loader2 } from "lucide-react";
import { toast } from "sonner";
import { Label } from "./ui/label";
import { PasswordInput } from "./ui/password-input";
export function OneTap() {
const [isOpen, setIsOpen] = useState(false);
@@ -123,7 +123,7 @@ function SignInBox() {
</Button>
<Button
variant="outline"
className=" gap-2"
className="gap-2"
onClick={async () => {
await signIn.social({
provider: "google",
+3 -3
View File
@@ -1,7 +1,7 @@
import Link from "next/link";
import { Button } from "./ui/button";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import Link from "next/link";
import { auth } from "@/lib/auth";
import { Button } from "./ui/button";
export async function SignInButton() {
const session = await auth.api.getSession({
+32 -9
View File
@@ -1,25 +1,25 @@
"use client";
import { Key, Loader2 } from "lucide-react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { useState, useTransition } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox";
import { useState, useTransition } from "react";
import { Loader2 } from "lucide-react";
import { client, signIn } from "@/lib/auth-client";
import Link from "next/link";
import { cn } from "@/lib/utils";
import { useRouter, useSearchParams } from "next/navigation";
import { toast } from "sonner";
import { getCallbackURL } from "@/lib/shared";
import { cn } from "@/lib/utils";
export default function SignIn() {
const [email, setEmail] = useState("");
@@ -213,6 +213,29 @@ export default function SignIn() {
<LastUsedIndicator />
)}
</Button>
<Button
variant="outline"
className={cn("w-full gap-2 flex items-center relative")}
onClick={async () => {
await signIn.passkey({
fetchOptions: {
onSuccess() {
toast.success("Successfully signed in");
router.push(getCallbackURL(params));
},
onError(context) {
toast.error(
"Authentication failed: " + context.error.message,
);
},
},
});
}}
>
<Key size={16} />
<span>Sign in with Passkey</span>
{client.isLastUsedLoginMethod("passkey") && <LastUsedIndicator />}
</Button>
</div>
</div>
</CardContent>
+5 -5
View File
@@ -1,5 +1,10 @@
"use client";
import { Loader2, X } from "lucide-react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { useState, useTransition } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
Card,
@@ -11,12 +16,7 @@ import {
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useState, useTransition } from "react";
import { Loader2, X } from "lucide-react";
import { signUp } from "@/lib/auth-client";
import { toast } from "sonner";
import { useSearchParams, useRouter } from "next/navigation";
import Link from "next/link";
import { getCallbackURL } from "@/lib/shared";
export function SignUp() {
+1 -1
View File
@@ -1,5 +1,5 @@
import type React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import type React from "react";
import { cn } from "@/lib/utils";
const tierVariants = cva(
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDownIcon } from "@radix-ui/react-icons";
import * as React from "react";
import { cn } from "@/lib/utils";
+2 -3
View File
@@ -1,10 +1,9 @@
"use client";
import * as React from "react";
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
import { cn } from "@/lib/utils";
import * as React from "react";
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
const AlertDialog = AlertDialogPrimitive.Root;
+1 -1
View File
@@ -1,5 +1,5 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
+1 -1
View File
@@ -1,7 +1,7 @@
"use client";
import * as React from "react";
import * as AvatarPrimitive from "@radix-ui/react-avatar";
import * as React from "react";
import { cn } from "@/lib/utils";
+1 -1
View File
@@ -1,5 +1,5 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
+1 -1
View File
@@ -1,6 +1,6 @@
import * as React from "react";
import { ChevronRightIcon, DotsHorizontalIcon } from "@radix-ui/react-icons";
import { Slot } from "@radix-ui/react-slot";
import * as React from "react";
import { cn } from "@/lib/utils";
+1 -1
View File
@@ -1,6 +1,6 @@
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
+1 -2
View File
@@ -2,9 +2,8 @@
import * as React from "react";
import { DayPicker } from "react-day-picker";
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
+2 -3
View File
@@ -1,13 +1,12 @@
"use client";
import * as React from "react";
import { ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons";
import useEmblaCarousel, {
type UseEmblaCarouselType,
} from "embla-carousel-react";
import { cn } from "@/lib/utils";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
type CarouselApi = UseEmblaCarouselType[1];
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { CheckIcon } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
+2 -3
View File
@@ -1,10 +1,8 @@
"use client";
import * as React from "react";
import { Command as CommandPrimitive } from "cmdk";
import { SearchIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import * as React from "react";
import {
Dialog,
DialogContent,
@@ -12,6 +10,7 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
function Command({
className,
+1 -1
View File
@@ -1,12 +1,12 @@
"use client";
import * as React from "react";
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
import {
CheckIcon,
ChevronRightIcon,
DotFilledIcon,
} from "@radix-ui/react-icons";
import * as React from "react";
import { cn } from "@/lib/utils";
+2 -2
View File
@@ -1,6 +1,6 @@
import { useState, useEffect } from "react";
import { Check, Copy } from "lucide-react";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Copy, Check } from "lucide-react";
import {
Tooltip,
TooltipContent,
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { XIcon } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
+2 -3
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { Slot } from "@radix-ui/react-slot";
import * as React from "react";
import {
Controller,
ControllerProps,
@@ -11,9 +11,8 @@ import {
FormProvider,
useFormContext,
} from "react-hook-form";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
const Form = FormProvider;
+1 -1
View File
@@ -1,7 +1,7 @@
"use client";
import * as React from "react";
import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
import * as React from "react";
import { cn } from "@/lib/utils";
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import * as React from "react";
import { DashIcon } from "@radix-ui/react-icons";
import { OTPInput, OTPInputContext } from "input-otp";
import * as React from "react";
import { cn } from "@/lib/utils";

Some files were not shown because too many files have changed in this diff Show More