mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-09 12:27:43 +00:00
fix: a bunch of fixes
This commit is contained in:
129
demo/nextjs/app/(auth)/forget-password/page.tsx
Normal file
129
demo/nextjs/app/(auth)/forget-password/page.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
"use client";
|
||||
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
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("");
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setError("");
|
||||
|
||||
// Simulate API call
|
||||
try {
|
||||
const res = await client.forgetPassword({
|
||||
email,
|
||||
});
|
||||
// If the API call is successful, set isSubmitted to true
|
||||
setIsSubmitted(true);
|
||||
} catch (err) {
|
||||
setError("An error occurred. Please try again.");
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isSubmitted) {
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
|
||||
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Check your email</CardTitle>
|
||||
<CardDescription>
|
||||
We've sent a password reset link to your email.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Alert>
|
||||
<CheckCircle2 className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
If you don't see the email, check your spam folder.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={() => setIsSubmitted(false)}
|
||||
>
|
||||
<ArrowLeft className="mr-2 h-4 w-4" /> Back to reset password
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
|
||||
{/* Radial gradient for the container to give a faded look */}
|
||||
<div className="absolute pointer-events-none inset-0 flex items-center justify-center dark:bg-black bg-white [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]"></div>
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Forgot password</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your email to reset your password
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{error && (
|
||||
<Alert variant="destructive" className="mt-4">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<Button
|
||||
className="w-full mt-4"
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? "Sending..." : "Send reset link"}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-center">
|
||||
<Link href="/sign-in">
|
||||
<Button variant="link" className="px-0">
|
||||
Back to sign in
|
||||
</Button>
|
||||
</Link>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
96
demo/nextjs/app/(auth)/reset-password/[token]/page.tsx
Normal file
96
demo/nextjs/app/(auth)/reset-password/[token]/page.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
"use client";
|
||||
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
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({
|
||||
params,
|
||||
}: { params: { token: string } }) {
|
||||
const [password, setPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const token = params.token;
|
||||
const router = useRouter();
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setError("");
|
||||
const res = await client.resetPassword({
|
||||
token,
|
||||
newPassword: password,
|
||||
});
|
||||
if (res.error) {
|
||||
toast.error(res.error.message);
|
||||
}
|
||||
setIsSubmitting(false);
|
||||
router.push("/sign-in");
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
|
||||
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Reset password</CardTitle>
|
||||
<CardDescription>
|
||||
Enter new password and confirm it to reset your password
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Label htmlFor="email">New password</Label>
|
||||
<PasswordInput
|
||||
id="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
autoComplete="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Label htmlFor="email">Confirm password</Label>
|
||||
<PasswordInput
|
||||
id="password"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
autoComplete="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{error && (
|
||||
<Alert variant="destructive" className="mt-4">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<Button
|
||||
className="w-full mt-4"
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? "Resetting..." : "Reset password"}
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
120
demo/nextjs/app/(auth)/two-factor/otp/page.tsx
Normal file
120
demo/nextjs/app/(auth)/two-factor/otp/page.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
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("");
|
||||
const [isOtpSent, setIsOtpSent] = useState(false);
|
||||
const [message, setMessage] = useState("");
|
||||
const [isError, setIsError] = useState(false);
|
||||
const [isValidated, setIsValidated] = useState(false);
|
||||
const [OTP, setOTP] = useState("");
|
||||
|
||||
// In a real app, this email would come from your authentication context
|
||||
const userEmail = "user@example.com";
|
||||
|
||||
const requestOTP = async () => {
|
||||
const res = await client.twoFactor.sendOtp({
|
||||
options: {
|
||||
body: {
|
||||
returnOTP: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
setOTP(res.data?.OTP || "");
|
||||
// In a real app, this would call your backend API to send the OTP
|
||||
setMessage("OTP sent to your email");
|
||||
setIsError(false);
|
||||
setIsOtpSent(true);
|
||||
};
|
||||
const router = useRouter();
|
||||
|
||||
const validateOTP = async () => {
|
||||
const res = await client.twoFactor.verifyOtp({
|
||||
code: otp,
|
||||
});
|
||||
if (res.data) {
|
||||
setMessage("OTP validated successfully");
|
||||
setIsError(false);
|
||||
setIsValidated(true);
|
||||
router.push("/");
|
||||
} else {
|
||||
setIsError(true);
|
||||
setMessage("Invalid OTP");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Two-Factor Authentication</CardTitle>
|
||||
<CardDescription>
|
||||
Verify your identity with a one-time password
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid w-full items-center gap-4">
|
||||
{!isOtpSent ? (
|
||||
<Button onClick={requestOTP} className="w-full">
|
||||
<Mail className="mr-2 h-4 w-4" /> Send OTP to Email
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Label htmlFor="otp">One-Time Password</Label>
|
||||
<Label className="py-2">
|
||||
Use{" "}
|
||||
<span className="text-blue-100 bg-slate-800 px-2">
|
||||
{OTP}
|
||||
</span>{" "}
|
||||
(on real app, this would be sent to your email)
|
||||
</Label>
|
||||
<Input
|
||||
id="otp"
|
||||
placeholder="Enter 6-digit OTP"
|
||||
value={otp}
|
||||
onChange={(e) => setOtp(e.target.value)}
|
||||
maxLength={6}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
onClick={validateOTP}
|
||||
disabled={otp.length !== 6 || isValidated}
|
||||
>
|
||||
Validate OTP
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{message && (
|
||||
<div
|
||||
className={`flex items-center gap-2 mt-4 ${isError ? "text-red-500" : "text-primary"
|
||||
}`}
|
||||
>
|
||||
{isError ? (
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
) : (
|
||||
<CheckCircle2 className="h-4 w-4" />
|
||||
)}
|
||||
<p className="text-sm">{message}</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
97
demo/nextjs/app/(auth)/two-factor/page.tsx
Normal file
97
demo/nextjs/app/(auth)/two-factor/page.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
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("");
|
||||
const [error, setError] = useState("");
|
||||
const [success, setSuccess] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (totpCode.length !== 6 || !/^\d+$/.test(totpCode)) {
|
||||
setError("TOTP code must be 6 digits");
|
||||
return;
|
||||
}
|
||||
client.twoFactor
|
||||
.verifyTotp({
|
||||
code: totpCode,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data?.status) {
|
||||
setSuccess(true);
|
||||
setError("");
|
||||
} else {
|
||||
setError("Invalid TOTP code");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>TOTP Verification</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your 6-digit TOTP code to authenticate
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{!success ? (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="totp">TOTP Code</Label>
|
||||
<Input
|
||||
id="totp"
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
pattern="\d{6}"
|
||||
maxLength={6}
|
||||
value={totpCode}
|
||||
onChange={(e) => setTotpCode(e.target.value)}
|
||||
placeholder="Enter 6-digit code"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{error && (
|
||||
<div className="flex items-center mt-2 text-red-500">
|
||||
<AlertCircle className="w-4 h-4 mr-2" />
|
||||
<span className="text-sm">{error}</span>
|
||||
</div>
|
||||
)}
|
||||
<Button type="submit" className="w-full mt-4">
|
||||
Verify
|
||||
</Button>
|
||||
</form>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center space-y-2">
|
||||
<CheckCircle2 className="w-12 h-12 text-green-500" />
|
||||
<p className="text-lg font-semibold">Verification Successful</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
<CardFooter className="text-sm text-muted-foreground gap-2">
|
||||
<Link href="/two-factor/otp">
|
||||
<Button variant="link" size="sm">
|
||||
Switch to Email Verification
|
||||
</Button>
|
||||
</Link>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -37,7 +37,7 @@ export default function InvitationPage({
|
||||
setError(res.error.message || "An error occurred")
|
||||
} else {
|
||||
setInvitationStatus("accepted");
|
||||
router.push(`/organizations/${invitation?.organizationSlug}`)
|
||||
router.push(`/dashboard`)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@@ -145,7 +145,9 @@ export function OrganizationCard(props: {
|
||||
memberIdOrEmail: member.id
|
||||
})
|
||||
}}>
|
||||
Remove
|
||||
{
|
||||
currentMember?.id === member.id ? "Leave" : "Remove"
|
||||
}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ export default async function DashboardPage() {
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="flex gap-4 flex-col">
|
||||
<UserCard session={JSON.parse(JSON.stringify(session))} activeSessions={activeSessions} />
|
||||
<UserCard session={JSON.parse(JSON.stringify(session))} activeSessions={JSON.parse(JSON.stringify(activeSessions))} />
|
||||
<OrganizationCard session={JSON.parse(JSON.stringify(session))} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ import { PasswordInput } from "@/components/ui/password-input";
|
||||
import { client, signOut, user, useSession } from "@/lib/auth-client";
|
||||
import { Session } from "@/lib/auth-types";
|
||||
import { MobileIcon } from "@radix-ui/react-icons";
|
||||
import { Edit, Fingerprint, Laptop, Loader2, LogOut, Plus, Trash, X } from "lucide-react";
|
||||
import { Edit, Fingerprint, Laptop, Loader2, LogOut, Plus, QrCode, ShieldCheck, ShieldOff, Trash, X } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -25,6 +25,8 @@ import { toast } from "sonner";
|
||||
import { UAParser } from "ua-parser-js";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
import QRCode from "react-qr-code";
|
||||
import CopyButton from "@/components/ui/copy-button";
|
||||
|
||||
|
||||
export default function UserCard(props: {
|
||||
@@ -41,6 +43,24 @@ export default function UserCard(props: {
|
||||
setUa(new UAParser(session?.session.userAgent))
|
||||
}, [session?.session.userAgent])
|
||||
|
||||
const [isTerminating, setIsTerminating] = useState<string>();
|
||||
|
||||
const { data: qr } = useQuery({
|
||||
queryKey: ["two-factor-qr"],
|
||||
queryFn: async () => {
|
||||
const res = await client.twoFactor.getTotpUri()
|
||||
if (res.error) {
|
||||
throw res.error
|
||||
}
|
||||
return res.data
|
||||
},
|
||||
enabled: !!session?.user.twoFactorSecret
|
||||
})
|
||||
|
||||
const [isPendingTwoFa, setIsPendingTwoFa] = useState<boolean>(false);
|
||||
const [twoFaPassword, setTwoFaPassword] = useState<string>("");
|
||||
const [twoFactorDialog, setTwoFactorDialog] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
@@ -71,11 +91,30 @@ export default function UserCard(props: {
|
||||
{
|
||||
props.activeSessions.filter((session) => session.userAgent).map((session) => {
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-sm text-black font-medium dark:text-white" key={session.id}>
|
||||
<div key={session.id}>
|
||||
<div className="flex items-center gap-2 text-sm text-black font-medium dark:text-white">
|
||||
{
|
||||
new UAParser(session.userAgent).getDevice().type === "mobile" ? <MobileIcon /> : <Laptop size={16} />
|
||||
}
|
||||
{new UAParser(session.userAgent).getOS().name}, {new UAParser(session.userAgent).getBrowser().name}
|
||||
<button 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.user.revokeSession({
|
||||
id: session.id,
|
||||
})
|
||||
if (res.error) {
|
||||
toast.error(res.error.message)
|
||||
} else {
|
||||
toast.success("Session terminated successfully")
|
||||
}
|
||||
router.refresh()
|
||||
setIsTerminating(undefined)
|
||||
}}>
|
||||
{
|
||||
isTerminating === session.id ? <Loader2 size={15} className="animate-spin" /> : session.id === props.session?.session.id ? "Sign Out" : "Terminate"
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
@@ -93,35 +132,128 @@ export default function UserCard(props: {
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-sm">
|
||||
2FA Authentication
|
||||
Two Factor
|
||||
</p>
|
||||
{session?.user.twoFactorEnabled ? (
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="gap-2"
|
||||
onClick={async () => {
|
||||
const res = await client.twoFactor.disable();
|
||||
if (res.error) {
|
||||
toast.error(res.error.message);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Disable 2FA
|
||||
<div className="flex gap-2">
|
||||
{
|
||||
session?.user.twoFactorEnabled && (
|
||||
<Dialog >
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" className="gap-2">
|
||||
<QrCode size={16} />
|
||||
<span className="text-sm">
|
||||
Scan QR Code
|
||||
</span>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
className="gap-2"
|
||||
onClick={async () => {
|
||||
const res = await client.twoFactor.enable();
|
||||
if (res.error) {
|
||||
toast.error(res.error.message);
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
Scan QR Code
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
Scan the QR code with your TOTP app
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex items-center justify-center">
|
||||
<QRCode value={qr?.totpURI || ""} />
|
||||
</div>
|
||||
<div className="flex gap-2 items-center justify-center">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Copy URI to clipboard
|
||||
</p>
|
||||
<CopyButton textToCopy={qr?.totpURI || ""} />
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
}}
|
||||
<Dialog open={twoFactorDialog} onOpenChange={setTwoFactorDialog}>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant={
|
||||
session?.user.twoFactorEnabled ? "destructive" : "outline"
|
||||
}
|
||||
className="gap-2"
|
||||
>
|
||||
<p>Enable 2FA</p>
|
||||
{
|
||||
session?.user.twoFactorEnabled ? <ShieldOff size={16} /> : <ShieldCheck size={16} />
|
||||
}
|
||||
<span className="text-sm">
|
||||
{
|
||||
session?.user.twoFactorEnabled ? "Disable 2FA" : "Enable 2FA"
|
||||
}
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{
|
||||
session?.user.twoFactorEnabled ? "Disable 2FA" : "Enable 2FA"
|
||||
}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{
|
||||
session?.user.twoFactorEnabled ? "Disable the second factor authentication from your account" : "Enable 2FA to secure your account"
|
||||
}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<PasswordInput id="password" placeholder="Password" value={twoFaPassword} onChange={(e) => setTwoFaPassword(e.target.value)} />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
|
||||
<Button
|
||||
disabled={isPendingTwoFa}
|
||||
onClick={async () => {
|
||||
if (twoFaPassword.length < 8) {
|
||||
toast.error("Password must be at least 8 characters");
|
||||
return;
|
||||
}
|
||||
setIsPendingTwoFa(true);
|
||||
if (session?.user.twoFactorEnabled) {
|
||||
const res = await client.twoFactor.disable({
|
||||
//@ts-ignore
|
||||
password: twoFaPassword,
|
||||
options: {
|
||||
onError(context) {
|
||||
toast.error(context.error.message);
|
||||
},
|
||||
onSuccess() {
|
||||
toast("2FA disabled successfully");
|
||||
setTwoFactorDialog(false);
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const res = await client.twoFactor.enable({
|
||||
password: twoFaPassword,
|
||||
options: {
|
||||
onError(context) {
|
||||
toast.error(context.error.message);
|
||||
},
|
||||
onSuccess() {
|
||||
toast.success("2FA enabled successfully");
|
||||
setTwoFactorDialog(false);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
setIsPendingTwoFa(false);
|
||||
setTwoFaPassword("");
|
||||
}}>
|
||||
{
|
||||
isPendingTwoFa ? <Loader2 size={15} className="animate-spin" /> : session?.user.twoFactorEnabled ? "Disable 2FA" : "Enable 2FA"
|
||||
}
|
||||
</Button>
|
||||
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -38,7 +38,7 @@ export default async function Home() {
|
||||
<Link href="/sign-in">
|
||||
<Button className="gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24"><path fill="currentColor" d="M5 3H3v4h2V5h14v14H5v-2H3v4h18V3zm12 8h-2V9h-2V7h-2v2h2v2H3v2h10v2h-2v2h2v-2h2v-2h2z"></path></svg>
|
||||
Sign In
|
||||
Get Started
|
||||
</Button>
|
||||
</Link>
|
||||
)
|
||||
|
||||
@@ -77,7 +77,9 @@ export default function SignIn() {
|
||||
<Label>Remember me</Label>
|
||||
</div>
|
||||
|
||||
<Button type="submit" className="w-full" onClick={async () => {
|
||||
<Button type="submit" className="w-full"
|
||||
disabled={loading}
|
||||
onClick={async () => {
|
||||
await signIn.email({
|
||||
email: email,
|
||||
password: password,
|
||||
@@ -103,7 +105,12 @@ export default function SignIn() {
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full gap-2"
|
||||
onClick={async () => { }}
|
||||
onClick={async () => {
|
||||
await signIn.social({
|
||||
provider: "github",
|
||||
callbackURL: "/dashboard",
|
||||
})
|
||||
}}
|
||||
>
|
||||
<GitHubLogoIcon />
|
||||
Continue with Github
|
||||
@@ -112,7 +119,10 @@ export default function SignIn() {
|
||||
variant="outline"
|
||||
className="w-full gap-2"
|
||||
onClick={async () => {
|
||||
|
||||
await signIn.social({
|
||||
provider: "google",
|
||||
callbackURL: "/dashboard",
|
||||
})
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
@@ -140,7 +150,11 @@ export default function SignIn() {
|
||||
</svg>
|
||||
Continue with Google
|
||||
</Button>
|
||||
<Button variant="outline" className="gap-2" onClick={async () => { }}>
|
||||
<Button variant="outline" className="gap-2" onClick={async () => {
|
||||
await signIn.passkey({
|
||||
callbackURL: "/dashboard",
|
||||
})
|
||||
}}>
|
||||
<Key size={16} />
|
||||
Sign-in with Passkey
|
||||
</Button>
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Label } from "@/components/ui/label";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
import { GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||
import { useState } from "react";
|
||||
import { signUp } from "@/lib/auth-client";
|
||||
import { client, signIn, signUp } from "@/lib/auth-client";
|
||||
import Image from "next/image";
|
||||
import { Loader2, X } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
@@ -139,7 +139,9 @@ export function SignUp() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button type="submit" className="w-full" onClick={async () => {
|
||||
<Button type="submit" className="w-full"
|
||||
disabled={loading}
|
||||
onClick={async () => {
|
||||
await signUp.email({
|
||||
email,
|
||||
password,
|
||||
@@ -166,7 +168,21 @@ export function SignUp() {
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full gap-2"
|
||||
onClick={async () => { }}
|
||||
onClick={async () => {
|
||||
const res = await client.signIn.social({
|
||||
provider: "google",
|
||||
callbackURL: "/dashboard",
|
||||
options: {
|
||||
onRequest: () => {
|
||||
setLoading(true)
|
||||
},
|
||||
onResponse: () => {
|
||||
setLoading(false)
|
||||
},
|
||||
}
|
||||
})
|
||||
}}
|
||||
disabled={loading}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -196,7 +212,21 @@ export function SignUp() {
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full gap-2"
|
||||
onClick={async () => { }}
|
||||
onClick={async () => {
|
||||
await signIn.social({
|
||||
provider: "github",
|
||||
callbackURL: "/dashboard",
|
||||
options: {
|
||||
onRequest: () => {
|
||||
setLoading(true)
|
||||
},
|
||||
onResponse: () => {
|
||||
setLoading(false)
|
||||
},
|
||||
}
|
||||
})
|
||||
}}
|
||||
disabled={loading}
|
||||
>
|
||||
<GitHubLogoIcon />
|
||||
Continue with Github
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
import { organizationClient, passkeyClient, twoFactorClient } from "better-auth/client/plugins"
|
||||
import {
|
||||
organizationClient,
|
||||
passkeyClient,
|
||||
twoFactorClient,
|
||||
} from "better-auth/client/plugins";
|
||||
|
||||
export const client = createAuthClient({
|
||||
plugins: [organizationClient(), twoFactorClient(), passkeyClient()],
|
||||
plugins: [
|
||||
organizationClient(),
|
||||
twoFactorClient({
|
||||
twoFactorPage: "/two-factor",
|
||||
}),
|
||||
passkeyClient(),
|
||||
],
|
||||
fetchOptions: {
|
||||
credentials: 'include'
|
||||
}
|
||||
credentials: "include",
|
||||
},
|
||||
});
|
||||
|
||||
export const { signUp, signIn, signOut, useSession, user, organization, useListOrganizations, useActiveOrganization } = client;
|
||||
export const {
|
||||
signUp,
|
||||
signIn,
|
||||
signOut,
|
||||
useSession,
|
||||
user,
|
||||
organization,
|
||||
useListOrganizations,
|
||||
useActiveOrganization,
|
||||
} = client;
|
||||
|
||||
@@ -2,17 +2,38 @@ import { betterAuth } from "better-auth";
|
||||
import { organization, passkey, twoFactor } from "better-auth/plugins";
|
||||
import { Resend } from "resend";
|
||||
import { reactInvitationEmail } from "./email/invitation";
|
||||
import { LibsqlDialect } from "@libsql/kysely-libsql";
|
||||
import { github, google } from "better-auth/social-providers";
|
||||
import { reactResetPasswordEmail } from "./email/rest-password";
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
const from = process.env.BETTER_AUTH_EMAIL || "delivered@resend.dev";
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: {
|
||||
provider: "sqlite",
|
||||
url: "./auth.db",
|
||||
},
|
||||
database: new LibsqlDialect({
|
||||
url: process.env.TURSO_DATABASE_URL || "",
|
||||
authToken: process.env.TURSO_AUTH_TOKEN || "",
|
||||
}),
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
async sendResetPasswordToken(token, user) {
|
||||
const res = await resend.emails.send({
|
||||
from,
|
||||
to: user.email,
|
||||
subject: "Reset your password",
|
||||
react: reactResetPasswordEmail({
|
||||
username: user.email,
|
||||
resetLink: `${
|
||||
process.env.NODE_ENV === "development"
|
||||
? "http://localhost:3000"
|
||||
: process.env.NEXT_PUBLIC_APP_URL ||
|
||||
process.env.VERCEL_URL ||
|
||||
process.env.BETTER_AUTH_URL
|
||||
}/reset-password/${token}`,
|
||||
}),
|
||||
});
|
||||
console.log(res, user.email);
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
organization({
|
||||
@@ -39,9 +60,25 @@ export const auth = betterAuth({
|
||||
console.log(res, data.email);
|
||||
},
|
||||
}),
|
||||
twoFactor(),
|
||||
twoFactor({
|
||||
otpOptions: {
|
||||
sendOTP(user, otp) {
|
||||
console.log({ otp });
|
||||
},
|
||||
},
|
||||
}),
|
||||
passkey({
|
||||
rpID: "localhost",
|
||||
}),
|
||||
],
|
||||
socialProvider: [
|
||||
github({
|
||||
clientId: process.env.GITHUB_CLIENT_ID || "",
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET || "",
|
||||
}),
|
||||
google({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID || "",
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
71
demo/nextjs/lib/email/rest-password.tsx
Normal file
71
demo/nextjs/lib/email/rest-password.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import {
|
||||
Body,
|
||||
Button,
|
||||
Container,
|
||||
Head,
|
||||
Heading,
|
||||
Hr,
|
||||
Html,
|
||||
Link,
|
||||
Preview,
|
||||
Text,
|
||||
Tailwind,
|
||||
Section,
|
||||
} from "@react-email/components";
|
||||
import * as React from "react";
|
||||
|
||||
interface BetterAuthResetPasswordEmailProps {
|
||||
username?: string;
|
||||
resetLink?: string;
|
||||
}
|
||||
|
||||
export const ResetPasswordEmail = ({
|
||||
username,
|
||||
resetLink,
|
||||
}: BetterAuthResetPasswordEmailProps) => {
|
||||
const previewText = `Reset your BetterAuth password`;
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<Preview>{previewText}</Preview>
|
||||
<Tailwind>
|
||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
||||
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
|
||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
||||
Reset your <strong>Better Auth</strong> password
|
||||
</Heading>
|
||||
<Text className="text-black text-[14px] leading-[24px]">
|
||||
Hello {username},
|
||||
</Text>
|
||||
<Text className="text-black text-[14px] leading-[24px]">
|
||||
We received a request to reset your password for your Better Auth account. If you didn't make this request, you can safely ignore this email.
|
||||
</Text>
|
||||
<Section className="text-center mt-[32px] mb-[32px]">
|
||||
<Button
|
||||
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
|
||||
href={resetLink}
|
||||
>
|
||||
Reset Password
|
||||
</Button>
|
||||
</Section>
|
||||
<Text className="text-black text-[14px] leading-[24px]">
|
||||
Or copy and paste this URL into your browser:{" "}
|
||||
<Link href={resetLink} className="text-blue-600 no-underline">
|
||||
{resetLink}
|
||||
</Link>
|
||||
</Text>
|
||||
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
|
||||
<Text className="text-[#666666] text-[12px] leading-[24px]">
|
||||
If you didn't request a password reset, please ignore this email or contact support if you have concerns.
|
||||
</Text>
|
||||
</Container>
|
||||
</Body>
|
||||
</Tailwind>
|
||||
</Html>
|
||||
);
|
||||
};
|
||||
|
||||
export function reactResetPasswordEmail(props: BetterAuthResetPasswordEmailProps) {
|
||||
console.log(props);
|
||||
return <ResetPasswordEmail {...props} />;
|
||||
}
|
||||
@@ -63,6 +63,7 @@
|
||||
"react-day-picker": "8.10.1",
|
||||
"react-dom": "19.0.0-rc-7771d3a7-20240827",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-qr-code": "^2.0.15",
|
||||
"react-resizable-panels": "^2.1.2",
|
||||
"recharts": "^2.12.7",
|
||||
"resend": "^4.0.0",
|
||||
|
||||
@@ -39,10 +39,6 @@ export const callbackOAuth = createAuthEndpoint(
|
||||
);
|
||||
let tokens: OAuth2Tokens;
|
||||
try {
|
||||
console.log({
|
||||
data: c.query.code,
|
||||
codeVerifier,
|
||||
});
|
||||
tokens = await provider.validateAuthorizationCode(
|
||||
c.query.code,
|
||||
codeVerifier,
|
||||
|
||||
@@ -148,7 +148,13 @@ export const revokeSession = createAuthEndpoint(
|
||||
},
|
||||
async (ctx) => {
|
||||
const id = ctx.body.id;
|
||||
console.log(id);
|
||||
try {
|
||||
await ctx.context.internalAdapter.deleteSession(id);
|
||||
} catch (error) {
|
||||
ctx.context.logger.error(error);
|
||||
return ctx.json(null, { status: 500 });
|
||||
}
|
||||
return ctx.json({
|
||||
status: true,
|
||||
});
|
||||
@@ -165,9 +171,14 @@ export const revokeSessions = createAuthEndpoint(
|
||||
requireHeaders: true,
|
||||
},
|
||||
async (ctx) => {
|
||||
try {
|
||||
await ctx.context.internalAdapter.deleteSessions(
|
||||
ctx.context.session.user.id,
|
||||
);
|
||||
} catch (error) {
|
||||
ctx.context.logger.error(error);
|
||||
return ctx.json(null, { status: 500 });
|
||||
}
|
||||
return ctx.json({
|
||||
status: true,
|
||||
});
|
||||
|
||||
@@ -51,23 +51,27 @@ export const removeMember = createAuthEndpoint(
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
(session.user.email === ctx.body.memberIdOrEmail ||
|
||||
member.id === ctx.body.memberIdOrEmail) &&
|
||||
member.role === (ctx.context.orgOptions?.creatorRole || "owner")
|
||||
) {
|
||||
const isLeaving =
|
||||
session.user.email === ctx.body.memberIdOrEmail ||
|
||||
member.id === ctx.body.memberIdOrEmail;
|
||||
const isOwnerLeaving =
|
||||
isLeaving &&
|
||||
member.role === (ctx.context.orgOptions?.creatorRole || "owner");
|
||||
if (isOwnerLeaving) {
|
||||
return ctx.json(null, {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "You cannot delete yourself",
|
||||
message: "You cannot leave the organization as the owner",
|
||||
},
|
||||
});
|
||||
}
|
||||
const canDeleteMember = role.authorize({
|
||||
|
||||
const canDeleteMember =
|
||||
isLeaving ||
|
||||
role.authorize({
|
||||
member: ["delete"],
|
||||
});
|
||||
if (canDeleteMember.error) {
|
||||
}).success;
|
||||
if (!canDeleteMember) {
|
||||
return ctx.json(null, {
|
||||
body: {
|
||||
message: "You are not allowed to delete this member",
|
||||
|
||||
@@ -272,6 +272,19 @@ export const setActiveOrganization = createAuthEndpoint(
|
||||
}
|
||||
orgId = sessionOrgId;
|
||||
}
|
||||
const isMember = await adapter.findMemberByOrgId({
|
||||
userId: session.user.id,
|
||||
organizationId: orgId,
|
||||
});
|
||||
if (!isMember) {
|
||||
await adapter.setActiveOrganization(session.session.id, null);
|
||||
return ctx.json(null, {
|
||||
status: 400,
|
||||
body: {
|
||||
message: "You are not a member of this organization",
|
||||
},
|
||||
});
|
||||
}
|
||||
await adapter.setActiveOrganization(session.session.id, orgId);
|
||||
const organization = await adapter.findFullOrganization(
|
||||
orgId,
|
||||
|
||||
@@ -35,6 +35,7 @@ export const getPasskeyActions = (
|
||||
method: "POST",
|
||||
body: {
|
||||
email: opts?.email,
|
||||
callbackURL: opts?.callbackURL,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -203,11 +203,12 @@ export const passkey = (options?: PasskeyOptions) => {
|
||||
*/
|
||||
const data: WebAuthnCookieType = {
|
||||
expectedChallenge: options.challenge,
|
||||
callbackURL: ctx.body?.callbackURL,
|
||||
userData: {
|
||||
id: session?.user.id || "",
|
||||
},
|
||||
callbackURL: ctx.body?.callbackURL,
|
||||
};
|
||||
|
||||
await ctx.setSignedCookie(
|
||||
opts.advanced.webAuthnChallengeCookie,
|
||||
JSON.stringify(data),
|
||||
@@ -337,6 +338,7 @@ export const passkey = (options?: PasskeyOptions) => {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
console.log({ challengeString });
|
||||
const { expectedChallenge, callbackURL } = JSON.parse(
|
||||
challengeString,
|
||||
) as WebAuthnCookieType;
|
||||
@@ -400,6 +402,7 @@ export const passkey = (options?: PasskeyOptions) => {
|
||||
ctx.request,
|
||||
);
|
||||
await setSessionCookie(ctx, s.id);
|
||||
|
||||
if (callbackURL) {
|
||||
return ctx.json({
|
||||
url: callbackURL,
|
||||
|
||||
@@ -11,6 +11,7 @@ import { totp2fa } from "./totp";
|
||||
import type { TwoFactorOptions, UserWithTwoFactor } from "./types";
|
||||
import type { Session } from "../../adapters/schema";
|
||||
import { TWO_FACTOR_COOKIE_NAME, TRUST_DEVICE_COOKIE_NAME } from "./constant";
|
||||
import { validatePassword } from "../../utils/password";
|
||||
|
||||
export const twoFactor = (options?: TwoFactorOptions) => {
|
||||
const totp = totp2fa({
|
||||
@@ -29,10 +30,29 @@ export const twoFactor = (options?: TwoFactorOptions) => {
|
||||
"/two-factor/enable",
|
||||
{
|
||||
method: "POST",
|
||||
body: z.object({
|
||||
password: z.string().min(8),
|
||||
}),
|
||||
use: [sessionMiddleware],
|
||||
},
|
||||
async (ctx) => {
|
||||
const user = ctx.context.session.user as UserWithTwoFactor;
|
||||
const { password } = ctx.body;
|
||||
const isPasswordValid = await validatePassword(ctx, {
|
||||
password,
|
||||
userId: user.id,
|
||||
});
|
||||
if (!isPasswordValid) {
|
||||
return ctx.json(
|
||||
{ status: false },
|
||||
{
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid password",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
const secret = generateRandomString(16, alphabet("a-z", "0-9", "-"));
|
||||
const encryptedSecret = symmetricEncrypt({
|
||||
key: ctx.context.secret,
|
||||
@@ -63,10 +83,29 @@ export const twoFactor = (options?: TwoFactorOptions) => {
|
||||
"/two-factor/disable",
|
||||
{
|
||||
method: "POST",
|
||||
body: z.object({
|
||||
password: z.string().min(8),
|
||||
}),
|
||||
use: [sessionMiddleware],
|
||||
},
|
||||
async (ctx) => {
|
||||
const user = ctx.context.session.user as UserWithTwoFactor;
|
||||
const { password } = ctx.body;
|
||||
const isPasswordValid = await validatePassword(ctx, {
|
||||
password,
|
||||
userId: user.id,
|
||||
});
|
||||
if (!isPasswordValid) {
|
||||
return ctx.json(
|
||||
{ status: false },
|
||||
{
|
||||
status: 400,
|
||||
body: {
|
||||
message: "Invalid password",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
await ctx.context.adapter.update({
|
||||
model: "user",
|
||||
update: {
|
||||
|
||||
@@ -75,6 +75,11 @@ export const totp2fa = (options: TOTPOptions) => {
|
||||
});
|
||||
}
|
||||
const user = ctx.context.session.user as UserWithTwoFactor;
|
||||
if (!user.twoFactorSecret) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: "totp isn't enabled",
|
||||
});
|
||||
}
|
||||
return {
|
||||
totpURI: createTOTPKeyURI(
|
||||
options?.issuer || "BetterAuth",
|
||||
|
||||
@@ -38,6 +38,7 @@ describe("two factor", async () => {
|
||||
}
|
||||
it("should enable two factor", async () => {
|
||||
const res = await client.twoFactor.enable({
|
||||
password: testUser.password,
|
||||
options: {
|
||||
headers,
|
||||
},
|
||||
@@ -183,6 +184,7 @@ describe("two factor", async () => {
|
||||
|
||||
it("should disable two factor", async () => {
|
||||
const res = await client.twoFactor.disable({
|
||||
password: testUser.password,
|
||||
options: {
|
||||
headers,
|
||||
},
|
||||
|
||||
@@ -55,7 +55,12 @@ export const google = (options: GoogleOptions) => {
|
||||
throw new BetterAuthError("codeVerifier is required for Google");
|
||||
}
|
||||
const _scopes = scopes || ["email", "profile"];
|
||||
return googleArctic.createAuthorizationURL(state, codeVerifier, _scopes);
|
||||
const url = googleArctic.createAuthorizationURL(
|
||||
state,
|
||||
codeVerifier,
|
||||
_scopes,
|
||||
);
|
||||
return url;
|
||||
},
|
||||
validateAuthorizationCode: async (code, codeVerifier, redirectURI) => {
|
||||
return validateAuthorizationCode({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createOAuth2Request, sendTokenRequest } from "arctic/dist/request";
|
||||
import { OAuth2Tokens } from "arctic";
|
||||
import type { ProviderOptions } from ".";
|
||||
import { getBaseURL } from "../utils/base-url";
|
||||
import { betterFetch } from "@better-fetch/fetch";
|
||||
|
||||
export function getRedirectURI(providerId: string, redirectURI?: string) {
|
||||
return redirectURI || `${getBaseURL()}/callback/${providerId}`;
|
||||
@@ -26,7 +27,19 @@ export async function validateAuthorizationCode({
|
||||
body.set("redirect_uri", redirectURI);
|
||||
body.set("client_id", options.clientId);
|
||||
body.set("client_secret", options.clientSecret);
|
||||
const request = createOAuth2Request(tokenEndpoint, body);
|
||||
const tokens = await sendTokenRequest(request);
|
||||
const { data, error } = await betterFetch<object>(tokenEndpoint, {
|
||||
method: "POST",
|
||||
body: body,
|
||||
headers: {
|
||||
"content-type": "application/x-www-form-urlencoded",
|
||||
accept: "application/json",
|
||||
"user-agent": "better-auth",
|
||||
},
|
||||
});
|
||||
console.log({ data, error, body });
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
const tokens = new OAuth2Tokens(data);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ import type { Primitive } from "zod";
|
||||
|
||||
export type LiteralString = "" | (string & Record<never, never>);
|
||||
|
||||
export type Prettify<T> = {
|
||||
[key in keyof T]: T[key];
|
||||
} & {};
|
||||
|
||||
export type Prettify<T> = Omit<T, never>;
|
||||
export type LiteralUnion<LiteralType, BaseType extends Primitive> =
|
||||
| LiteralType
|
||||
| (BaseType & Record<never, never>);
|
||||
@@ -30,25 +27,3 @@ export type RequiredKeysOf<BaseType extends object> = Exclude<
|
||||
export type HasRequiredKeys<BaseType extends object> =
|
||||
RequiredKeysOf<BaseType> extends never ? false : true;
|
||||
export type WithoutEmpty<T> = T extends T ? ({} extends T ? never : T) : never;
|
||||
|
||||
type LastOf<T> = UnionToIntersection<
|
||||
T extends any ? () => T : never
|
||||
> extends () => infer R
|
||||
? R
|
||||
: never;
|
||||
|
||||
type Push<T extends any[], V> = [...T, V];
|
||||
|
||||
type TuplifyUnion<
|
||||
T,
|
||||
L = LastOf<T>,
|
||||
N = [T] extends [never] ? true : false,
|
||||
> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>;
|
||||
|
||||
// The magic happens here!
|
||||
export type Tuple<
|
||||
T,
|
||||
A extends T[] = [],
|
||||
> = TuplifyUnion<T>["length"] extends A["length"]
|
||||
? [...A]
|
||||
: Tuple<T, [T, ...A]>;
|
||||
|
||||
23
packages/better-auth/src/utils/password.ts
Normal file
23
packages/better-auth/src/utils/password.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { GenericEndpointContext } from "../types/context";
|
||||
|
||||
export async function validatePassword(
|
||||
ctx: GenericEndpointContext,
|
||||
data: {
|
||||
password: string;
|
||||
userId: string;
|
||||
},
|
||||
) {
|
||||
const accounts = await ctx.context.internalAdapter.findAccounts(data.userId);
|
||||
const credentialAccount = accounts?.find(
|
||||
(account) => account.providerId === "credential",
|
||||
);
|
||||
const currentPassword = credentialAccount?.password;
|
||||
if (!credentialAccount || !currentPassword) {
|
||||
return false;
|
||||
}
|
||||
const compare = await ctx.context.password.verify(
|
||||
currentPassword,
|
||||
data.password,
|
||||
);
|
||||
return compare;
|
||||
}
|
||||
314
pnpm-lock.yaml
generated
314
pnpm-lock.yaml
generated
@@ -198,6 +198,9 @@ importers:
|
||||
react-hook-form:
|
||||
specifier: ^7.53.0
|
||||
version: 7.53.0(react@19.0.0-rc-7771d3a7-20240827)
|
||||
react-qr-code:
|
||||
specifier: ^2.0.15
|
||||
version: 2.0.15(react@19.0.0-rc-7771d3a7-20240827)
|
||||
react-resizable-panels:
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2(react-dom@19.0.0-rc-7771d3a7-20240827(react@19.0.0-rc-7771d3a7-20240827))(react@19.0.0-rc-7771d3a7-20240827)
|
||||
@@ -264,7 +267,7 @@ importers:
|
||||
version: 1.12.2(hono@4.5.9)
|
||||
better-auth:
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.6.2)(vue@3.5.5(typescript@5.6.2))
|
||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.6.2)(vue@3.5.6(typescript@5.6.2))
|
||||
dotenv:
|
||||
specifier: ^16.4.5
|
||||
version: 16.4.5
|
||||
@@ -526,13 +529,13 @@ importers:
|
||||
dependencies:
|
||||
better-auth:
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.6.2)(vue@3.5.5(typescript@5.6.2))
|
||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.6.2)(vue@3.5.6(typescript@5.6.2))
|
||||
nuxt:
|
||||
specifier: ^3.13.0
|
||||
version: 3.13.0(@biomejs/biome@1.7.3)(@parcel/watcher@2.4.1)(@types/node@22.3.0)(eslint@9.9.1(jiti@1.21.6))(ioredis@5.4.1)(lightningcss@1.22.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.2)(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))
|
||||
vue:
|
||||
specifier: latest
|
||||
version: 3.5.5(typescript@5.6.2)
|
||||
version: 3.5.6(typescript@5.6.2)
|
||||
|
||||
dev/solidjs:
|
||||
dependencies:
|
||||
@@ -565,7 +568,7 @@ importers:
|
||||
dependencies:
|
||||
better-auth:
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.5(typescript@5.5.4))
|
||||
version: 0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.6(typescript@5.5.4))
|
||||
devDependencies:
|
||||
'@sveltejs/adapter-auto':
|
||||
specifier: ^3.0.0
|
||||
@@ -581,7 +584,7 @@ importers:
|
||||
version: 4.2.19
|
||||
svelte-check:
|
||||
specifier: ^3.6.0
|
||||
version: 3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.44)(svelte@4.2.19)
|
||||
version: 3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.47)(svelte@4.2.19)
|
||||
typescript:
|
||||
specifier: ^5.0.0
|
||||
version: 5.5.4
|
||||
@@ -1124,7 +1127,7 @@ importers:
|
||||
version: 2.2.5(react@18.3.1)
|
||||
tsup:
|
||||
specifier: ^8.2.4
|
||||
version: 8.2.4(@swc/core@1.7.26(@swc/helpers@0.5.13))(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0)
|
||||
version: 8.2.4(@swc/core@1.7.26(@swc/helpers@0.5.13))(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0)
|
||||
typescript:
|
||||
specifier: 5.6.0-beta
|
||||
version: 5.6.0-beta
|
||||
@@ -2745,7 +2748,7 @@ packages:
|
||||
|
||||
'@expo/bunyan@4.0.1':
|
||||
resolution: {integrity: sha512-+Lla7nYSiHZirgK+U/uYzsLv/X+HaJienbD5AKX1UQZHYfWaP+9uuQluRB4GrEVWF0GZ7vEVp/jzaOT9k/SQlg==}
|
||||
engines: {'0': node >=0.10.0}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
'@expo/cli@0.18.29':
|
||||
resolution: {integrity: sha512-X810C48Ss+67RdZU39YEO1khNYo1RmjouRV+vVe0QhMoTe8R6OA3t+XYEdwaNbJ5p/DJN7szfHfNmX2glpC7xg==}
|
||||
@@ -5824,39 +5827,39 @@ packages:
|
||||
'@vue/compiler-core@3.5.0':
|
||||
resolution: {integrity: sha512-ja7cpqAOfw4tyFAxgBz70Z42miNDeaqTxExTsnXDLomRpqfyCgyvZvFp482fmsElpfvsoMJUsvzULhvxUTW6Iw==}
|
||||
|
||||
'@vue/compiler-core@3.5.4':
|
||||
resolution: {integrity: sha512-oNwn+BAt3n9dK9uAYvI+XGlutwuTq/wfj4xCBaZCqwwVIGtD7D6ViihEbyYZrDHIHTDE3Q6oL3/hqmAyFEy9DQ==}
|
||||
|
||||
'@vue/compiler-core@3.5.5':
|
||||
resolution: {integrity: sha512-ZrxcY8JMoV+kgDrmRwlDufz0SjDZ7jfoNZiIBluAACMBmgr55o/jTbxnyrccH6VSJXnFaDI4Ik1UFCiq9r8i7w==}
|
||||
|
||||
'@vue/compiler-core@3.5.6':
|
||||
resolution: {integrity: sha512-r+gNu6K4lrvaQLQGmf+1gc41p3FO2OUJyWmNqaIITaJU6YFiV5PtQSFZt8jfztYyARwqhoCayjprC7KMvT3nRA==}
|
||||
|
||||
'@vue/compiler-dom@3.5.0':
|
||||
resolution: {integrity: sha512-xYjUybWZXl+1R/toDy815i4PbeehL2hThiSGkcpmIOCy2HoYyeeC/gAWK/Y/xsoK+GSw198/T5O31bYuQx5uvQ==}
|
||||
|
||||
'@vue/compiler-dom@3.5.4':
|
||||
resolution: {integrity: sha512-yP9RRs4BDLOLfldn6ah+AGCNovGjMbL9uHvhDHf5wan4dAHLnFGOkqtfE7PPe4HTXIqE7l/NILdYw53bo1C8jw==}
|
||||
|
||||
'@vue/compiler-dom@3.5.5':
|
||||
resolution: {integrity: sha512-HSvK5q1gmBbxRse3S0Wt34RcKuOyjDJKDDMuF3i7NC+QkDFrbAqw8NnrEm/z7zFDxWZa4/5eUwsBOMQzm1RHBA==}
|
||||
|
||||
'@vue/compiler-dom@3.5.6':
|
||||
resolution: {integrity: sha512-xRXqxDrIqK8v8sSScpistyYH0qYqxakpsIvqMD2e5sV/PXQ1mTwtXp4k42yHK06KXxKSmitop9e45Ui/3BrTEw==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.0':
|
||||
resolution: {integrity: sha512-B9DgLtrqok2GLuaFjLlSL15ZG3ZDBiitUH1ecex9guh/ZcA5MCdwuVE6nsfQxktuZY/QY0awJ35/ripIviCQTQ==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.4':
|
||||
resolution: {integrity: sha512-P+yiPhL+NYH7m0ZgCq7AQR2q7OIE+mpAEgtkqEeH9oHSdIRvUO+4X6MPvblJIWcoe4YC5a2Gdf/RsoyP8FFiPQ==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.5':
|
||||
resolution: {integrity: sha512-MzBHDxwZhgQPHrwJ5tj92gdTYRCuPDSZr8PY3+JFv8cv2UD5/WayH5yo0kKCkKfrtJhc39jNSMityHrkMSbfnA==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.6':
|
||||
resolution: {integrity: sha512-pjWJ8Kj9TDHlbF5LywjVso+BIxCY5wVOLhkEXRhuCHDxPFIeX1zaFefKs8RYoHvkSMqRWt93a0f2gNJVJixHwg==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.0':
|
||||
resolution: {integrity: sha512-E263QZmA1dqRd7c3u/sWTLRMpQOT0aZ8av/L9SoD/v/BVMZaWFHPUUBswS+bzrfvG2suJF8vSLKx6k6ba5SUdA==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.4':
|
||||
resolution: {integrity: sha512-acESdTXsxPnYr2C4Blv0ggx5zIFMgOzZmYU2UgvIff9POdRGbRNBHRyzHAnizcItvpgerSKQbllUc9USp3V7eg==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.5':
|
||||
resolution: {integrity: sha512-oFasHnpv/upubjJEmqiTKQYb4qS3ziJddf4UVWuFw6ebk/QTrTUc+AUoTJdo39x9g+AOQBzhOU0ICCRuUjvkmw==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.6':
|
||||
resolution: {integrity: sha512-VpWbaZrEOCqnmqjE83xdwegtr5qO/2OPUC6veWgvNqTJ3bYysz6vY3VqMuOijubuUYPRpG3OOKIh9TD0Stxb9A==}
|
||||
|
||||
'@vue/devtools-api@6.6.3':
|
||||
resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==}
|
||||
|
||||
@@ -5872,30 +5875,30 @@ packages:
|
||||
'@vue/reactivity@3.5.0':
|
||||
resolution: {integrity: sha512-Ew3F5riP3B3ZDGjD3ZKb9uZylTTPSqt8hAf4sGbvbjrjDjrFb3Jm15Tk1/w7WwTE5GbQ2Qhwxx1moc9hr8A/OQ==}
|
||||
|
||||
'@vue/reactivity@3.5.5':
|
||||
resolution: {integrity: sha512-V4tTWElZQhT73PSK3Wnax9R9m4qvMX+LeKHnfylZc6SLh4Jc5/BPakp6e3zEhKWi5AN8TDzRkGnLkp8OqycYng==}
|
||||
'@vue/reactivity@3.5.6':
|
||||
resolution: {integrity: sha512-shZ+KtBoHna5GyUxWfoFVBCVd7k56m6lGhk5e+J9AKjheHF6yob5eukssHRI+rzvHBiU1sWs/1ZhNbLExc5oYQ==}
|
||||
|
||||
'@vue/runtime-core@3.5.0':
|
||||
resolution: {integrity: sha512-mQyW0F9FaNRdt8ghkAs+BMG3iQ7LGgWKOpkzUzR5AI5swPNydHGL5hvVTqFaeMzwecF1g0c86H4yFQsSxJhH1w==}
|
||||
|
||||
'@vue/runtime-core@3.5.5':
|
||||
resolution: {integrity: sha512-2/CFaRN17jgsXy4MpigWFBCAMmLkXPb4CjaHrndglwYSra7ajvkH2cat21dscuXaH91G8fXAeg5gCyxWJ+wCRA==}
|
||||
'@vue/runtime-core@3.5.6':
|
||||
resolution: {integrity: sha512-FpFULR6+c2lI+m1fIGONLDqPQO34jxV8g6A4wBOgne8eSRHP6PQL27+kWFIx5wNhhjkO7B4rgtsHAmWv7qKvbg==}
|
||||
|
||||
'@vue/runtime-dom@3.5.0':
|
||||
resolution: {integrity: sha512-NQQXjpdXgyYVJ2M56FJ+lSJgZiecgQ2HhxhnQBN95FymXegRNY/N2htI7vOTwpP75pfxhIeYOJ8mE8sW8KAW6A==}
|
||||
|
||||
'@vue/runtime-dom@3.5.5':
|
||||
resolution: {integrity: sha512-0bQGgCuL+4Muz5PsCLgF4Ata9BTdhHi5VjsxtTDyI0Wy4MgoSvBGaA6bDc7W7CGgZOyirf9LNeetMYHQ05pgpw==}
|
||||
'@vue/runtime-dom@3.5.6':
|
||||
resolution: {integrity: sha512-SDPseWre45G38ENH2zXRAHL1dw/rr5qp91lS4lt/nHvMr0MhsbCbihGAWLXNB/6VfFOJe2O+RBRkXU+CJF7/sw==}
|
||||
|
||||
'@vue/server-renderer@3.5.0':
|
||||
resolution: {integrity: sha512-HyDIFUg+l7L4PKrEnJlCYWHUOlm6NxZhmSxIefZ5MTYjkIPfDfkwhX7hqxAQHfgIAE1uLMLQZwuNR/ozI0NhZg==}
|
||||
peerDependencies:
|
||||
vue: 3.5.0
|
||||
|
||||
'@vue/server-renderer@3.5.5':
|
||||
resolution: {integrity: sha512-XjRamLIq5f47cxgy+hiX7zUIY+4RHdPDVrPvvMDAUTdW5RJWX/S0ji/rCbm3LWTT/9Co9bvQME8ZI15ahL4/Qw==}
|
||||
'@vue/server-renderer@3.5.6':
|
||||
resolution: {integrity: sha512-zivnxQnOnwEXVaT9CstJ64rZFXMS5ZkKxCjDQKiMSvUhXRzFLWZVbaBiNF4HGDqGNNsTgmjcCSmU6TB/0OOxLA==}
|
||||
peerDependencies:
|
||||
vue: 3.5.5
|
||||
vue: 3.5.6
|
||||
|
||||
'@vue/shared@3.4.38':
|
||||
resolution: {integrity: sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==}
|
||||
@@ -5903,12 +5906,12 @@ packages:
|
||||
'@vue/shared@3.5.0':
|
||||
resolution: {integrity: sha512-m9IgiteBpCkFaMNwCOBkFksA7z8QiKc30ooRuoXWUFRDu0mGyNPlFHmbncF0/Kra1RlX8QrmBbRaIxVvikaR0Q==}
|
||||
|
||||
'@vue/shared@3.5.4':
|
||||
resolution: {integrity: sha512-L2MCDD8l7yC62Te5UUyPVpmexhL9ipVnYRw9CsWfm/BGRL5FwDX4a25bcJ/OJSD3+Hx+k/a8LDKcG2AFdJV3BA==}
|
||||
|
||||
'@vue/shared@3.5.5':
|
||||
resolution: {integrity: sha512-0KyMXyEgnmFAs6rNUL+6eUHtUCqCaNrVd+AW3MX3LyA0Yry5SA0Km03CDKiOua1x1WWnIr+W9+S0GMFoSDWERQ==}
|
||||
|
||||
'@vue/shared@3.5.6':
|
||||
resolution: {integrity: sha512-eidH0HInnL39z6wAt6SFIwBrvGOpDWsDxlw3rCgo1B+CQ1781WzQUSU3YjxgdkcJo9Q8S6LmXTkvI+cLHGkQfA==}
|
||||
|
||||
'@web3-storage/multipart-parser@1.0.0':
|
||||
resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==}
|
||||
|
||||
@@ -9195,6 +9198,7 @@ packages:
|
||||
|
||||
libsql@0.3.19:
|
||||
resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==}
|
||||
cpu: [x64, arm64, wasm32]
|
||||
os: [darwin, linux, win32]
|
||||
|
||||
lighthouse-logger@1.4.2:
|
||||
@@ -10616,6 +10620,9 @@ packages:
|
||||
picocolors@1.0.1:
|
||||
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
|
||||
|
||||
picocolors@1.1.0:
|
||||
resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==}
|
||||
|
||||
picomatch@2.3.1:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
@@ -10904,6 +10911,10 @@ packages:
|
||||
resolution: {integrity: sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postcss@8.4.47:
|
||||
resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
postgres-array@2.0.0:
|
||||
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -11801,6 +11812,10 @@ packages:
|
||||
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
source-map-support@0.5.21:
|
||||
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
|
||||
|
||||
@@ -13061,8 +13076,8 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
vue@3.5.5:
|
||||
resolution: {integrity: sha512-ybC+xn67K4+df1yVeov4UjBGyVcXM0a1g7JVZr+pWVUX3xF6ntXU0wIjkTkduZBUIpxTlsftJSxz2kwhsT7dgA==}
|
||||
vue@3.5.6:
|
||||
resolution: {integrity: sha512-zv+20E2VIYbcJOzJPUWp03NOGFhMmpCKOfSxVTmCYyYFFko48H9tmuQFzYj7tu4qX1AeXlp9DmhIP89/sSxxhw==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
@@ -15576,17 +15591,17 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@vue/devtools-api': 6.6.3
|
||||
|
||||
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.5(typescript@5.5.4))':
|
||||
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.6(typescript@5.5.4))':
|
||||
dependencies:
|
||||
nanostores: 0.11.2
|
||||
vue: 3.5.5(typescript@5.5.4)
|
||||
vue: 3.5.6(typescript@5.5.4)
|
||||
optionalDependencies:
|
||||
'@vue/devtools-api': 6.6.3
|
||||
|
||||
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.5(typescript@5.6.2))':
|
||||
'@nanostores/vue@0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.6(typescript@5.6.2))':
|
||||
dependencies:
|
||||
nanostores: 0.11.2
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
optionalDependencies:
|
||||
'@vue/devtools-api': 6.6.3
|
||||
|
||||
@@ -15985,12 +16000,12 @@ snapshots:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
||||
'@nuxt/vite-builder@3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1(jiti@1.21.6))(lightningcss@1.22.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.2)(vue@3.5.5(typescript@5.6.2))':
|
||||
'@nuxt/vite-builder@3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1(jiti@1.21.6))(lightningcss@1.22.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.2)(vue@3.5.6(typescript@5.6.2))':
|
||||
dependencies:
|
||||
'@nuxt/kit': 3.13.0(magicast@0.3.5)(rollup@4.21.2)
|
||||
'@rollup/plugin-replace': 5.0.7(rollup@4.21.2)
|
||||
'@vitejs/plugin-vue': 5.1.3(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.5(typescript@5.6.2))
|
||||
'@vitejs/plugin-vue-jsx': 4.0.1(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.5(typescript@5.6.2))
|
||||
'@vitejs/plugin-vue': 5.1.3(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.6(typescript@5.6.2))
|
||||
'@vitejs/plugin-vue-jsx': 4.0.1(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.6(typescript@5.6.2))
|
||||
autoprefixer: 10.4.20(postcss@8.4.44)
|
||||
clear: 0.1.0
|
||||
consola: 3.2.3
|
||||
@@ -16019,7 +16034,7 @@ snapshots:
|
||||
vite: 5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6)
|
||||
vite-node: 2.0.5(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6)
|
||||
vite-plugin-checker: 0.7.2(@biomejs/biome@1.7.3)(eslint@9.9.1(jiti@1.21.6))(optionator@0.9.4)(typescript@5.6.2)(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
vue-bundle-renderer: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
- '@biomejs/biome'
|
||||
@@ -19916,13 +19931,13 @@ snapshots:
|
||||
'@unhead/schema': 1.10.0
|
||||
'@unhead/shared': 1.10.0
|
||||
|
||||
'@unhead/vue@1.10.0(vue@3.5.5(typescript@5.6.2))':
|
||||
'@unhead/vue@1.10.0(vue@3.5.6(typescript@5.6.2))':
|
||||
dependencies:
|
||||
'@unhead/schema': 1.10.0
|
||||
'@unhead/shared': 1.10.0
|
||||
hookable: 5.5.3
|
||||
unhead: 1.10.0
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
|
||||
'@urql/core@2.3.6(graphql@15.8.0)':
|
||||
dependencies:
|
||||
@@ -20022,20 +20037,20 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-vue-jsx@4.0.1(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.5(typescript@5.6.2))':
|
||||
'@vitejs/plugin-vue-jsx@4.0.1(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.6(typescript@5.6.2))':
|
||||
dependencies:
|
||||
'@babel/core': 7.25.2
|
||||
'@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2)
|
||||
'@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2)
|
||||
vite: 5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6)
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-vue@5.1.3(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.5(typescript@5.6.2))':
|
||||
'@vitejs/plugin-vue@5.1.3(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))(vue@3.5.6(typescript@5.6.2))':
|
||||
dependencies:
|
||||
vite: 5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6)
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
|
||||
'@vitest/expect@1.6.0':
|
||||
dependencies:
|
||||
@@ -20066,16 +20081,16 @@ snapshots:
|
||||
loupe: 2.3.7
|
||||
pretty-format: 29.7.0
|
||||
|
||||
'@vue-macros/common@1.12.2(rollup@4.21.2)(vue@3.5.5(typescript@5.6.2))':
|
||||
'@vue-macros/common@1.12.2(rollup@4.21.2)(vue@3.5.6(typescript@5.6.2))':
|
||||
dependencies:
|
||||
'@babel/types': 7.25.6
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.21.2)
|
||||
'@vue/compiler-sfc': 3.5.4
|
||||
'@vue/compiler-sfc': 3.5.5
|
||||
ast-kit: 1.1.0
|
||||
local-pkg: 0.5.0
|
||||
magic-string-ast: 0.6.2
|
||||
optionalDependencies:
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
|
||||
@@ -20106,7 +20121,7 @@ snapshots:
|
||||
'@babel/helper-module-imports': 7.22.15
|
||||
'@babel/helper-plugin-utils': 7.24.8
|
||||
'@babel/parser': 7.25.6
|
||||
'@vue/compiler-sfc': 3.5.4
|
||||
'@vue/compiler-sfc': 3.5.5
|
||||
|
||||
'@vue/compiler-core@3.5.0':
|
||||
dependencies:
|
||||
@@ -20116,14 +20131,6 @@ snapshots:
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-core@3.5.4':
|
||||
dependencies:
|
||||
'@babel/parser': 7.25.6
|
||||
'@vue/shared': 3.5.4
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-core@3.5.5':
|
||||
dependencies:
|
||||
'@babel/parser': 7.25.6
|
||||
@@ -20132,21 +20139,29 @@ snapshots:
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-core@3.5.6':
|
||||
dependencies:
|
||||
'@babel/parser': 7.25.6
|
||||
'@vue/shared': 3.5.6
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-dom@3.5.0':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.0
|
||||
'@vue/shared': 3.5.0
|
||||
|
||||
'@vue/compiler-dom@3.5.4':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.4
|
||||
'@vue/shared': 3.5.4
|
||||
|
||||
'@vue/compiler-dom@3.5.5':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.5
|
||||
'@vue/shared': 3.5.5
|
||||
|
||||
'@vue/compiler-dom@3.5.6':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.6
|
||||
'@vue/shared': 3.5.6
|
||||
|
||||
'@vue/compiler-sfc@3.5.0':
|
||||
dependencies:
|
||||
'@babel/parser': 7.25.6
|
||||
@@ -20159,18 +20174,6 @@ snapshots:
|
||||
postcss: 8.4.44
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-sfc@3.5.4':
|
||||
dependencies:
|
||||
'@babel/parser': 7.25.6
|
||||
'@vue/compiler-core': 3.5.4
|
||||
'@vue/compiler-dom': 3.5.4
|
||||
'@vue/compiler-ssr': 3.5.4
|
||||
'@vue/shared': 3.5.4
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.11
|
||||
postcss: 8.4.44
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-sfc@3.5.5':
|
||||
dependencies:
|
||||
'@babel/parser': 7.25.6
|
||||
@@ -20183,21 +20186,33 @@ snapshots:
|
||||
postcss: 8.4.44
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-sfc@3.5.6':
|
||||
dependencies:
|
||||
'@babel/parser': 7.25.6
|
||||
'@vue/compiler-core': 3.5.6
|
||||
'@vue/compiler-dom': 3.5.6
|
||||
'@vue/compiler-ssr': 3.5.6
|
||||
'@vue/shared': 3.5.6
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.11
|
||||
postcss: 8.4.47
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-ssr@3.5.0':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.0
|
||||
'@vue/shared': 3.5.0
|
||||
|
||||
'@vue/compiler-ssr@3.5.4':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.4
|
||||
'@vue/shared': 3.5.4
|
||||
|
||||
'@vue/compiler-ssr@3.5.5':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.5
|
||||
'@vue/shared': 3.5.5
|
||||
|
||||
'@vue/compiler-ssr@3.5.6':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.6
|
||||
'@vue/shared': 3.5.6
|
||||
|
||||
'@vue/devtools-api@6.6.3': {}
|
||||
|
||||
'@vue/devtools-core@7.3.3(vite@5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6))':
|
||||
@@ -20229,19 +20244,19 @@ snapshots:
|
||||
dependencies:
|
||||
'@vue/shared': 3.5.0
|
||||
|
||||
'@vue/reactivity@3.5.5':
|
||||
'@vue/reactivity@3.5.6':
|
||||
dependencies:
|
||||
'@vue/shared': 3.5.5
|
||||
'@vue/shared': 3.5.6
|
||||
|
||||
'@vue/runtime-core@3.5.0':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.0
|
||||
'@vue/shared': 3.5.0
|
||||
|
||||
'@vue/runtime-core@3.5.5':
|
||||
'@vue/runtime-core@3.5.6':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.5
|
||||
'@vue/shared': 3.5.5
|
||||
'@vue/reactivity': 3.5.6
|
||||
'@vue/shared': 3.5.6
|
||||
|
||||
'@vue/runtime-dom@3.5.0':
|
||||
dependencies:
|
||||
@@ -20250,11 +20265,11 @@ snapshots:
|
||||
'@vue/shared': 3.5.0
|
||||
csstype: 3.1.3
|
||||
|
||||
'@vue/runtime-dom@3.5.5':
|
||||
'@vue/runtime-dom@3.5.6':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.5
|
||||
'@vue/runtime-core': 3.5.5
|
||||
'@vue/shared': 3.5.5
|
||||
'@vue/reactivity': 3.5.6
|
||||
'@vue/runtime-core': 3.5.6
|
||||
'@vue/shared': 3.5.6
|
||||
csstype: 3.1.3
|
||||
|
||||
'@vue/server-renderer@3.5.0(vue@3.5.0(typescript@5.6.0-beta))':
|
||||
@@ -20263,26 +20278,26 @@ snapshots:
|
||||
'@vue/shared': 3.5.0
|
||||
vue: 3.5.0(typescript@5.6.0-beta)
|
||||
|
||||
'@vue/server-renderer@3.5.5(vue@3.5.5(typescript@5.5.4))':
|
||||
'@vue/server-renderer@3.5.6(vue@3.5.6(typescript@5.5.4))':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.5.5
|
||||
'@vue/shared': 3.5.5
|
||||
vue: 3.5.5(typescript@5.5.4)
|
||||
'@vue/compiler-ssr': 3.5.6
|
||||
'@vue/shared': 3.5.6
|
||||
vue: 3.5.6(typescript@5.5.4)
|
||||
|
||||
'@vue/server-renderer@3.5.5(vue@3.5.5(typescript@5.6.2))':
|
||||
'@vue/server-renderer@3.5.6(vue@3.5.6(typescript@5.6.2))':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.5.5
|
||||
'@vue/shared': 3.5.5
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
'@vue/compiler-ssr': 3.5.6
|
||||
'@vue/shared': 3.5.6
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
|
||||
'@vue/shared@3.4.38': {}
|
||||
|
||||
'@vue/shared@3.5.0': {}
|
||||
|
||||
'@vue/shared@3.5.4': {}
|
||||
|
||||
'@vue/shared@3.5.5': {}
|
||||
|
||||
'@vue/shared@3.5.6': {}
|
||||
|
||||
'@web3-storage/multipart-parser@1.0.0': {}
|
||||
|
||||
'@webgpu/types@0.1.45': {}
|
||||
@@ -20706,7 +20721,7 @@ snapshots:
|
||||
|
||||
base64-js@1.5.1: {}
|
||||
|
||||
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.5(typescript@5.5.4)):
|
||||
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.5.4)(vue@3.5.6(typescript@5.5.4)):
|
||||
dependencies:
|
||||
'@better-fetch/fetch': 1.1.4
|
||||
'@better-fetch/logger': 1.1.3
|
||||
@@ -20714,7 +20729,7 @@ snapshots:
|
||||
'@nanostores/query': 0.3.4(nanostores@0.11.2)
|
||||
'@nanostores/react': 0.7.3(nanostores@0.11.2)(react@19.0.0-rc-7771d3a7-20240827)
|
||||
'@nanostores/solid': 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
||||
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.5(typescript@5.5.4))
|
||||
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.6(typescript@5.5.4))
|
||||
'@noble/ciphers': 0.6.0
|
||||
'@noble/hashes': 1.4.0
|
||||
'@paralleldrive/cuid2': 2.2.2
|
||||
@@ -20749,7 +20764,7 @@ snapshots:
|
||||
- typescript
|
||||
- vue
|
||||
|
||||
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.6.2)(vue@3.5.5(typescript@5.6.2)):
|
||||
better-auth@0.0.4(@vue/devtools-api@6.6.3)(react@19.0.0-rc-7771d3a7-20240827)(solid-js@1.8.21)(typescript@5.6.2)(vue@3.5.6(typescript@5.6.2)):
|
||||
dependencies:
|
||||
'@better-fetch/fetch': 1.1.4
|
||||
'@better-fetch/logger': 1.1.3
|
||||
@@ -20757,7 +20772,7 @@ snapshots:
|
||||
'@nanostores/query': 0.3.4(nanostores@0.11.2)
|
||||
'@nanostores/react': 0.7.3(nanostores@0.11.2)(react@19.0.0-rc-7771d3a7-20240827)
|
||||
'@nanostores/solid': 0.4.2(nanostores@0.11.2)(solid-js@1.8.21)
|
||||
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.5(typescript@5.6.2))
|
||||
'@nanostores/vue': 0.10.0(@vue/devtools-api@6.6.3)(nanostores@0.11.2)(vue@3.5.6(typescript@5.6.2))
|
||||
'@noble/ciphers': 0.6.0
|
||||
'@noble/hashes': 1.4.0
|
||||
'@paralleldrive/cuid2': 2.2.2
|
||||
@@ -25814,10 +25829,10 @@ snapshots:
|
||||
'@nuxt/kit': 3.13.0(magicast@0.3.5)(rollup@4.21.2)
|
||||
'@nuxt/schema': 3.13.0(rollup@4.21.2)
|
||||
'@nuxt/telemetry': 2.5.4(magicast@0.3.5)(rollup@4.21.2)
|
||||
'@nuxt/vite-builder': 3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1(jiti@1.21.6))(lightningcss@1.22.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.2)(vue@3.5.5(typescript@5.6.2))
|
||||
'@nuxt/vite-builder': 3.13.0(@biomejs/biome@1.7.3)(@types/node@22.3.0)(eslint@9.9.1(jiti@1.21.6))(lightningcss@1.22.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.21.2)(terser@5.31.6)(typescript@5.6.2)(vue@3.5.6(typescript@5.6.2))
|
||||
'@unhead/dom': 1.10.0
|
||||
'@unhead/ssr': 1.10.0
|
||||
'@unhead/vue': 1.10.0(vue@3.5.5(typescript@5.6.2))
|
||||
'@unhead/vue': 1.10.0(vue@3.5.6(typescript@5.6.2))
|
||||
'@vue/shared': 3.4.38
|
||||
acorn: 8.12.1
|
||||
c12: 1.11.1(magicast@0.3.5)
|
||||
@@ -25861,13 +25876,13 @@ snapshots:
|
||||
unenv: 1.10.0
|
||||
unimport: 3.11.1(rollup@4.21.2)
|
||||
unplugin: 1.12.2
|
||||
unplugin-vue-router: 0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.5.5(typescript@5.6.2)))(vue@3.5.5(typescript@5.6.2))
|
||||
unplugin-vue-router: 0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.5.6(typescript@5.6.2)))(vue@3.5.6(typescript@5.6.2))
|
||||
unstorage: 1.10.2(ioredis@5.4.1)
|
||||
untyped: 1.4.2
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
vue-bundle-renderer: 2.1.0
|
||||
vue-devtools-stub: 0.1.0
|
||||
vue-router: 4.4.3(vue@3.5.5(typescript@5.6.2))
|
||||
vue-router: 4.4.3(vue@3.5.6(typescript@5.6.2))
|
||||
optionalDependencies:
|
||||
'@parcel/watcher': 2.4.1
|
||||
'@types/node': 22.3.0
|
||||
@@ -26301,6 +26316,8 @@ snapshots:
|
||||
|
||||
picocolors@1.0.1: {}
|
||||
|
||||
picocolors@1.1.0: {}
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
picomatch@3.0.1: {}
|
||||
@@ -26422,12 +26439,21 @@ snapshots:
|
||||
postcss: 8.4.44
|
||||
ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.6.2)
|
||||
|
||||
postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(yaml@2.5.0):
|
||||
postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)):
|
||||
dependencies:
|
||||
lilconfig: 3.1.2
|
||||
yaml: 2.5.0
|
||||
optionalDependencies:
|
||||
postcss: 8.4.47
|
||||
ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)
|
||||
optional: true
|
||||
|
||||
postcss-load-config@6.0.1(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.0)(yaml@2.5.0):
|
||||
dependencies:
|
||||
lilconfig: 3.1.2
|
||||
optionalDependencies:
|
||||
jiti: 1.21.6
|
||||
postcss: 8.4.44
|
||||
postcss: 8.4.47
|
||||
tsx: 4.19.0
|
||||
yaml: 2.5.0
|
||||
|
||||
@@ -26583,6 +26609,12 @@ snapshots:
|
||||
picocolors: 1.0.1
|
||||
source-map-js: 1.2.0
|
||||
|
||||
postcss@8.4.47:
|
||||
dependencies:
|
||||
nanoid: 3.3.7
|
||||
picocolors: 1.1.0
|
||||
source-map-js: 1.2.1
|
||||
|
||||
postgres-array@2.0.0: {}
|
||||
|
||||
postgres-array@3.0.2: {}
|
||||
@@ -27008,6 +27040,12 @@ snapshots:
|
||||
qr.js: 0.0.0
|
||||
react: 18.3.1
|
||||
|
||||
react-qr-code@2.0.15(react@19.0.0-rc-7771d3a7-20240827):
|
||||
dependencies:
|
||||
prop-types: 15.8.1
|
||||
qr.js: 0.0.0
|
||||
react: 19.0.0-rc-7771d3a7-20240827
|
||||
|
||||
react-reconciler@0.27.0(react@19.0.0-rc-7771d3a7-20240827):
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
@@ -27845,6 +27883,8 @@ snapshots:
|
||||
|
||||
source-map-js@1.2.0: {}
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
source-map-support@0.5.21:
|
||||
dependencies:
|
||||
buffer-from: 1.1.2
|
||||
@@ -28126,14 +28166,14 @@ snapshots:
|
||||
dependencies:
|
||||
react: 19.0.0-rc-7771d3a7-20240827
|
||||
|
||||
svelte-check@3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.44)(svelte@4.2.19):
|
||||
svelte-check@3.8.6(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.47)(svelte@4.2.19):
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
chokidar: 3.6.0
|
||||
picocolors: 1.0.1
|
||||
sade: 1.8.1
|
||||
svelte: 4.2.19
|
||||
svelte-preprocess: 5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.44)(svelte@4.2.19)(typescript@5.6.2)
|
||||
svelte-preprocess: 5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.47)(svelte@4.2.19)(typescript@5.6.2)
|
||||
typescript: 5.6.2
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
@@ -28150,7 +28190,7 @@ snapshots:
|
||||
dependencies:
|
||||
svelte: 4.2.19
|
||||
|
||||
svelte-preprocess@5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.44)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.44)(svelte@4.2.19)(typescript@5.6.2):
|
||||
svelte-preprocess@5.1.4(@babel/core@7.25.2)(postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4)))(postcss@8.4.47)(svelte@4.2.19)(typescript@5.6.2):
|
||||
dependencies:
|
||||
'@types/pug': 2.0.10
|
||||
detect-indent: 6.1.0
|
||||
@@ -28160,8 +28200,8 @@ snapshots:
|
||||
svelte: 4.2.19
|
||||
optionalDependencies:
|
||||
'@babel/core': 7.25.2
|
||||
postcss: 8.4.44
|
||||
postcss-load-config: 4.0.2(postcss@8.4.44)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4))
|
||||
postcss: 8.4.47
|
||||
postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.3.0)(typescript@5.5.4))
|
||||
typescript: 5.6.2
|
||||
|
||||
svelte@4.2.19:
|
||||
@@ -28625,7 +28665,7 @@ snapshots:
|
||||
|
||||
tslib@2.6.3: {}
|
||||
|
||||
tsup@8.2.4(@swc/core@1.7.26(@swc/helpers@0.5.13))(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0):
|
||||
tsup@8.2.4(@swc/core@1.7.26(@swc/helpers@0.5.13))(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.0)(typescript@5.6.0-beta)(yaml@2.5.0):
|
||||
dependencies:
|
||||
bundle-require: 5.0.0(esbuild@0.23.1)
|
||||
cac: 6.7.14
|
||||
@@ -28637,7 +28677,7 @@ snapshots:
|
||||
globby: 11.1.0
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.0.1
|
||||
postcss-load-config: 6.0.1(jiti@1.21.6)(postcss@8.4.44)(tsx@4.19.0)(yaml@2.5.0)
|
||||
postcss-load-config: 6.0.1(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.0)(yaml@2.5.0)
|
||||
resolve-from: 5.0.0
|
||||
rollup: 4.21.2
|
||||
source-map: 0.8.0-beta.0
|
||||
@@ -28645,7 +28685,7 @@ snapshots:
|
||||
tree-kill: 1.2.2
|
||||
optionalDependencies:
|
||||
'@swc/core': 1.7.26(@swc/helpers@0.5.13)
|
||||
postcss: 8.4.44
|
||||
postcss: 8.4.47
|
||||
typescript: 5.6.0-beta
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
@@ -28940,11 +28980,11 @@ snapshots:
|
||||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
unplugin-vue-router@0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.5.5(typescript@5.6.2)))(vue@3.5.5(typescript@5.6.2)):
|
||||
unplugin-vue-router@0.10.7(rollup@4.21.2)(vue-router@4.4.3(vue@3.5.6(typescript@5.6.2)))(vue@3.5.6(typescript@5.6.2)):
|
||||
dependencies:
|
||||
'@babel/types': 7.25.6
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.21.2)
|
||||
'@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.5(typescript@5.6.2))
|
||||
'@vue-macros/common': 1.12.2(rollup@4.21.2)(vue@3.5.6(typescript@5.6.2))
|
||||
ast-walker-scope: 0.6.2
|
||||
chokidar: 3.6.0
|
||||
fast-glob: 3.3.2
|
||||
@@ -28957,7 +28997,7 @@ snapshots:
|
||||
unplugin: 1.12.2
|
||||
yaml: 2.5.0
|
||||
optionalDependencies:
|
||||
vue-router: 4.4.3(vue@3.5.5(typescript@5.6.2))
|
||||
vue-router: 4.4.3(vue@3.5.6(typescript@5.6.2))
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- vue
|
||||
@@ -29361,7 +29401,7 @@ snapshots:
|
||||
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2)
|
||||
'@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2)
|
||||
'@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2)
|
||||
'@vue/compiler-dom': 3.5.4
|
||||
'@vue/compiler-dom': 3.5.5
|
||||
kolorist: 1.8.0
|
||||
magic-string: 0.30.11
|
||||
vite: 5.4.2(@types/node@22.3.0)(lightningcss@1.22.0)(terser@5.31.6)
|
||||
@@ -29449,10 +29489,10 @@ snapshots:
|
||||
|
||||
vue-devtools-stub@0.1.0: {}
|
||||
|
||||
vue-router@4.4.3(vue@3.5.5(typescript@5.6.2)):
|
||||
vue-router@4.4.3(vue@3.5.6(typescript@5.6.2)):
|
||||
dependencies:
|
||||
'@vue/devtools-api': 6.6.3
|
||||
vue: 3.5.5(typescript@5.6.2)
|
||||
vue: 3.5.6(typescript@5.6.2)
|
||||
|
||||
vue@3.5.0(typescript@5.6.0-beta):
|
||||
dependencies:
|
||||
@@ -29464,23 +29504,23 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.6.0-beta
|
||||
|
||||
vue@3.5.5(typescript@5.5.4):
|
||||
vue@3.5.6(typescript@5.5.4):
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.5
|
||||
'@vue/compiler-sfc': 3.5.5
|
||||
'@vue/runtime-dom': 3.5.5
|
||||
'@vue/server-renderer': 3.5.5(vue@3.5.5(typescript@5.5.4))
|
||||
'@vue/shared': 3.5.5
|
||||
'@vue/compiler-dom': 3.5.6
|
||||
'@vue/compiler-sfc': 3.5.6
|
||||
'@vue/runtime-dom': 3.5.6
|
||||
'@vue/server-renderer': 3.5.6(vue@3.5.6(typescript@5.5.4))
|
||||
'@vue/shared': 3.5.6
|
||||
optionalDependencies:
|
||||
typescript: 5.5.4
|
||||
|
||||
vue@3.5.5(typescript@5.6.2):
|
||||
vue@3.5.6(typescript@5.6.2):
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.5
|
||||
'@vue/compiler-sfc': 3.5.5
|
||||
'@vue/runtime-dom': 3.5.5
|
||||
'@vue/server-renderer': 3.5.5(vue@3.5.5(typescript@5.6.2))
|
||||
'@vue/shared': 3.5.5
|
||||
'@vue/compiler-dom': 3.5.6
|
||||
'@vue/compiler-sfc': 3.5.6
|
||||
'@vue/runtime-dom': 3.5.6
|
||||
'@vue/server-renderer': 3.5.6(vue@3.5.6(typescript@5.6.2))
|
||||
'@vue/shared': 3.5.6
|
||||
optionalDependencies:
|
||||
typescript: 5.6.2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user