mirror of
https://github.com/SrIzan10/echospace.git
synced 2026-06-06 00:56:54 +00:00
feat: github auth
This commit is contained in:
@@ -1,2 +0,0 @@
|
|||||||
# from the dev postgres containeer
|
|
||||||
DATABASE_URL=postgresql://postgres:dfsjhkdswkjntelsmldbfvsgknl5t@localhost:5555/postgres
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -35,3 +35,6 @@ yarn-error.log*
|
|||||||
# typescript
|
# typescript
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
|
dev/
|
||||||
|
!dev/docker-compose.yml
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
volumes:
|
|
||||||
psql:
|
|
||||||
services:
|
services:
|
||||||
psql:
|
psql:
|
||||||
image: postgres
|
image: postgres
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
POSTGRES_PASSWORD: dfsjhkdswkjntelsmldbfvsgknl5t
|
POSTGRES_PASSWORD: S+xyPXPDcYNQtTy3hUNoC9eBwmsoGA
|
||||||
volumes:
|
volumes:
|
||||||
- psql:/var/lib/postgresql/data
|
- ./psql:/var/lib/postgresql/data
|
||||||
ports:
|
ports:
|
||||||
- 5555:5432
|
- 5555:5432
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "docker compose --file dev/docker-compose.yml up -d && next dev",
|
||||||
"build": "prisma generate && next build",
|
"build": "prisma generate && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
@@ -13,11 +13,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lucia-auth/adapter-prisma": "^4.0.1",
|
"@lucia-auth/adapter-prisma": "^4.0.1",
|
||||||
"@node-rs/argon2": "^2.0.2",
|
"@node-rs/argon2": "^2.0.2",
|
||||||
"@prisma/client": "^5.12.1",
|
"@prisma/client": "^6.0.1",
|
||||||
"@radix-ui/react-avatar": "^1.0.4",
|
"@radix-ui/react-avatar": "^1.0.4",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
|
"arctic": "^2.3.1",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"lucia": "^3.1.1",
|
"lucia": "^3.1.1",
|
||||||
|
|||||||
17
prisma/migrations/20241213233617_github_init/migration.sql
Normal file
17
prisma/migrations/20241213233617_github_init/migration.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `hashed_password` on the `User` table. All the data in the column will be lost.
|
||||||
|
- A unique constraint covering the columns `[githubId]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||||
|
- Added the required column `githubId` to the `User` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropIndex
|
||||||
|
DROP INDEX "User_username_key";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" DROP COLUMN "hashed_password",
|
||||||
|
ADD COLUMN "githubId" TEXT NOT NULL;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_githubId_key" ON "User"("githubId");
|
||||||
@@ -15,8 +15,8 @@ datasource db {
|
|||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
username String @unique
|
githubId String @unique
|
||||||
hashed_password String
|
username String
|
||||||
sessions Session[]
|
sessions Session[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { redirect } from "next/navigation";
|
|||||||
export default async function Layout({ children }: { children: React.ReactNode }) {
|
export default async function Layout({ children }: { children: React.ReactNode }) {
|
||||||
const { user } = await validateRequest()
|
const { user } = await validateRequest()
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return redirect('/auth/login')
|
return redirect('/auth')
|
||||||
}
|
}
|
||||||
return children
|
return children
|
||||||
}
|
}
|
||||||
84
src/app/(public)/auth/github/callback/route.ts
Normal file
84
src/app/(public)/auth/github/callback/route.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import { github, lucia } from "@/lib/auth";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
import { OAuth2RequestError } from "arctic";
|
||||||
|
import { generateIdFromEntropySize } from "lucia";
|
||||||
|
import prisma from "@/lib/db";
|
||||||
|
|
||||||
|
// TODO: maybe do the requests with octokit?
|
||||||
|
export async function GET(request: Request): Promise<Response> {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const code = url.searchParams.get("code");
|
||||||
|
const state = url.searchParams.get("state");
|
||||||
|
const storedState = cookies().get("github_oauth_state")?.value ?? null;
|
||||||
|
if (!code || !state || !storedState || state !== storedState) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 400
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tokens = await github.validateAuthorizationCode(code);
|
||||||
|
console.log(tokens);
|
||||||
|
const githubUserResponse = await fetch("https://api.github.com/user", {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens.accessToken()}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const githubUser: GitHubUser = await githubUserResponse.json();
|
||||||
|
|
||||||
|
const existingUser = await prisma.user.findUnique({
|
||||||
|
where: {
|
||||||
|
githubId: githubUser.id.toString()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingUser) {
|
||||||
|
const session = await lucia.createSession(existingUser.id, {});
|
||||||
|
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||||
|
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
||||||
|
return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: {
|
||||||
|
Location: "/"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const userId = generateIdFromEntropySize(10);
|
||||||
|
|
||||||
|
await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
id: userId,
|
||||||
|
githubId: githubUser.id.toString(),
|
||||||
|
username: githubUser.login
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const session = await lucia.createSession(userId, {});
|
||||||
|
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||||
|
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
||||||
|
return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: {
|
||||||
|
Location: "/"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// the specific error message depends on the provider
|
||||||
|
console.error(e);
|
||||||
|
if (e instanceof OAuth2RequestError) {
|
||||||
|
// invalid code
|
||||||
|
return new Response(null, {
|
||||||
|
status: 400
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new Response(null, {
|
||||||
|
status: 500
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GitHubUser {
|
||||||
|
id: number;
|
||||||
|
login: string;
|
||||||
|
}
|
||||||
18
src/app/(public)/auth/github/route.ts
Normal file
18
src/app/(public)/auth/github/route.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { generateState } from "arctic";
|
||||||
|
import { github } from "@/lib/auth";
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
|
||||||
|
export async function GET(): Promise<Response> {
|
||||||
|
const state = generateState();
|
||||||
|
const url = github.createAuthorizationURL(state, []);
|
||||||
|
|
||||||
|
cookies().set("github_oauth_state", state, {
|
||||||
|
path: "/",
|
||||||
|
secure: process.env.NODE_ENV === "production",
|
||||||
|
httpOnly: true,
|
||||||
|
maxAge: 60 * 10,
|
||||||
|
sameSite: "lax"
|
||||||
|
});
|
||||||
|
|
||||||
|
return Response.redirect(url);
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { Label } from "@/components/ui/label";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useFormState } from "react-dom";
|
|
||||||
import { login } from "@/lib/auth/actions";
|
|
||||||
import SubmitButton from "@/components/app/SubmitButton/SubmitButton";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const [formData, formAction] = useFormState(login, null);
|
|
||||||
useEffect(() => {
|
|
||||||
if (formData?.error) {
|
|
||||||
toast.error(formData.error)
|
|
||||||
}
|
|
||||||
}, [formData])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center p-4 lg:p-8">
|
|
||||||
<div className="w-full max-w-md m-auto space-y-8">
|
|
||||||
<div className="text-center">
|
|
||||||
<h1 className="text-4xl font-bold pb-1">Log In</h1>
|
|
||||||
</div>
|
|
||||||
<form action={formAction}>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label htmlFor="email">Username</Label>
|
|
||||||
<Input name="username" id="username" required type="text" />
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label htmlFor="password">Password</Label>
|
|
||||||
<Input name="password" id="password" required type="password" />
|
|
||||||
</div>
|
|
||||||
<SubmitButton buttonText="Log In" className="w-full" />
|
|
||||||
<div className="text-center text-sm">
|
|
||||||
No account?
|
|
||||||
<Link className="underline pl-1" href="/auth/signUp">
|
|
||||||
Create one!
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
15
src/app/(public)/auth/page.tsx
Normal file
15
src/app/(public)/auth/page.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
"use client";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center p-4 lg:p-8">
|
||||||
|
<div className="w-full max-w-md m-auto">
|
||||||
|
<Link href="/auth/github">
|
||||||
|
<Button className="w-full">Log In with GitHub</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import { Label } from "@/components/ui/label"
|
|
||||||
import { Input } from "@/components/ui/input"
|
|
||||||
import Link from "next/link"
|
|
||||||
import { signup } from "@/lib/auth/actions";
|
|
||||||
import SubmitButton from "@/components/app/SubmitButton/SubmitButton";
|
|
||||||
import { useFormState } from "react-dom";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
export default function Page() {
|
|
||||||
const [signupData, signupAction] = useFormState(signup, null)
|
|
||||||
useEffect(() => {
|
|
||||||
if (signupData?.error) {
|
|
||||||
toast.error(signupData.error)
|
|
||||||
}
|
|
||||||
}, [signupData])
|
|
||||||
return (
|
|
||||||
<div className="flex items-center p-6 lg:p-8">
|
|
||||||
<div className="w-full max-w-md m-auto space-y-8">
|
|
||||||
<div className="text-center">
|
|
||||||
<h1 className="text-4xl font-bold pb-1">Sign Up</h1>
|
|
||||||
</div>
|
|
||||||
<form action={signupAction}>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label htmlFor="username">Username</Label>
|
|
||||||
<Input name="username" required type="text" id="username" />
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Label htmlFor="password">Password</Label>
|
|
||||||
<Input name="password" required type="password" id="password" />
|
|
||||||
</div>
|
|
||||||
<SubmitButton buttonText="Create account" className="w-full" />
|
|
||||||
<div className="text-center text-sm">
|
|
||||||
Already have an account?
|
|
||||||
<Link className="underline pl-1" href="/auth/login">
|
|
||||||
Login
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -54,8 +54,7 @@ export default function Navbar() {
|
|||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild className="cursor-pointer">
|
<DropdownMenuTrigger asChild className="cursor-pointer">
|
||||||
<Avatar>
|
<Avatar>
|
||||||
{/* TODO: Implement avatar system */}
|
<AvatarImage src={`https://github.com/${user.username}.png`} alt={user.username} />
|
||||||
{/*<AvatarImage src={"https://srizan.dev/pfp.webp"} alt="@srizan" />*/}
|
|
||||||
<AvatarFallback>{user.username}</AvatarFallback>
|
<AvatarFallback>{user.username}</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
@@ -73,7 +72,7 @@ export default function Navbar() {
|
|||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Link href="/auth/login">
|
<Link href="/auth">
|
||||||
<Button variant="outline">Sign in</Button>
|
<Button variant="outline">Sign in</Button>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export async function logout() {
|
|||||||
await lucia.invalidateSession(session!.id);
|
await lucia.invalidateSession(session!.id);
|
||||||
const sessionCookie = lucia.createBlankSessionCookie();
|
const sessionCookie = lucia.createBlankSessionCookie();
|
||||||
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
||||||
return redirect("/auth/login");
|
return redirect("/auth");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function login(prev: any, data: FormData) {
|
export async function login(prev: any, data: FormData) {
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import { Lucia, Session, User } from "lucia";
|
|||||||
import prisma from "../db";
|
import prisma from "../db";
|
||||||
import { cache } from "react";
|
import { cache } from "react";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
|
import { GitHub } from "arctic";
|
||||||
|
|
||||||
|
export const github = new GitHub(process.env.GITHUB_CLIENT!, process.env.GITHUB_SECRET!, 'http://localhost:3000/auth/github/callback');
|
||||||
const adapter = new PrismaAdapter(prisma.session, prisma.user);
|
const adapter = new PrismaAdapter(prisma.session, prisma.user);
|
||||||
|
|
||||||
export const lucia = new Lucia(adapter, {
|
export const lucia = new Lucia(adapter, {
|
||||||
@@ -18,6 +20,7 @@ export const lucia = new Lucia(adapter, {
|
|||||||
},
|
},
|
||||||
getUserAttributes: (attributes) => {
|
getUserAttributes: (attributes) => {
|
||||||
return {
|
return {
|
||||||
|
githubId: attributes.githubId,
|
||||||
username: attributes.username
|
username: attributes.username
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -67,5 +70,6 @@ declare module "lucia" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DatabaseUserAttributes {
|
interface DatabaseUserAttributes {
|
||||||
|
githubId: string;
|
||||||
username: string;
|
username: string;
|
||||||
}
|
}
|
||||||
54
yarn.lock
54
yarn.lock
@@ -551,15 +551,52 @@
|
|||||||
"@nodelib/fs.scandir" "2.1.5"
|
"@nodelib/fs.scandir" "2.1.5"
|
||||||
fastq "^1.6.0"
|
fastq "^1.6.0"
|
||||||
|
|
||||||
|
"@oslojs/asn1@1.0.0":
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@oslojs/asn1/-/asn1-1.0.0.tgz#25edb31585b369efdc103e9a1eb822df9c235174"
|
||||||
|
integrity sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==
|
||||||
|
dependencies:
|
||||||
|
"@oslojs/binary" "1.0.0"
|
||||||
|
|
||||||
|
"@oslojs/binary@1.0.0":
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@oslojs/binary/-/binary-1.0.0.tgz#3e73f9cef0d06731d2aa528066666ccc00d610d6"
|
||||||
|
integrity sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==
|
||||||
|
|
||||||
|
"@oslojs/crypto@1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@oslojs/crypto/-/crypto-1.0.1.tgz#74cf0d19d9fcda7cf5648cf3188dfeaf1d1b039f"
|
||||||
|
integrity sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==
|
||||||
|
dependencies:
|
||||||
|
"@oslojs/asn1" "1.0.0"
|
||||||
|
"@oslojs/binary" "1.0.0"
|
||||||
|
|
||||||
|
"@oslojs/encoding@0.4.1":
|
||||||
|
version "0.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@oslojs/encoding/-/encoding-0.4.1.tgz#1489e560041533214511e9e03626962d24e58e9f"
|
||||||
|
integrity sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==
|
||||||
|
|
||||||
|
"@oslojs/encoding@1.1.0":
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@oslojs/encoding/-/encoding-1.1.0.tgz#55f3d9a597430a01f2a5ef63c6b42f769f9ce34e"
|
||||||
|
integrity sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==
|
||||||
|
|
||||||
|
"@oslojs/jwt@0.2.0":
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@oslojs/jwt/-/jwt-0.2.0.tgz#cdcd51e562eed2e536d273c840e90648c2d4a54a"
|
||||||
|
integrity sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==
|
||||||
|
dependencies:
|
||||||
|
"@oslojs/encoding" "0.4.1"
|
||||||
|
|
||||||
"@pkgjs/parseargs@^0.11.0":
|
"@pkgjs/parseargs@^0.11.0":
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||||
|
|
||||||
"@prisma/client@^5.12.1":
|
"@prisma/client@^6.0.1":
|
||||||
version "5.13.0"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.13.0.tgz#b9f1d0983d714e982675201d8222a9ecb4bdad4a"
|
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-6.0.1.tgz#e24c5a44fb46d04a92426879bd9f8a2c28338420"
|
||||||
integrity sha512-uYdfpPncbZ/syJyiYBwGZS8Gt1PTNoErNYMuqHDa2r30rNSFtgTA/LXsSk55R7pdRTMi5pHkeP9B14K6nHmwkg==
|
integrity sha512-60w7kL6bUxz7M6Gs/V+OWMhwy94FshpngVmOY05TmGD0Lhk+Ac0ZgtjlL6Wll9TD4G03t4Sq1wZekNVy+Xdlbg==
|
||||||
|
|
||||||
"@prisma/debug@6.0.1":
|
"@prisma/debug@6.0.1":
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
@@ -1044,6 +1081,15 @@ anymatch@~3.1.2:
|
|||||||
normalize-path "^3.0.0"
|
normalize-path "^3.0.0"
|
||||||
picomatch "^2.0.4"
|
picomatch "^2.0.4"
|
||||||
|
|
||||||
|
arctic@^2.3.1:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/arctic/-/arctic-2.3.1.tgz#2cc9c5f2610ffdca0228b623a17cd9c8abf13b7f"
|
||||||
|
integrity sha512-bnmPYWbPtrQcneG/dmZIdvDeZ7pYhHqd4hYTbOR5LB9f429XLHiE4VnmKmJCPkw+G2CsG689WS+NDwa5UKsigA==
|
||||||
|
dependencies:
|
||||||
|
"@oslojs/crypto" "1.0.1"
|
||||||
|
"@oslojs/encoding" "1.1.0"
|
||||||
|
"@oslojs/jwt" "0.2.0"
|
||||||
|
|
||||||
arg@^5.0.2:
|
arg@^5.0.2:
|
||||||
version "5.0.2"
|
version "5.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
|
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
|
||||||
|
|||||||
Reference in New Issue
Block a user