mirror of
https://github.com/SrIzan10/echospace.git
synced 2026-06-06 00:56:54 +00:00
feat: projects, api, viewer, settings
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"useTabs": false,
|
"useTabs": false,
|
||||||
"printWidth": 800,
|
"printWidth": 100,
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
|
|||||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -2,4 +2,6 @@
|
|||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false,
|
||||||
"editor.insertSpaces": true,
|
"editor.insertSpaces": true,
|
||||||
|
"editor.rulers": [100],
|
||||||
|
"rewrap.wrappingColumn": 70,
|
||||||
}
|
}
|
||||||
@@ -12,13 +12,15 @@
|
|||||||
"ui:add": "shadcn add"
|
"ui:add": "shadcn add"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hookform/resolvers": "^3.9.1",
|
||||||
"@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": "^6.0.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.1",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.1",
|
||||||
|
"@radix-ui/react-tabs": "^1.1.2",
|
||||||
"arctic": "^2.3.1",
|
"arctic": "^2.3.1",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
@@ -28,6 +30,7 @@
|
|||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
"react-hook-form": "^7.54.1",
|
||||||
"sonner": "^1.4.41",
|
"sonner": "^1.4.41",
|
||||||
"tailwind-merge": "^2.2.2",
|
"tailwind-merge": "^2.2.2",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
|||||||
13
prisma/migrations/20241214165516_add_projects/migration.sql
Normal file
13
prisma/migrations/20241214165516_add_projects/migration.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Project" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"description" TEXT NOT NULL,
|
||||||
|
"githubUrl" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Project_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Project" ADD CONSTRAINT "Project_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `githubUrl` on the `Project` table. All the data in the column will be lost.
|
||||||
|
- Added the required column `github` to the `Project` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Project" DROP COLUMN "githubUrl",
|
||||||
|
ADD COLUMN "github" TEXT NOT NULL;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The primary key for the `Project` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||||
|
- The `id` column on the `Project` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Project" DROP CONSTRAINT "Project_pkey",
|
||||||
|
DROP COLUMN "id",
|
||||||
|
ADD COLUMN "id" SERIAL NOT NULL,
|
||||||
|
ADD CONSTRAINT "Project_pkey" PRIMARY KEY ("id");
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The primary key for the `Project` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Project" DROP CONSTRAINT "Project_pkey",
|
||||||
|
ADD COLUMN "customData" TEXT[],
|
||||||
|
ALTER COLUMN "id" DROP DEFAULT,
|
||||||
|
ALTER COLUMN "id" SET DATA TYPE TEXT,
|
||||||
|
ADD CONSTRAINT "Project_pkey" PRIMARY KEY ("id");
|
||||||
|
DROP SEQUENCE "Project_id_seq";
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Feedback" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"message" TEXT NOT NULL,
|
||||||
|
"customData" TEXT NOT NULL,
|
||||||
|
"projectId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Feedback_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Feedback" ADD CONSTRAINT "Feedback_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Project" ADD COLUMN "rateLimitReq" INTEGER NOT NULL DEFAULT 5,
|
||||||
|
ADD COLUMN "rateLimitTime" INTEGER NOT NULL DEFAULT 60;
|
||||||
@@ -17,6 +17,7 @@ model User {
|
|||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
githubId String @unique
|
githubId String @unique
|
||||||
username String
|
username String
|
||||||
|
projects Project[]
|
||||||
sessions Session[]
|
sessions Session[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,4 +26,27 @@ model Session {
|
|||||||
userId String
|
userId String
|
||||||
expiresAt DateTime
|
expiresAt DateTime
|
||||||
user User @relation(references: [id], fields: [userId], onDelete: Cascade)
|
user User @relation(references: [id], fields: [userId], onDelete: Cascade)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Project {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
description String
|
||||||
|
github String
|
||||||
|
customData String[]
|
||||||
|
rateLimitReq Int @default(5)
|
||||||
|
rateLimitTime Int @default(60)
|
||||||
|
|
||||||
|
userId String
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
feedback Feedback[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model Feedback {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
message String
|
||||||
|
customData String
|
||||||
|
|
||||||
|
projectId String
|
||||||
|
project Project @relation(fields: [projectId], references: [id])
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { useFormState } from 'react-dom';
|
||||||
|
import { createSchema, createSchemaType } from '@/lib/forms/zod';
|
||||||
|
import { create } from '@/lib/forms/actions';
|
||||||
|
import React from 'react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import SubmitButton from '@/components/app/SubmitButton/SubmitButton';
|
||||||
|
|
||||||
|
// TODO: move form to the new universal form component
|
||||||
|
export default function ProfileForm() {
|
||||||
|
const router = useRouter();
|
||||||
|
const form = useForm<createSchemaType>({
|
||||||
|
resolver: zodResolver(createSchema),
|
||||||
|
defaultValues: {
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
github: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [formState, formAction] = useFormState(create, null);
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (formState && formState.id) {
|
||||||
|
router.push(`/project/${formState.id}`);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [formState]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-[calc(100vh-4rem)] flex items-center justify-center">
|
||||||
|
<div className="max-w-md w-full p-4">
|
||||||
|
<Form {...form}>
|
||||||
|
<form
|
||||||
|
action={formAction}
|
||||||
|
onSubmit={form.handleSubmit((data) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
|
formData.append(key, value);
|
||||||
|
});
|
||||||
|
formAction(formData);
|
||||||
|
})}
|
||||||
|
className="space-y-8"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="name"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Project name</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="Echospace" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>How the project is called.</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="description"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Description</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="A developer-centric user feedback platform." {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Describe the project a bit.</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="github"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Github</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="https://github.com/SrIzan10/echospace" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>Your Github repository link. Will come in handy for some integrations!</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<SubmitButton buttonText='Submit' className='w-full' />
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import ProjectCard from '@/components/app/ProjectCard/ProjectCard';
|
import ProjectCard from '@/components/app/ProjectCard/ProjectCard';
|
||||||
|
import { validateRequest } from '@/lib/auth';
|
||||||
|
import prisma from '@/lib/db';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
|
|
||||||
export const dummyData = Array.from({ length: 10 }, (_, id) => ({
|
export default async function Page() {
|
||||||
id: id + 1,
|
const { user } = await validateRequest();
|
||||||
name: faker.word.noun(),
|
const db = await prisma.project.findMany({
|
||||||
description: faker.lorem.sentence(),
|
where: {
|
||||||
github: id !== 5 ? faker.internet.url() : undefined,
|
userId: user!.id,
|
||||||
}));
|
},
|
||||||
export default function Page() {
|
});
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Dashboard</h1>
|
<h1>Dashboard</h1>
|
||||||
<div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 p-4">
|
<div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 p-4">
|
||||||
{dummyData.map((d) => (
|
{db.map((d) => (
|
||||||
<ProjectCard key={d.id} {...d} />
|
<ProjectCard key={d.id} {...d} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
94
src/app/(protected)/project/[id]/page.tsx
Normal file
94
src/app/(protected)/project/[id]/page.tsx
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from '@/components/ui/table';
|
||||||
|
import { validateRequest } from '@/lib/auth';
|
||||||
|
import prisma from '@/lib/db';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import {
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbItem,
|
||||||
|
BreadcrumbLink,
|
||||||
|
BreadcrumbList,
|
||||||
|
BreadcrumbPage,
|
||||||
|
BreadcrumbSeparator,
|
||||||
|
} from "@/components/ui/breadcrumb"
|
||||||
|
|
||||||
|
// TODO: refactor to maybe append the no feedback message to the table div
|
||||||
|
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
|
||||||
|
const { id } = await params;
|
||||||
|
const { user } = await validateRequest();
|
||||||
|
const project = await prisma.project.findFirst({
|
||||||
|
where: { id, userId: user!.id },
|
||||||
|
include: { feedback: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!project) {
|
||||||
|
return <div>Project not found</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="max-w-4xl mx-auto">
|
||||||
|
<Breadcrumb className='pb-5'>
|
||||||
|
<BreadcrumbList>
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink href="/dashboard">Dashboard</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbPage>{project.name}</BreadcrumbPage>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</BreadcrumbList>
|
||||||
|
</Breadcrumb>
|
||||||
|
<div className="flex items-center justify-between w-full pb-10">
|
||||||
|
<h2>{project.name}</h2>
|
||||||
|
<p className="text-muted-foreground ml-2 truncate">{project.description}</p>
|
||||||
|
<Link href={`/project/${id}/settings`}>
|
||||||
|
<Button>Settings</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
{project.feedback.length === 0 ? (
|
||||||
|
<div className="border rounded-lg max-h-[32rem] overflow-y-auto text-center p-10">
|
||||||
|
<h2>No feedback!</h2>
|
||||||
|
<p className="text-muted-foreground mt-2">
|
||||||
|
Once you start receiving feedback, it will appear here.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="border rounded-lg max-h-[32rem] overflow-y-auto">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px]">ID</TableHead>
|
||||||
|
<TableHead>Message</TableHead>
|
||||||
|
{project.customData.map((key) => (
|
||||||
|
<TableHead key={key}>{key}</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{/* using toReversed to not change the upstream array in case of other data treatments needed */}
|
||||||
|
{project.feedback.toReversed().map((feedback) => (
|
||||||
|
<TableRow key={feedback.id}>
|
||||||
|
<TableCell>{feedback.id}</TableCell>
|
||||||
|
<TableCell>{feedback.message}</TableCell>
|
||||||
|
{Object.entries(JSON.parse(feedback.customData)).map(([key, value]) => (
|
||||||
|
<TableCell key={key}>{value as string}</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
src/app/(protected)/project/[id]/settings/page.tsx
Normal file
15
src/app/(protected)/project/[id]/settings/page.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import ProjectSettings from "@/components/app/ProjectSettings/ProjectSettings";
|
||||||
|
import { validateRequest } from "@/lib/auth";
|
||||||
|
import prisma from "@/lib/db";
|
||||||
|
|
||||||
|
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
|
||||||
|
const { id } = await params;
|
||||||
|
const { user } = await validateRequest();
|
||||||
|
const project = await prisma.project.findFirst({
|
||||||
|
where: { id, userId: user!.id },
|
||||||
|
});
|
||||||
|
if (!project) {
|
||||||
|
return <h1>Project not found</h1>;
|
||||||
|
}
|
||||||
|
return <ProjectSettings {...project} />;
|
||||||
|
}
|
||||||
70
src/app/api/feedback/[projectId]/route.ts
Normal file
70
src/app/api/feedback/[projectId]/route.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import prisma from '@/lib/db';
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
|
export async function POST(request: Request, { params }: { params: { projectId: string } }) {
|
||||||
|
const { projectId } = params;
|
||||||
|
const body = await request.json();
|
||||||
|
const queryProject = await prisma.project.findFirst({
|
||||||
|
where: {
|
||||||
|
id: projectId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!queryProject) {
|
||||||
|
return Response.json({ success: false, error: 'Project not found' }, { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert customKeys to regular array and add message
|
||||||
|
const customKeys = [...queryProject.customData, 'message'];
|
||||||
|
const bodyKeys = Object.keys(body);
|
||||||
|
console.log(bodyKeys);
|
||||||
|
|
||||||
|
// Find missing required keys (keys that should be in body but aren't)
|
||||||
|
const keysLeft = customKeys.filter((key) => !bodyKeys.includes(key));
|
||||||
|
console.log(keysLeft);
|
||||||
|
|
||||||
|
// Find invalid keys (keys in body that aren't allowed)
|
||||||
|
const invalidKeys = bodyKeys.filter((key) => !customKeys.includes(key));
|
||||||
|
console.log(invalidKeys);
|
||||||
|
|
||||||
|
if (keysLeft.length || invalidKeys.length) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
error: `Invalid keys: ${invalidKeys.join(', ')}, keys left: ${keysLeft.join(', ')}`,
|
||||||
|
},
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// check if all values of the keys are strings. this will prevent
|
||||||
|
// any type of injection or unexpected behavior.
|
||||||
|
const invalidValues = Object.entries(body).filter(([key, value]) => typeof value !== 'string');
|
||||||
|
if (invalidValues.length) {
|
||||||
|
return Response.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
error: `Invalid values for keys: ${invalidValues
|
||||||
|
.map(([key]) => key)
|
||||||
|
.join(', ')}. Make sure it is a string.`,
|
||||||
|
},
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const noMessageBody = Object.fromEntries(
|
||||||
|
Object.entries(body).filter(([key]) => key !== 'message')
|
||||||
|
);
|
||||||
|
await prisma.feedback.create({
|
||||||
|
data: {
|
||||||
|
message: body.message,
|
||||||
|
customData: JSON.stringify(noMessageBody),
|
||||||
|
project: {
|
||||||
|
connect: {
|
||||||
|
id: projectId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return Response.json({ success: true });
|
||||||
|
}
|
||||||
@@ -2,79 +2,85 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 220 23.077% 94.902%; /* base */
|
--background: 220 23.077% 94.902%; /* base */
|
||||||
--foreground: 233.793 16.022% 35.490%; /* text */
|
--foreground: 233.793 16.022% 35.49%; /* text */
|
||||||
|
|
||||||
--muted: 222.857 15.909% 82.745%; /* surface0 */
|
--muted: 222.857 15.909% 82.745%; /* surface0 */
|
||||||
--muted-foreground: 233.333 12.796% 41.373%; /* subtext1 */
|
--muted-foreground: 233.333 12.796% 41.373%; /* subtext1 */
|
||||||
|
|
||||||
--popover: 220 23.077% 94.902%; /* base */
|
--popover: 220 23.077% 94.902%; /* base */
|
||||||
--popover-foreground: 233.793 16.022% 35.490%; /* text */
|
--popover-foreground: 233.793 16.022% 35.49%; /* text */
|
||||||
|
|
||||||
--card: 220 23.077% 94.902%; /* base */
|
--card: 220 23.077% 94.902%; /* base */
|
||||||
--card-foreground: 233.793 16.022% 35.490%; /* text */
|
--card-foreground: 233.793 16.022% 35.49%; /* text */
|
||||||
|
|
||||||
--border: 225 13.559% 76.863%; /* surface1 */
|
--border: 225 13.559% 76.863%; /* surface1 */
|
||||||
--input: 225 13.559% 76.863%; /* surface1 */
|
--input: 225 13.559% 76.863%; /* surface1 */
|
||||||
|
|
||||||
--primary: 219.907 91.489% 53.922%; /* blue */
|
--primary: 219.907 91.489% 53.922%; /* blue */
|
||||||
--primary-foreground: 220 23.077% 94.902%; /* base */
|
--primary-foreground: 220 23.077% 94.902%; /* base */
|
||||||
|
|
||||||
--secondary: 222.857 15.909% 82.745%; /* surface0 */
|
--secondary: 222.857 15.909% 82.745%; /* surface0 */
|
||||||
--secondary-foreground: 233.793 16.022% 35.490%; /* text */
|
--secondary-foreground: 233.793 16.022% 35.49%; /* text */
|
||||||
|
|
||||||
--accent: 222.857 15.909% 82.745%; /* surface0 */
|
--accent: 222.857 15.909% 82.745%; /* surface0 */
|
||||||
--accent-foreground: 233.793 16.022% 35.490%; /* text */
|
--accent-foreground: 233.793 16.022% 35.49%; /* text */
|
||||||
|
|
||||||
--destructive: 347.077 86.667% 44.118%; /* red */
|
--destructive: 347.077 86.667% 44.118%; /* red */
|
||||||
--destructive-foreground: 220 21.951% 91.961%; /* mantle */
|
--destructive-foreground: 220 21.951% 91.961%; /* mantle */
|
||||||
|
|
||||||
--ring: 233.793 16.022% 35.490%; /* text */
|
--ring: 233.793 16.022% 35.49%; /* text */
|
||||||
|
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
}
|
|
||||||
|
|
||||||
.dark {
|
|
||||||
--background: 240 21.053% 14.902%; /* base */
|
|
||||||
--foreground: 226.154 63.934% 88.039%; /* text */
|
|
||||||
|
|
||||||
--muted: 236.842 16.239% 22.941%; /* surface0 */
|
|
||||||
--muted-foreground: 226.667 35.294% 80.000%; /* subtext1 */
|
|
||||||
|
|
||||||
--popover: 240 21.053% 14.902%; /* base */
|
|
||||||
--popover-foreground: 226.154 63.934% 88.039%; /* text */
|
|
||||||
|
|
||||||
--card: 240 21.053% 14.902%; /* base */
|
|
||||||
--card-foreground: 226.154 63.934% 88.039%; /* text */
|
|
||||||
|
|
||||||
--border: 234.286 13.208% 31.176%; /* surface1 */
|
|
||||||
--input: 234.286 13.208% 31.176%; /* surface1 */
|
|
||||||
|
|
||||||
--primary: 217.168 91.870% 75.882%; /* blue */
|
|
||||||
--primary-foreground: 240 21.053% 14.902%; /* base */
|
|
||||||
|
|
||||||
--secondary: 236.842 16.239% 22.941%; /* surface0 */
|
|
||||||
--secondary-foreground: 226.154 63.934% 88.039%; /* text */
|
|
||||||
|
|
||||||
--accent: 236.842 16.239% 22.941%; /* surface0 */
|
|
||||||
--accent-foreground: 226.154 63.934% 88.039%; /* text */
|
|
||||||
|
|
||||||
--destructive: 343.269 81.250% 74.902%; /* red */
|
|
||||||
--destructive-foreground: 240 21.311% 11.961%; /* mantle */
|
|
||||||
|
|
||||||
--ring: 226.154 63.934% 88.039%; /* text */
|
|
||||||
|
|
||||||
--radius: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
.dark {
|
||||||
* {
|
--background: 240 21.053% 14.902%; /* base */
|
||||||
@apply border-border;
|
--foreground: 226.154 63.934% 88.039%; /* text */
|
||||||
}
|
|
||||||
body {
|
--muted: 236.842 16.239% 22.941%; /* surface0 */
|
||||||
@apply bg-background text-foreground;
|
--muted-foreground: 226.667 35.294% 80%; /* subtext1 */
|
||||||
}
|
|
||||||
}
|
--popover: 240 21.053% 14.902%; /* base */
|
||||||
|
--popover-foreground: 226.154 63.934% 88.039%; /* text */
|
||||||
|
|
||||||
|
--card: 240 21.053% 14.902%; /* base */
|
||||||
|
--card-foreground: 226.154 63.934% 88.039%; /* text */
|
||||||
|
|
||||||
|
--border: 234.286 13.208% 31.176%; /* surface1 */
|
||||||
|
--input: 234.286 13.208% 31.176%; /* surface1 */
|
||||||
|
|
||||||
|
--primary: 217.168 91.87% 75.882%; /* blue */
|
||||||
|
--primary-foreground: 240 21.053% 14.902%; /* base */
|
||||||
|
|
||||||
|
--secondary: 236.842 16.239% 22.941%; /* surface0 */
|
||||||
|
--secondary-foreground: 226.154 63.934% 88.039%; /* text */
|
||||||
|
|
||||||
|
--accent: 236.842 16.239% 22.941%; /* surface0 */
|
||||||
|
--accent-foreground: 226.154 63.934% 88.039%; /* text */
|
||||||
|
|
||||||
|
--destructive: 343.269 81.25% 74.902%; /* red */
|
||||||
|
--destructive-foreground: 240 21.311% 11.961%; /* mantle */
|
||||||
|
|
||||||
|
--ring: 226.154 63.934% 88.039%; /* text */
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
* {
|
||||||
|
@apply border-border;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
@apply bg-background text-foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
@apply scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
@apply scroll-m-20 pb-2 text-3xl font-semibold tracking-tight first:mt-0;
|
||||||
|
}
|
||||||
@@ -18,7 +18,8 @@ import { ThemeSwitcher } from "../ThemeSwitcher/ThemeSwitcher"
|
|||||||
|
|
||||||
export const links = [
|
export const links = [
|
||||||
{ href: '/', name: 'Home' },
|
{ href: '/', name: 'Home' },
|
||||||
{ href: '/dashboard', name: 'Dashboard' }
|
{ href: '/dashboard', name: 'Dashboard' },
|
||||||
|
{ href: '/create', name: 'Create' },
|
||||||
]
|
]
|
||||||
|
|
||||||
function NavbarLinks() {
|
function NavbarLinks() {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { dummyData } from '@/app/(protected)/dashboard/page';
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
|
import type { Project } from '@prisma/client';
|
||||||
import { Eye, Github } from 'lucide-react';
|
import { Eye, Github } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export default function ProjectCard(props: (typeof dummyData)[0]) {
|
export default function ProjectCard(props: Project) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
222
src/components/app/ProjectSettings/ProjectSettings.tsx
Normal file
222
src/components/app/ProjectSettings/ProjectSettings.tsx
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import type { Project } from '@prisma/client';
|
||||||
|
import { UniversalForm } from '../UniversalForm/UniversalForm';
|
||||||
|
import { customData, editProject, ratelimitChange } from '@/lib/forms/actions';
|
||||||
|
import { bodyGen, bodyGenNoIdent } from '@/lib/bodyGen';
|
||||||
|
import {
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbItem,
|
||||||
|
BreadcrumbLink,
|
||||||
|
BreadcrumbList,
|
||||||
|
BreadcrumbPage,
|
||||||
|
BreadcrumbSeparator,
|
||||||
|
} from '@/components/ui/breadcrumb';
|
||||||
|
|
||||||
|
export default function ProjectSettings(project: Project) {
|
||||||
|
const url = `https://${window.location.hostname}/api/feedback/${project.id}`;
|
||||||
|
return (
|
||||||
|
<div className="w-full max-w-4xl mx-auto p-4">
|
||||||
|
<Breadcrumb className="pb-5">
|
||||||
|
<BreadcrumbList>
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink href="/dashboard">Dashboard</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink href={`/project/${project.id}`}>{project.name}</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbPage>Settings</BreadcrumbPage>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</BreadcrumbList>
|
||||||
|
</Breadcrumb>
|
||||||
|
<div className="mb-6">
|
||||||
|
<h1 className="pb-2">Project Settings</h1>
|
||||||
|
<p className="text-muted-foreground">Manage your project configuration and preferences</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tabs defaultValue="project" className="w-full">
|
||||||
|
<TabsList className="mb-4">
|
||||||
|
<TabsTrigger value="project">Project</TabsTrigger>
|
||||||
|
<TabsTrigger value="github">Github</TabsTrigger>
|
||||||
|
<TabsTrigger value="api">API</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="project">
|
||||||
|
<div className="grid gap-4">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Project Details</CardTitle>
|
||||||
|
<CardDescription>Basic information about your project</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<UniversalForm
|
||||||
|
fields={[
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
label: 'Project Name',
|
||||||
|
placeholder: 'My Awesome Project',
|
||||||
|
value: project.name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
label: 'Description',
|
||||||
|
placeholder: 'A brief description of your project',
|
||||||
|
value: project.description,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
label: 'ID',
|
||||||
|
type: 'hidden',
|
||||||
|
value: project.id,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
schemaName={'projectSettings'}
|
||||||
|
action={editProject}
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Custom Data</CardTitle>
|
||||||
|
<CardDescription>Custom fields to store additional data</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<UniversalForm
|
||||||
|
fields={[
|
||||||
|
{
|
||||||
|
name: 'data',
|
||||||
|
label: 'Custom data',
|
||||||
|
value: project.customData.join(','),
|
||||||
|
description: 'Comma separated list of custom data',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
label: 'ID',
|
||||||
|
type: 'hidden',
|
||||||
|
value: project.id,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
schemaName={'customData'}
|
||||||
|
action={customData}
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="github">
|
||||||
|
<h2>Soon™</h2>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="api" className="space-y-5">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Making a Request</CardTitle>
|
||||||
|
<CardDescription>Instructions on how to make an API request</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Endpoint</h3>
|
||||||
|
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
|
||||||
|
{url}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Method</h3>
|
||||||
|
<p className="text-sm">POST</p>
|
||||||
|
</div>
|
||||||
|
{/* <div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Headers</h3>
|
||||||
|
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm block whitespace-pre">
|
||||||
|
{`Content-Type: application/json
|
||||||
|
Authorization: Bearer YOUR_API_KEY`}
|
||||||
|
</code>
|
||||||
|
</div> */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Body</h3>
|
||||||
|
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm block whitespace-pre">
|
||||||
|
{bodyGen(project.customData)}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h3 className="text-sm font-medium">Example Request (cURL)</h3>
|
||||||
|
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm block whitespace-pre overflow-x-auto">
|
||||||
|
{stripIndents`curl -X POST \\
|
||||||
|
-H "Content-Type: application/json" \\
|
||||||
|
-H "Authorization: Bearer YOUR_API_KEY" \\
|
||||||
|
-d '${bodyGenNoIdent(project.customData)}' \\
|
||||||
|
${url}`}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Rate limiting</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Manage your API rate limits. Not implemented but you can change it
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<UniversalForm
|
||||||
|
fields={[
|
||||||
|
{
|
||||||
|
name: 'requests',
|
||||||
|
label: 'Requests',
|
||||||
|
placeholder: project.rateLimitReq.toString(),
|
||||||
|
value: project.rateLimitReq.toString(),
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'duration',
|
||||||
|
label: 'Duration',
|
||||||
|
placeholder: project.rateLimitTime.toString(),
|
||||||
|
value: project.rateLimitTime.toString(),
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
label: 'ID',
|
||||||
|
type: 'hidden',
|
||||||
|
value: project.id,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
schemaName={'ratelimitChange'}
|
||||||
|
action={ratelimitChange}
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripIndents(strings: TemplateStringsArray, ...values: any[]) {
|
||||||
|
const fullString = strings.reduce((accumulator, str, i) => {
|
||||||
|
const value = values[i] ? values[i] : '';
|
||||||
|
return accumulator + str + value;
|
||||||
|
}, '');
|
||||||
|
|
||||||
|
const lines = fullString.split('\n');
|
||||||
|
|
||||||
|
// Find minimum indentation level (excluding empty lines)
|
||||||
|
const minIndent = lines
|
||||||
|
.filter((line) => line.trim().length > 0)
|
||||||
|
.reduce((min, line) => {
|
||||||
|
const indent = line.match(/^\s*/)![0].length;
|
||||||
|
return indent < min ? indent : min;
|
||||||
|
}, Infinity);
|
||||||
|
|
||||||
|
// Apply minimum indent + 2 spaces to each line
|
||||||
|
return lines
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.map((line) => (line ? ' '.repeat(minIndent + 2) + line : line))
|
||||||
|
.join('\n')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
88
src/components/app/UniversalForm/UniversalForm.tsx
Normal file
88
src/components/app/UniversalForm/UniversalForm.tsx
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// props to claude for helping out with typescript tomfoolery
|
||||||
|
// copyleft srizan tho
|
||||||
|
'use client';
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { Path, PathValue, useForm } from 'react-hook-form';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '@/components/ui/form';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import type { UniversalFormProps } from './types';
|
||||||
|
import { customDataSchema, projectSettingsSchema, ratelimitChangeSchema } from './zod';
|
||||||
|
import SubmitButton from '../SubmitButton/SubmitButton';
|
||||||
|
import { useFormState } from 'react-dom';
|
||||||
|
import React from 'react';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
|
export const schemaDb = [
|
||||||
|
{ name: 'projectSettings', zod: projectSettingsSchema },
|
||||||
|
{ name: 'ratelimitChange', zod: ratelimitChangeSchema },
|
||||||
|
{ name: 'customData', zod: customDataSchema },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export function UniversalForm<T extends z.ZodType>({
|
||||||
|
fields,
|
||||||
|
schemaName,
|
||||||
|
action,
|
||||||
|
defaultValues,
|
||||||
|
submitText = 'Submit',
|
||||||
|
}: UniversalFormProps<T>) {
|
||||||
|
const [state, formAction] = useFormState(action, null);
|
||||||
|
const schema = schemaDb.find((s) => s.name === schemaName)?.zod;
|
||||||
|
|
||||||
|
if (!schema) {
|
||||||
|
throw new Error(`Schema "${schemaName}" not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = useForm<z.infer<T>>({
|
||||||
|
resolver: zodResolver(schema),
|
||||||
|
defaultValues: (defaultValues || {}) as z.infer<T>,
|
||||||
|
});
|
||||||
|
|
||||||
|
// pretend nothing is happening on here
|
||||||
|
React.useEffect(() => {
|
||||||
|
// @ts-ignore
|
||||||
|
if (state && !state.success) {
|
||||||
|
// @ts-ignore
|
||||||
|
toast.error(state.error);
|
||||||
|
}
|
||||||
|
}, [state]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form {...form}>
|
||||||
|
<form action={formAction} className="space-y-2">
|
||||||
|
{fields.map((field) => (
|
||||||
|
<FormField
|
||||||
|
key={field.name}
|
||||||
|
control={form.control}
|
||||||
|
name={field.name as Path<z.infer<T>>}
|
||||||
|
defaultValue={field.value as PathValue<z.infer<T>, Path<z.infer<T>>>}
|
||||||
|
render={({ field: formField }) => (
|
||||||
|
<FormItem>
|
||||||
|
{field.type !== 'hidden' && <FormLabel>{field.label}</FormLabel>}
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type={field.type || 'text'}
|
||||||
|
placeholder={field.placeholder}
|
||||||
|
{...formField}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
{field.description && <FormDescription>{field.description}</FormDescription>}
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<SubmitButton buttonText={submitText} />
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
20
src/components/app/UniversalForm/types.ts
Normal file
20
src/components/app/UniversalForm/types.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
import { HTMLInputTypeAttribute } from 'react';
|
||||||
|
import { schemaDb } from './UniversalForm';
|
||||||
|
|
||||||
|
export type FormFieldConfig = {
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
type?: HTMLInputTypeAttribute;
|
||||||
|
placeholder?: string;
|
||||||
|
description?: string;
|
||||||
|
value?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UniversalFormProps<T extends z.ZodType> = {
|
||||||
|
fields: FormFieldConfig[];
|
||||||
|
schemaName: typeof schemaDb[number]['name'];
|
||||||
|
action: (prev: any, formData: FormData) => void;
|
||||||
|
defaultValues?: Partial<z.infer<T>>;
|
||||||
|
submitText?: string;
|
||||||
|
};
|
||||||
18
src/components/app/UniversalForm/zod.ts
Normal file
18
src/components/app/UniversalForm/zod.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const projectSettingsSchema = z.object({
|
||||||
|
id: z.string().nonempty(),
|
||||||
|
name: z.string().nonempty(),
|
||||||
|
description: z.string().nonempty(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const ratelimitChangeSchema = z.object({
|
||||||
|
id: z.string().nonempty(),
|
||||||
|
requests: z.string().nonempty().transform((val) => parseInt(val, 10)),
|
||||||
|
duration: z.string().nonempty().transform((val) => parseInt(val, 10))
|
||||||
|
})
|
||||||
|
|
||||||
|
export const customDataSchema = z.object({
|
||||||
|
id: z.string().nonempty(),
|
||||||
|
data: z.string().nonempty()
|
||||||
|
})
|
||||||
115
src/components/ui/breadcrumb.tsx
Normal file
115
src/components/ui/breadcrumb.tsx
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { Slot } from "@radix-ui/react-slot"
|
||||||
|
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Breadcrumb = React.forwardRef<
|
||||||
|
HTMLElement,
|
||||||
|
React.ComponentPropsWithoutRef<"nav"> & {
|
||||||
|
separator?: React.ReactNode
|
||||||
|
}
|
||||||
|
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
|
||||||
|
Breadcrumb.displayName = "Breadcrumb"
|
||||||
|
|
||||||
|
const BreadcrumbList = React.forwardRef<
|
||||||
|
HTMLOListElement,
|
||||||
|
React.ComponentPropsWithoutRef<"ol">
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<ol
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
BreadcrumbList.displayName = "BreadcrumbList"
|
||||||
|
|
||||||
|
const BreadcrumbItem = React.forwardRef<
|
||||||
|
HTMLLIElement,
|
||||||
|
React.ComponentPropsWithoutRef<"li">
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<li
|
||||||
|
ref={ref}
|
||||||
|
className={cn("inline-flex items-center gap-1.5", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
BreadcrumbItem.displayName = "BreadcrumbItem"
|
||||||
|
|
||||||
|
const BreadcrumbLink = React.forwardRef<
|
||||||
|
HTMLAnchorElement,
|
||||||
|
React.ComponentPropsWithoutRef<"a"> & {
|
||||||
|
asChild?: boolean
|
||||||
|
}
|
||||||
|
>(({ asChild, className, ...props }, ref) => {
|
||||||
|
const Comp = asChild ? Slot : "a"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
ref={ref}
|
||||||
|
className={cn("transition-colors hover:text-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
BreadcrumbLink.displayName = "BreadcrumbLink"
|
||||||
|
|
||||||
|
const BreadcrumbPage = React.forwardRef<
|
||||||
|
HTMLSpanElement,
|
||||||
|
React.ComponentPropsWithoutRef<"span">
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<span
|
||||||
|
ref={ref}
|
||||||
|
role="link"
|
||||||
|
aria-disabled="true"
|
||||||
|
aria-current="page"
|
||||||
|
className={cn("font-normal text-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
BreadcrumbPage.displayName = "BreadcrumbPage"
|
||||||
|
|
||||||
|
const BreadcrumbSeparator = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"li">) => (
|
||||||
|
<li
|
||||||
|
role="presentation"
|
||||||
|
aria-hidden="true"
|
||||||
|
className={cn("[&>svg]:w-3.5 [&>svg]:h-3.5", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children ?? <ChevronRight />}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
|
||||||
|
|
||||||
|
const BreadcrumbEllipsis = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"span">) => (
|
||||||
|
<span
|
||||||
|
role="presentation"
|
||||||
|
aria-hidden="true"
|
||||||
|
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
|
<span className="sr-only">More</span>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
|
||||||
|
|
||||||
|
export {
|
||||||
|
Breadcrumb,
|
||||||
|
BreadcrumbList,
|
||||||
|
BreadcrumbItem,
|
||||||
|
BreadcrumbLink,
|
||||||
|
BreadcrumbPage,
|
||||||
|
BreadcrumbSeparator,
|
||||||
|
BreadcrumbEllipsis,
|
||||||
|
}
|
||||||
178
src/components/ui/form.tsx
Normal file
178
src/components/ui/form.tsx
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||||
|
import { Slot } from "@radix-ui/react-slot"
|
||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
ControllerProps,
|
||||||
|
FieldPath,
|
||||||
|
FieldValues,
|
||||||
|
FormProvider,
|
||||||
|
useFormContext,
|
||||||
|
} from "react-hook-form"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
|
||||||
|
const Form = FormProvider
|
||||||
|
|
||||||
|
type FormFieldContextValue<
|
||||||
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||||
|
> = {
|
||||||
|
name: TName
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||||
|
{} as FormFieldContextValue
|
||||||
|
)
|
||||||
|
|
||||||
|
const FormField = <
|
||||||
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||||
|
>({
|
||||||
|
...props
|
||||||
|
}: ControllerProps<TFieldValues, TName>) => {
|
||||||
|
return (
|
||||||
|
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||||
|
<Controller {...props} />
|
||||||
|
</FormFieldContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const useFormField = () => {
|
||||||
|
const fieldContext = React.useContext(FormFieldContext)
|
||||||
|
const itemContext = React.useContext(FormItemContext)
|
||||||
|
const { getFieldState, formState } = useFormContext()
|
||||||
|
|
||||||
|
const fieldState = getFieldState(fieldContext.name, formState)
|
||||||
|
|
||||||
|
if (!fieldContext) {
|
||||||
|
throw new Error("useFormField should be used within <FormField>")
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = itemContext
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name: fieldContext.name,
|
||||||
|
formItemId: `${id}-form-item`,
|
||||||
|
formDescriptionId: `${id}-form-item-description`,
|
||||||
|
formMessageId: `${id}-form-item-message`,
|
||||||
|
...fieldState,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormItemContextValue = {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||||
|
{} as FormItemContextValue
|
||||||
|
)
|
||||||
|
|
||||||
|
const FormItem = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
const id = React.useId()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormItemContext.Provider value={{ id }}>
|
||||||
|
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
||||||
|
</FormItemContext.Provider>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
FormItem.displayName = "FormItem"
|
||||||
|
|
||||||
|
const FormLabel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
const { error, formItemId } = useFormField()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Label
|
||||||
|
ref={ref}
|
||||||
|
className={cn(error && "text-destructive", className)}
|
||||||
|
htmlFor={formItemId}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
FormLabel.displayName = "FormLabel"
|
||||||
|
|
||||||
|
const FormControl = React.forwardRef<
|
||||||
|
React.ElementRef<typeof Slot>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof Slot>
|
||||||
|
>(({ ...props }, ref) => {
|
||||||
|
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Slot
|
||||||
|
ref={ref}
|
||||||
|
id={formItemId}
|
||||||
|
aria-describedby={
|
||||||
|
!error
|
||||||
|
? `${formDescriptionId}`
|
||||||
|
: `${formDescriptionId} ${formMessageId}`
|
||||||
|
}
|
||||||
|
aria-invalid={!!error}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
FormControl.displayName = "FormControl"
|
||||||
|
|
||||||
|
const FormDescription = React.forwardRef<
|
||||||
|
HTMLParagraphElement,
|
||||||
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
const { formDescriptionId } = useFormField()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<p
|
||||||
|
ref={ref}
|
||||||
|
id={formDescriptionId}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
FormDescription.displayName = "FormDescription"
|
||||||
|
|
||||||
|
const FormMessage = React.forwardRef<
|
||||||
|
HTMLParagraphElement,
|
||||||
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
|
>(({ className, children, ...props }, ref) => {
|
||||||
|
const { error, formMessageId } = useFormField()
|
||||||
|
const body = error ? String(error?.message) : children
|
||||||
|
|
||||||
|
if (!body) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<p
|
||||||
|
ref={ref}
|
||||||
|
id={formMessageId}
|
||||||
|
className={cn("text-sm font-medium text-destructive", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{body}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
FormMessage.displayName = "FormMessage"
|
||||||
|
|
||||||
|
export {
|
||||||
|
useFormField,
|
||||||
|
Form,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormMessage,
|
||||||
|
FormField,
|
||||||
|
}
|
||||||
124
src/components/ui/table.tsx
Normal file
124
src/components/ui/table.tsx
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Table = React.forwardRef<
|
||||||
|
HTMLTableElement,
|
||||||
|
React.HTMLAttributes<HTMLTableElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div className="relative w-full overflow-auto">
|
||||||
|
<table
|
||||||
|
ref={ref}
|
||||||
|
className={cn("w-full caption-bottom text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
Table.displayName = "Table"
|
||||||
|
|
||||||
|
const TableHeader = React.forwardRef<
|
||||||
|
HTMLTableSectionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<thead
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"[&_tr]:border-b",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableHeader.displayName = "TableHeader"
|
||||||
|
|
||||||
|
const TableBody = React.forwardRef<
|
||||||
|
HTMLTableSectionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<tbody
|
||||||
|
ref={ref}
|
||||||
|
className={cn("[&_tr:last-child]:border-0", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableBody.displayName = "TableBody"
|
||||||
|
|
||||||
|
const TableFooter = React.forwardRef<
|
||||||
|
HTMLTableSectionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<tfoot
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableFooter.displayName = "TableFooter"
|
||||||
|
|
||||||
|
const TableRow = React.forwardRef<
|
||||||
|
HTMLTableRowElement,
|
||||||
|
React.HTMLAttributes<HTMLTableRowElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<tr
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableRow.displayName = "TableRow"
|
||||||
|
|
||||||
|
const TableHead = React.forwardRef<
|
||||||
|
HTMLTableCellElement,
|
||||||
|
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<th
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableHead.displayName = "TableHead"
|
||||||
|
|
||||||
|
const TableCell = React.forwardRef<
|
||||||
|
HTMLTableCellElement,
|
||||||
|
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<td
|
||||||
|
ref={ref}
|
||||||
|
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableCell.displayName = "TableCell"
|
||||||
|
|
||||||
|
const TableCaption = React.forwardRef<
|
||||||
|
HTMLTableCaptionElement,
|
||||||
|
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<caption
|
||||||
|
ref={ref}
|
||||||
|
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableCaption.displayName = "TableCaption"
|
||||||
|
|
||||||
|
export {
|
||||||
|
Table,
|
||||||
|
TableHeader,
|
||||||
|
TableBody,
|
||||||
|
TableFooter,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
TableCell,
|
||||||
|
TableCaption,
|
||||||
|
}
|
||||||
55
src/components/ui/tabs.tsx
Normal file
55
src/components/ui/tabs.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Tabs = TabsPrimitive.Root
|
||||||
|
|
||||||
|
const TabsList = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TabsPrimitive.List>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<TabsPrimitive.List
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TabsList.displayName = TabsPrimitive.List.displayName
|
||||||
|
|
||||||
|
const TabsTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<TabsPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
||||||
|
|
||||||
|
const TabsContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<TabsPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TabsContent.displayName = TabsPrimitive.Content.displayName
|
||||||
|
|
||||||
|
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
||||||
@@ -3,10 +3,6 @@
|
|||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import { lucia, validateRequest } from ".";
|
import { lucia, validateRequest } from ".";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import prisma from "../db";
|
|
||||||
import { generateId } from "lucia";
|
|
||||||
import { accountSchema } from "./zod";
|
|
||||||
import { hash, verify } from "@node-rs/argon2";
|
|
||||||
|
|
||||||
export async function logout() {
|
export async function logout() {
|
||||||
const { session } = await validateRequest();
|
const { session } = await validateRequest();
|
||||||
@@ -15,78 +11,3 @@ export async function logout() {
|
|||||||
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
||||||
return redirect("/auth");
|
return redirect("/auth");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function login(prev: any, data: FormData) {
|
|
||||||
const checkSchema = await accountSchema.safeParseAsync(Object.fromEntries(data.entries()))
|
|
||||||
if (!checkSchema.success)
|
|
||||||
return {
|
|
||||||
error: `From ${checkSchema.error.errors[0].path[0]}: ${checkSchema.error.errors[0].message}`,
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
const { username, password } = checkSchema.data;
|
|
||||||
|
|
||||||
const existingUser = await prisma.user.findUnique({
|
|
||||||
where: {
|
|
||||||
username: username
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (!existingUser) {
|
|
||||||
// NOTE:
|
|
||||||
// Returning immediately allows malicious actors to figure out valid usernames from response times,
|
|
||||||
// allowing them to only focus on guessing passwords in brute-force attacks.
|
|
||||||
// As a preventive measure, you may want to hash passwords even for invalid usernames.
|
|
||||||
// However, valid usernames can be already be revealed with the signup page among other methods.
|
|
||||||
// It will also be much more resource intensive.
|
|
||||||
// Since protecting against this is non-trivial,
|
|
||||||
// it is crucial your implementation is protected against brute-force attacks with login throttling etc.
|
|
||||||
// If usernames are public, you may outright tell the user that the username is invalid.
|
|
||||||
return {
|
|
||||||
error: "Incorrect username or password",
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const validPassword = await verify(existingUser.hashed_password, password);
|
|
||||||
if (!validPassword) {
|
|
||||||
return {
|
|
||||||
error: "Incorrect username or password",
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const session = await lucia.createSession(existingUser.id, {});
|
|
||||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
|
||||||
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
|
||||||
return redirect("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function signup(prev: any, formData: FormData): Promise<ActionResult> {
|
|
||||||
const checkSchema = await accountSchema.safeParseAsync(Object.fromEntries(formData.entries()))
|
|
||||||
if (!checkSchema.success)
|
|
||||||
return {
|
|
||||||
error: `From ${checkSchema.error.errors[0].path[0]}: ${checkSchema.error.errors[0].message}`,
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
const { username, password } = checkSchema.data;
|
|
||||||
|
|
||||||
const hashedPassword = await hash(password);
|
|
||||||
const userId = generateId(15);
|
|
||||||
|
|
||||||
await prisma.user.create({
|
|
||||||
data: {
|
|
||||||
id: userId,
|
|
||||||
username: username,
|
|
||||||
hashed_password: hashedPassword
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const session = await lucia.createSession(userId, {});
|
|
||||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
|
||||||
cookies().set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
|
|
||||||
return redirect("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ActionResult {
|
|
||||||
error: string | null;
|
|
||||||
success: boolean | null;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import { z } from 'zod'
|
|
||||||
|
|
||||||
export const accountSchema = z.object({
|
|
||||||
username: z.string().min(3, { message: 'Mininum 3 characters' }).max(31, { message: 'Maximum 31 characters' }).regex(/^[a-z0-9_-]+$/, { message: 'Only characters from a-z, 0-9, underscores and dashes' }),
|
|
||||||
password: z.string().min(6, { message: 'Minimum 6 characters' }).max(255, { message: 'Maximum 255 characters' }),
|
|
||||||
})
|
|
||||||
11
src/lib/bodyGen.ts
Normal file
11
src/lib/bodyGen.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export const bodyGen = (customData: string[]) => {
|
||||||
|
// thankfully ai came in clutch with the comma brainfuck here
|
||||||
|
return `{
|
||||||
|
"message": "Hello, world!",
|
||||||
|
${customData.map((data) => `"${data}": "${data}"`).join(',\n ')}
|
||||||
|
}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const bodyGenNoIdent = (customData: string[]) => {
|
||||||
|
return JSON.stringify(JSON.parse(bodyGen(customData)));
|
||||||
|
}
|
||||||
98
src/lib/forms/actions.ts
Normal file
98
src/lib/forms/actions.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
'use server'
|
||||||
|
|
||||||
|
import { customDataSchema, projectSettingsSchema, ratelimitChangeSchema } from "@/components/app/UniversalForm/zod";
|
||||||
|
import { validateRequest } from "../auth";
|
||||||
|
import prisma from "../db";
|
||||||
|
import zodVerify from "../zodVerify";
|
||||||
|
import { createSchema } from "./zod";
|
||||||
|
|
||||||
|
export async function create(prev: any, formData: FormData) {
|
||||||
|
const zod = await zodVerify(createSchema, formData);
|
||||||
|
const { user } = await validateRequest();
|
||||||
|
if (!user) {
|
||||||
|
return { success: false, error: "You must be logged in" };
|
||||||
|
}
|
||||||
|
if (!zod.success) {
|
||||||
|
return zod;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbCreate = await prisma.project.create({
|
||||||
|
data: {
|
||||||
|
...zod.data,
|
||||||
|
user: {
|
||||||
|
connect: {
|
||||||
|
id: user.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { success: true, id: dbCreate.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editProject(prev: any, formData: FormData) {
|
||||||
|
const zod = await zodVerify(projectSettingsSchema, formData);
|
||||||
|
const { user } = await validateRequest();
|
||||||
|
if (!user) {
|
||||||
|
return { success: false, error: "You must be logged in" };
|
||||||
|
}
|
||||||
|
if (!zod.success) {
|
||||||
|
return zod;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbUpdate = await prisma.project.update({
|
||||||
|
where: {
|
||||||
|
id: zod.data.id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
...zod.data,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { success: true, id: dbUpdate.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function ratelimitChange(prev: any, formData: FormData) {
|
||||||
|
// @ts-ignore transforming string to number makes the types go crazy
|
||||||
|
const zod = await zodVerify(ratelimitChangeSchema, formData);
|
||||||
|
const { user } = await validateRequest();
|
||||||
|
if (!user) {
|
||||||
|
return { success: false, error: "You must be logged in" };
|
||||||
|
}
|
||||||
|
if (!zod.success) {
|
||||||
|
return zod;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbUpdate = await prisma.project.update({
|
||||||
|
where: {
|
||||||
|
id: zod.data.id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
rateLimitReq: zod.data.requests,
|
||||||
|
rateLimitTime: zod.data.duration,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { success: true, id: dbUpdate.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function customData(prev: any, formData: FormData) {
|
||||||
|
const zod = await zodVerify(customDataSchema, formData);
|
||||||
|
const { user } = await validateRequest();
|
||||||
|
if (!user) {
|
||||||
|
return { success: false, error: "You must be logged in" };
|
||||||
|
}
|
||||||
|
if (!zod.success) {
|
||||||
|
return zod;
|
||||||
|
}
|
||||||
|
|
||||||
|
// separate by comma, remove whitespace
|
||||||
|
const splitted = zod.data.data.split(',').map((s: string) => s.trim());
|
||||||
|
|
||||||
|
const dbUpdate = await prisma.project.update({
|
||||||
|
where: {
|
||||||
|
id: zod.data.id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
customData: splitted,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { success: true, id: dbUpdate.id };
|
||||||
|
}
|
||||||
8
src/lib/forms/zod.ts
Normal file
8
src/lib/forms/zod.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const createSchema = z.object({
|
||||||
|
name: z.string().nonempty(),
|
||||||
|
description: z.string().nonempty(),
|
||||||
|
github: z.string().url().nonempty(),
|
||||||
|
});
|
||||||
|
export type createSchemaType = z.infer<typeof createSchema>;
|
||||||
34
src/lib/zodVerify.ts
Normal file
34
src/lib/zodVerify.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
|
import { ZodEffects, ZodSchema, ZodType } from 'zod';
|
||||||
|
|
||||||
|
type SuccessResult<T> = {
|
||||||
|
success: true;
|
||||||
|
data: T;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ErrorResult = {
|
||||||
|
success: false;
|
||||||
|
error: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type VerifyResult<T> = SuccessResult<T> | ErrorResult;
|
||||||
|
|
||||||
|
export default async function zodVerify<T>(schema: ZodType<T>, data: FormData | Object): Promise<VerifyResult<T>> {
|
||||||
|
let obj: any = data;
|
||||||
|
if (data instanceof FormData) {
|
||||||
|
obj = Object.fromEntries(data.entries());
|
||||||
|
}
|
||||||
|
|
||||||
|
const zod = schema.safeParse(obj);
|
||||||
|
if (!zod.success) {
|
||||||
|
return {
|
||||||
|
error: `From ${zod.error.errors[0].path[0]}: ${zod.error.errors[0].message}`,
|
||||||
|
success: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: zod.data,
|
||||||
|
};
|
||||||
|
}
|
||||||
419
yarn.lock
419
yarn.lock
@@ -341,6 +341,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2"
|
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2"
|
||||||
integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==
|
integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==
|
||||||
|
|
||||||
|
"@hookform/resolvers@^3.9.1":
|
||||||
|
version "3.9.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-3.9.1.tgz#a23883c40bfd449cb6c6ab5a0fa0729184c950ff"
|
||||||
|
integrity sha512-ud2HqmGBM0P0IABqoskKWI6PEf6ZDDBZkFqe2Vnl+mTHCEHzr3ISjjZyCwTjC/qpL25JC9aIDkloQejvMeq0ug==
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.11.14":
|
"@humanwhocodes/config-array@^0.11.14":
|
||||||
version "0.11.14"
|
version "0.11.14"
|
||||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
|
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
|
||||||
@@ -875,6 +880,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2"
|
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2"
|
||||||
integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==
|
integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==
|
||||||
|
|
||||||
|
"@radix-ui/primitive@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.1.tgz#fc169732d755c7fbad33ba8d0cd7fd10c90dc8e3"
|
||||||
|
integrity sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==
|
||||||
|
|
||||||
"@radix-ui/react-arrow@1.1.0":
|
"@radix-ui/react-arrow@1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz#744f388182d360b86285217e43b6c63633f39e7a"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz#744f388182d360b86285217e43b6c63633f39e7a"
|
||||||
@@ -903,6 +913,16 @@
|
|||||||
"@radix-ui/react-primitive" "2.0.0"
|
"@radix-ui/react-primitive" "2.0.0"
|
||||||
"@radix-ui/react-slot" "1.1.0"
|
"@radix-ui/react-slot" "1.1.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-collection@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.1.tgz#be2c7e01d3508e6d4b6d838f492e7d182f17d3b0"
|
||||||
|
integrity sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.1"
|
||||||
|
"@radix-ui/react-context" "1.1.1"
|
||||||
|
"@radix-ui/react-primitive" "2.0.1"
|
||||||
|
"@radix-ui/react-slot" "1.1.1"
|
||||||
|
|
||||||
"@radix-ui/react-compose-refs@1.0.1":
|
"@radix-ui/react-compose-refs@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
|
||||||
@@ -915,6 +935,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74"
|
||||||
integrity sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==
|
integrity sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==
|
||||||
|
|
||||||
|
"@radix-ui/react-compose-refs@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec"
|
||||||
|
integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==
|
||||||
|
|
||||||
"@radix-ui/react-context@1.0.1":
|
"@radix-ui/react-context@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c"
|
||||||
@@ -982,12 +1007,12 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||||
|
|
||||||
"@radix-ui/react-label@^2.1.0":
|
"@radix-ui/react-label@^2.1.1":
|
||||||
version "2.1.0"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-2.1.0.tgz#3aa2418d70bb242be37c51ff5e51a2adcbc372e3"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-2.1.1.tgz#f30bd577b26873c638006e4f65761d4c6b80566d"
|
||||||
integrity sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==
|
integrity sha512-UUw5E4e/2+4kFMH7+YxORXGWggtY6sM8WIwh5RZchhLuUg2H1hc98Py+pr8HMz6rdaYrK2t296ZEjYLOCO5uUw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@radix-ui/react-primitive" "2.0.0"
|
"@radix-ui/react-primitive" "2.0.1"
|
||||||
|
|
||||||
"@radix-ui/react-menu@2.1.2":
|
"@radix-ui/react-menu@2.1.2":
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
@@ -1045,6 +1070,14 @@
|
|||||||
"@radix-ui/react-compose-refs" "1.1.0"
|
"@radix-ui/react-compose-refs" "1.1.0"
|
||||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-presence@1.1.2":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.2.tgz#bb764ed8a9118b7ec4512da5ece306ded8703cdc"
|
||||||
|
integrity sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.1"
|
||||||
|
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||||
|
|
||||||
"@radix-ui/react-primitive@1.0.3":
|
"@radix-ui/react-primitive@1.0.3":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
|
||||||
@@ -1060,6 +1093,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@radix-ui/react-slot" "1.1.0"
|
"@radix-ui/react-slot" "1.1.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-primitive@2.0.1":
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz#6d9efc550f7520135366f333d1e820cf225fad9e"
|
||||||
|
integrity sha512-sHCWTtxwNn3L3fH8qAfnF3WbUZycW93SM1j3NFDzXBiz8D6F5UTTy8G1+WFEaiCdvCVRJWj6N2R4Xq6HdiHmDg==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-slot" "1.1.1"
|
||||||
|
|
||||||
"@radix-ui/react-roving-focus@1.1.0":
|
"@radix-ui/react-roving-focus@1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz#b30c59daf7e714c748805bfe11c76f96caaac35e"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz#b30c59daf7e714c748805bfe11c76f96caaac35e"
|
||||||
@@ -1075,6 +1115,21 @@
|
|||||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-roving-focus@1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.1.tgz#3b3abb1e03646937f28d9ab25e96343667ca6520"
|
||||||
|
integrity sha512-QE1RoxPGJ/Nm8Qmk0PxP8ojmoaS67i0s7hVssS7KuI2FQoc/uzVlZsqKfQvxPE6D8hICCPHJ4D88zNhT3OOmkw==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/primitive" "1.1.1"
|
||||||
|
"@radix-ui/react-collection" "1.1.1"
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.1"
|
||||||
|
"@radix-ui/react-context" "1.1.1"
|
||||||
|
"@radix-ui/react-direction" "1.1.0"
|
||||||
|
"@radix-ui/react-id" "1.1.0"
|
||||||
|
"@radix-ui/react-primitive" "2.0.1"
|
||||||
|
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||||
|
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||||
|
|
||||||
"@radix-ui/react-slot@1.0.2":
|
"@radix-ui/react-slot@1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
|
||||||
@@ -1083,13 +1138,34 @@
|
|||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@radix-ui/react-compose-refs" "1.0.1"
|
"@radix-ui/react-compose-refs" "1.0.1"
|
||||||
|
|
||||||
"@radix-ui/react-slot@1.1.0", "@radix-ui/react-slot@^1.1.0":
|
"@radix-ui/react-slot@1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84"
|
||||||
integrity sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==
|
integrity sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@radix-ui/react-compose-refs" "1.1.0"
|
"@radix-ui/react-compose-refs" "1.1.0"
|
||||||
|
|
||||||
|
"@radix-ui/react-slot@1.1.1", "@radix-ui/react-slot@^1.1.1":
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.1.tgz#ab9a0ffae4027db7dc2af503c223c978706affc3"
|
||||||
|
integrity sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.1"
|
||||||
|
|
||||||
|
"@radix-ui/react-tabs@^1.1.2":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.1.2.tgz#a72da059593cba30fccb30a226d63af686b32854"
|
||||||
|
integrity sha512-9u/tQJMcC2aGq7KXpGivMm1mgq7oRJKXphDwdypPd/j21j/2znamPU8WkXgnhUaTrSFNIt8XhOyCAupg8/GbwQ==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/primitive" "1.1.1"
|
||||||
|
"@radix-ui/react-context" "1.1.1"
|
||||||
|
"@radix-ui/react-direction" "1.1.0"
|
||||||
|
"@radix-ui/react-id" "1.1.0"
|
||||||
|
"@radix-ui/react-presence" "1.1.2"
|
||||||
|
"@radix-ui/react-primitive" "2.0.1"
|
||||||
|
"@radix-ui/react-roving-focus" "1.1.1"
|
||||||
|
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||||
|
|
||||||
"@radix-ui/react-use-callback-ref@1.0.1":
|
"@radix-ui/react-use-callback-ref@1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
|
||||||
@@ -1147,80 +1223,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438"
|
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438"
|
||||||
integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
|
integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
|
||||||
|
|
||||||
"@remix-run/node@^2.15.0":
|
|
||||||
version "2.15.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/node/-/node-2.15.1.tgz#f57b06016f3a71cbdc47e89bdc08ac579e2a2f66"
|
|
||||||
integrity sha512-23xWN3/yOohNUr27KS7hEcDMbtufMkniXfXkcLx8Dz2wUVNfJYGpICjeV48Ue/INtpiUCCzOYwkL9VRjIMEJbA==
|
|
||||||
dependencies:
|
|
||||||
"@remix-run/server-runtime" "2.15.1"
|
|
||||||
"@remix-run/web-fetch" "^4.4.2"
|
|
||||||
"@web3-storage/multipart-parser" "^1.0.0"
|
|
||||||
cookie-signature "^1.1.0"
|
|
||||||
source-map-support "^0.5.21"
|
|
||||||
stream-slice "^0.1.2"
|
|
||||||
undici "^6.11.1"
|
|
||||||
|
|
||||||
"@remix-run/router@1.21.0":
|
|
||||||
version "1.21.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.21.0.tgz#c65ae4262bdcfe415dbd4f64ec87676e4a56e2b5"
|
|
||||||
integrity sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==
|
|
||||||
|
|
||||||
"@remix-run/server-runtime@2.15.1":
|
|
||||||
version "2.15.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/server-runtime/-/server-runtime-2.15.1.tgz#1ebf96c351f3398d73856fae38dbd41fd45b2da2"
|
|
||||||
integrity sha512-TDM3rzax//N2F5uNMV5pNTWAop8cYul6hteDu+Xmfwys/eRGlbzEf7YJzyRj6Kcsg2TFVHI7+xEPItGAVm1hHA==
|
|
||||||
dependencies:
|
|
||||||
"@remix-run/router" "1.21.0"
|
|
||||||
"@types/cookie" "^0.6.0"
|
|
||||||
"@web3-storage/multipart-parser" "^1.0.0"
|
|
||||||
cookie "^0.6.0"
|
|
||||||
set-cookie-parser "^2.4.8"
|
|
||||||
source-map "^0.7.3"
|
|
||||||
turbo-stream "2.4.0"
|
|
||||||
|
|
||||||
"@remix-run/web-blob@^3.1.0":
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/web-blob/-/web-blob-3.1.0.tgz#e0c669934c1eb6028960047e57a13ed38bbfb434"
|
|
||||||
integrity sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==
|
|
||||||
dependencies:
|
|
||||||
"@remix-run/web-stream" "^1.1.0"
|
|
||||||
web-encoding "1.1.5"
|
|
||||||
|
|
||||||
"@remix-run/web-fetch@^4.4.2":
|
|
||||||
version "4.4.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/web-fetch/-/web-fetch-4.4.2.tgz#ce7aedef72cc26e15060e8cf84674029f92809b6"
|
|
||||||
integrity sha512-jgKfzA713/4kAW/oZ4bC3MoLWyjModOVDjFPNseVqcJKSafgIscrYL9G50SurEYLswPuoU3HzSbO0jQCMYWHhA==
|
|
||||||
dependencies:
|
|
||||||
"@remix-run/web-blob" "^3.1.0"
|
|
||||||
"@remix-run/web-file" "^3.1.0"
|
|
||||||
"@remix-run/web-form-data" "^3.1.0"
|
|
||||||
"@remix-run/web-stream" "^1.1.0"
|
|
||||||
"@web3-storage/multipart-parser" "^1.0.0"
|
|
||||||
abort-controller "^3.0.0"
|
|
||||||
data-uri-to-buffer "^3.0.1"
|
|
||||||
mrmime "^1.0.0"
|
|
||||||
|
|
||||||
"@remix-run/web-file@^3.1.0":
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/web-file/-/web-file-3.1.0.tgz#07219021a2910e90231bc30ca1ce693d0e9d3825"
|
|
||||||
integrity sha512-dW2MNGwoiEYhlspOAXFBasmLeYshyAyhIdrlXBi06Duex5tDr3ut2LFKVj7tyHLmn8nnNwFf1BjNbkQpygC2aQ==
|
|
||||||
dependencies:
|
|
||||||
"@remix-run/web-blob" "^3.1.0"
|
|
||||||
|
|
||||||
"@remix-run/web-form-data@^3.1.0":
|
|
||||||
version "3.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/web-form-data/-/web-form-data-3.1.0.tgz#47f9ad8ce8bf1c39ed83eab31e53967fe8e3df6a"
|
|
||||||
integrity sha512-NdeohLMdrb+pHxMQ/Geuzdp0eqPbea+Ieo8M8Jx2lGC6TBHsgHzYcBvr0LyPdPVycNRDEpWpiDdCOdCryo3f9A==
|
|
||||||
dependencies:
|
|
||||||
web-encoding "1.1.5"
|
|
||||||
|
|
||||||
"@remix-run/web-stream@^1.1.0":
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/web-stream/-/web-stream-1.1.0.tgz#b93a8f806c2c22204930837c44d81fdedfde079f"
|
|
||||||
integrity sha512-KRJtwrjRV5Bb+pM7zxcTJkhIqWWSy+MYsIxHK+0m5atcznsf15YwUBWHWulZerV2+vvHH1Lp1DD7pw6qKW8SgA==
|
|
||||||
dependencies:
|
|
||||||
web-streams-polyfill "^3.1.1"
|
|
||||||
|
|
||||||
"@rushstack/eslint-patch@^1.3.3":
|
"@rushstack/eslint-patch@^1.3.3":
|
||||||
version "1.10.2"
|
version "1.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz#053f1540703faa81dea2966b768ee5581c66aeda"
|
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz#053f1540703faa81dea2966b768ee5581c66aeda"
|
||||||
@@ -1239,43 +1241,6 @@
|
|||||||
"@swc/counter" "^0.1.3"
|
"@swc/counter" "^0.1.3"
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
"@tanstack/form-core@0.40.2":
|
|
||||||
version "0.40.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/form-core/-/form-core-0.40.2.tgz#095ead78f09c1a3aa75b46456bfdb55cf13fc786"
|
|
||||||
integrity sha512-ecJgr+jRKSClUzYhOixfiJTXqfCxAiWmeMTKKzV848OfCtdzWxEzSasZLDMQG5KlyL9q/GDhk1GRHQmEUxynoA==
|
|
||||||
dependencies:
|
|
||||||
"@tanstack/store" "^0.6.0"
|
|
||||||
|
|
||||||
"@tanstack/react-form@^0.40.2":
|
|
||||||
version "0.40.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/react-form/-/react-form-0.40.2.tgz#c4382ccd04644ccf4873a470000f57c7b177c311"
|
|
||||||
integrity sha512-YHGsnqYLE5lFz5jvoR0RGczhzX0WFLqe8mtFRixk2uN92zdNTcxSgoJHrCV5/q+fWY5+bxtixB/B0cApi8qQmA==
|
|
||||||
dependencies:
|
|
||||||
"@remix-run/node" "^2.15.0"
|
|
||||||
"@tanstack/form-core" "0.40.2"
|
|
||||||
"@tanstack/react-store" "^0.6.1"
|
|
||||||
decode-formdata "^0.8.0"
|
|
||||||
|
|
||||||
"@tanstack/react-store@^0.6.1":
|
|
||||||
version "0.6.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/react-store/-/react-store-0.6.1.tgz#2632409ff4257846584b7779daed7eff3e4b8de1"
|
|
||||||
integrity sha512-6gOopOpPp1cAXkEyTEv6tMbAywwFunvIdCKN/SpEiButUayjXU+Q5Sp5Y3hREN3VMR4OA5+RI5SPhhJoqP9e4w==
|
|
||||||
dependencies:
|
|
||||||
"@tanstack/store" "0.6.0"
|
|
||||||
use-sync-external-store "^1.2.2"
|
|
||||||
|
|
||||||
"@tanstack/store@0.6.0", "@tanstack/store@^0.6.0":
|
|
||||||
version "0.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/store/-/store-0.6.0.tgz#f73d711c6e53f2f91c0f0af0771583095d449f67"
|
|
||||||
integrity sha512-+m2OBglsjXcLmmKOX6/9v8BDOCtyxhMmZLsRUDswOOSdIIR9mvv6i0XNKsmTh3AlYU8c1mRcodC8/Vyf+69VlQ==
|
|
||||||
|
|
||||||
"@tanstack/zod-form-adapter@^0.40.2":
|
|
||||||
version "0.40.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/zod-form-adapter/-/zod-form-adapter-0.40.2.tgz#98228e3bdf4fe5ae67a42e2516e8aaa07e3b6ab8"
|
|
||||||
integrity sha512-450DAYAb7uN6GwEhMWQlGOvfQzj6ZtgEsZf94M1a3S/lGioKAFuidelRaErXpG4b7lvZiQmfyhlTA0RwNE2r0Q==
|
|
||||||
dependencies:
|
|
||||||
"@tanstack/form-core" "0.40.2"
|
|
||||||
|
|
||||||
"@ts-morph/common@~0.19.0":
|
"@ts-morph/common@~0.19.0":
|
||||||
version "0.19.0"
|
version "0.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.19.0.tgz#927fcd81d1bbc09c89c4a310a84577fb55f3694e"
|
resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.19.0.tgz#927fcd81d1bbc09c89c4a310a84577fb55f3694e"
|
||||||
@@ -1300,11 +1265,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
"@types/cookie@^0.6.0":
|
|
||||||
version "0.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5"
|
|
||||||
integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==
|
|
||||||
|
|
||||||
"@types/json5@^0.0.29":
|
"@types/json5@^0.0.29":
|
||||||
version "0.0.29"
|
version "0.0.29"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
@@ -1388,23 +1348,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
|
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
|
||||||
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
|
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
|
||||||
|
|
||||||
"@web3-storage/multipart-parser@^1.0.0":
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz#6b69dc2a32a5b207ba43e556c25cc136a56659c4"
|
|
||||||
integrity sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==
|
|
||||||
|
|
||||||
"@zxing/text-encoding@0.9.0":
|
|
||||||
version "0.9.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
|
|
||||||
integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
|
|
||||||
|
|
||||||
abort-controller@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
|
||||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
|
||||||
dependencies:
|
|
||||||
event-target-shim "^5.0.0"
|
|
||||||
|
|
||||||
acorn-jsx@^5.3.2:
|
acorn-jsx@^5.3.2:
|
||||||
version "5.3.2"
|
version "5.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||||
@@ -1689,11 +1632,6 @@ browserslist@^4.24.0:
|
|||||||
node-releases "^2.0.19"
|
node-releases "^2.0.19"
|
||||||
update-browserslist-db "^1.1.1"
|
update-browserslist-db "^1.1.1"
|
||||||
|
|
||||||
buffer-from@^1.0.0:
|
|
||||||
version "1.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
|
|
||||||
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
|
|
||||||
|
|
||||||
buffer@^6.0.3:
|
buffer@^6.0.3:
|
||||||
version "6.0.3"
|
version "6.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
|
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
|
||||||
@@ -1709,14 +1647,6 @@ busboy@1.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
streamsearch "^1.1.0"
|
streamsearch "^1.1.0"
|
||||||
|
|
||||||
call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840"
|
|
||||||
integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==
|
|
||||||
dependencies:
|
|
||||||
es-errors "^1.3.0"
|
|
||||||
function-bind "^1.1.2"
|
|
||||||
|
|
||||||
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||||
@@ -1728,24 +1658,6 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
|||||||
get-intrinsic "^1.2.4"
|
get-intrinsic "^1.2.4"
|
||||||
set-function-length "^1.2.1"
|
set-function-length "^1.2.1"
|
||||||
|
|
||||||
call-bind@^1.0.8:
|
|
||||||
version "1.0.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
|
|
||||||
integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
|
|
||||||
dependencies:
|
|
||||||
call-bind-apply-helpers "^1.0.0"
|
|
||||||
es-define-property "^1.0.0"
|
|
||||||
get-intrinsic "^1.2.4"
|
|
||||||
set-function-length "^1.2.2"
|
|
||||||
|
|
||||||
call-bound@^1.0.2:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.2.tgz#9dbd4daf9f5f753bec3e4c8fbb8a2ecc4de6c39b"
|
|
||||||
integrity sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==
|
|
||||||
dependencies:
|
|
||||||
call-bind "^1.0.8"
|
|
||||||
get-intrinsic "^1.2.5"
|
|
||||||
|
|
||||||
callsites@^3.0.0:
|
callsites@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||||
@@ -1865,16 +1777,6 @@ convert-source-map@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||||
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
|
||||||
|
|
||||||
cookie-signature@^1.1.0:
|
|
||||||
version "1.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793"
|
|
||||||
integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==
|
|
||||||
|
|
||||||
cookie@^0.6.0:
|
|
||||||
version "0.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
|
||||||
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
|
||||||
|
|
||||||
cosmiconfig@^8.1.3:
|
cosmiconfig@^8.1.3:
|
||||||
version "8.3.6"
|
version "8.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3"
|
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3"
|
||||||
@@ -1918,11 +1820,6 @@ damerau-levenshtein@^1.0.8:
|
|||||||
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
|
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
|
||||||
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
|
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
|
||||||
|
|
||||||
data-uri-to-buffer@^3.0.1:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
|
|
||||||
integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==
|
|
||||||
|
|
||||||
data-uri-to-buffer@^4.0.0:
|
data-uri-to-buffer@^4.0.0:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
|
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e"
|
||||||
@@ -1976,11 +1873,6 @@ debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "2.1.2"
|
ms "2.1.2"
|
||||||
|
|
||||||
decode-formdata@^0.8.0:
|
|
||||||
version "0.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/decode-formdata/-/decode-formdata-0.8.0.tgz#1631d0252ee73de07cdd6ce04e22e6e8acadc987"
|
|
||||||
integrity sha512-iUzDgnWsw5ToSkFY7VPFA5Gfph6ROoOxOB7Ybna4miUSzLZ4KaSJk6IAB2AdW6+C9vCVWhjjNA4gjT6wF3eZHQ==
|
|
||||||
|
|
||||||
deep-is@^0.1.3:
|
deep-is@^0.1.3:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
||||||
@@ -2062,15 +1954,6 @@ doctrine@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
dunder-proto@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.0.tgz#c2fce098b3c8f8899554905f4377b6d85dabaa80"
|
|
||||||
integrity sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==
|
|
||||||
dependencies:
|
|
||||||
call-bind-apply-helpers "^1.0.0"
|
|
||||||
es-errors "^1.3.0"
|
|
||||||
gopd "^1.2.0"
|
|
||||||
|
|
||||||
eastasianwidth@^0.2.0:
|
eastasianwidth@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
|
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
|
||||||
@@ -2165,11 +2048,6 @@ es-define-property@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic "^1.2.4"
|
get-intrinsic "^1.2.4"
|
||||||
|
|
||||||
es-define-property@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
|
|
||||||
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
|
|
||||||
|
|
||||||
es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0:
|
es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
||||||
@@ -2450,11 +2328,6 @@ esutils@^2.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||||
|
|
||||||
event-target-shim@^5.0.0:
|
|
||||||
version "5.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
|
||||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
|
||||||
|
|
||||||
execa@^7.0.0:
|
execa@^7.0.0:
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9"
|
resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9"
|
||||||
@@ -2629,22 +2502,6 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@
|
|||||||
has-symbols "^1.0.3"
|
has-symbols "^1.0.3"
|
||||||
hasown "^2.0.0"
|
hasown "^2.0.0"
|
||||||
|
|
||||||
get-intrinsic@^1.2.5:
|
|
||||||
version "1.2.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.6.tgz#43dd3dd0e7b49b82b2dfcad10dc824bf7fc265d5"
|
|
||||||
integrity sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==
|
|
||||||
dependencies:
|
|
||||||
call-bind-apply-helpers "^1.0.1"
|
|
||||||
dunder-proto "^1.0.0"
|
|
||||||
es-define-property "^1.0.1"
|
|
||||||
es-errors "^1.3.0"
|
|
||||||
es-object-atoms "^1.0.0"
|
|
||||||
function-bind "^1.1.2"
|
|
||||||
gopd "^1.2.0"
|
|
||||||
has-symbols "^1.1.0"
|
|
||||||
hasown "^2.0.2"
|
|
||||||
math-intrinsics "^1.0.0"
|
|
||||||
|
|
||||||
get-nonce@^1.0.0:
|
get-nonce@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
|
resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
|
||||||
@@ -2762,11 +2619,6 @@ gopd@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic "^1.1.3"
|
get-intrinsic "^1.1.3"
|
||||||
|
|
||||||
gopd@^1.2.0:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
|
|
||||||
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
|
|
||||||
|
|
||||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4:
|
graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4:
|
||||||
version "4.2.11"
|
version "4.2.11"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||||
@@ -2804,11 +2656,6 @@ has-symbols@^1.0.2, has-symbols@^1.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
|
||||||
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
|
||||||
|
|
||||||
has-symbols@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
|
|
||||||
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
|
|
||||||
|
|
||||||
has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
|
has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
|
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
|
||||||
@@ -2888,14 +2735,6 @@ invariant@^2.2.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
loose-envify "^1.0.0"
|
loose-envify "^1.0.0"
|
||||||
|
|
||||||
is-arguments@^1.0.4:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.2.0.tgz#ad58c6aecf563b78ef2bf04df540da8f5d7d8e1b"
|
|
||||||
integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==
|
|
||||||
dependencies:
|
|
||||||
call-bound "^1.0.2"
|
|
||||||
has-tostringtag "^1.0.2"
|
|
||||||
|
|
||||||
is-array-buffer@^3.0.4:
|
is-array-buffer@^3.0.4:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98"
|
resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98"
|
||||||
@@ -2981,7 +2820,7 @@ is-fullwidth-code-point@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
|
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
|
||||||
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
||||||
|
|
||||||
is-generator-function@^1.0.10, is-generator-function@^1.0.7:
|
is-generator-function@^1.0.10:
|
||||||
version "1.0.10"
|
version "1.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
|
resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
|
||||||
integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
|
integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
|
||||||
@@ -3076,7 +2915,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
has-symbols "^1.0.2"
|
has-symbols "^1.0.2"
|
||||||
|
|
||||||
is-typed-array@^1.1.13, is-typed-array@^1.1.3:
|
is-typed-array@^1.1.13:
|
||||||
version "1.1.13"
|
version "1.1.13"
|
||||||
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229"
|
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229"
|
||||||
integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==
|
integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==
|
||||||
@@ -3341,11 +3180,6 @@ lucide-react@^0.368.0:
|
|||||||
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.368.0.tgz#3c0ee63f4f7d30ae63b621b2b8f04f9e409ee6e7"
|
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.368.0.tgz#3c0ee63f4f7d30ae63b621b2b8f04f9e409ee6e7"
|
||||||
integrity sha512-soryVrCjheZs8rbXKdINw9B8iPi5OajBJZMJ1HORig89ljcOcEokKKAgGbg3QWxSXel7JwHOfDFUdDHAKyUAMw==
|
integrity sha512-soryVrCjheZs8rbXKdINw9B8iPi5OajBJZMJ1HORig89ljcOcEokKKAgGbg3QWxSXel7JwHOfDFUdDHAKyUAMw==
|
||||||
|
|
||||||
math-intrinsics@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.0.0.tgz#4e04bf87c85aa51e90d078dac2252b4eb5260817"
|
|
||||||
integrity sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==
|
|
||||||
|
|
||||||
memfs-browser@^3.4.13000:
|
memfs-browser@^3.4.13000:
|
||||||
version "3.5.10302"
|
version "3.5.10302"
|
||||||
resolved "https://registry.yarnpkg.com/memfs-browser/-/memfs-browser-3.5.10302.tgz#2067baf616a1b3a8e8023a033e5ead434a7ea0c0"
|
resolved "https://registry.yarnpkg.com/memfs-browser/-/memfs-browser-3.5.10302.tgz#2067baf616a1b3a8e8023a033e5ead434a7ea0c0"
|
||||||
@@ -3431,11 +3265,6 @@ mkdirp@^2.1.6:
|
|||||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
|
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
|
||||||
integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
|
integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
|
||||||
|
|
||||||
mrmime@^1.0.0:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27"
|
|
||||||
integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==
|
|
||||||
|
|
||||||
ms@2.1.2:
|
ms@2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||||
@@ -3866,6 +3695,11 @@ react-dom@^18:
|
|||||||
loose-envify "^1.1.0"
|
loose-envify "^1.1.0"
|
||||||
scheduler "^0.23.1"
|
scheduler "^0.23.1"
|
||||||
|
|
||||||
|
react-hook-form@^7.54.1:
|
||||||
|
version "7.54.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.54.1.tgz#e99c2a55a5e4859fb47a8f55adf66b34d6ac331d"
|
||||||
|
integrity sha512-PUNzFwQeQ5oHiiTUO7GO/EJXGEtuun2Y1A59rLnZBBj+vNEOWt/3ERTiG1/zt7dVeJEM+4vDX/7XQ/qanuvPMg==
|
||||||
|
|
||||||
react-is@^16.13.1:
|
react-is@^16.13.1:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
@@ -4066,12 +3900,7 @@ semver@^7.5.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lru-cache "^6.0.0"
|
lru-cache "^6.0.0"
|
||||||
|
|
||||||
set-cookie-parser@^2.4.8:
|
set-function-length@^1.2.1:
|
||||||
version "2.7.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943"
|
|
||||||
integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==
|
|
||||||
|
|
||||||
set-function-length@^1.2.1, set-function-length@^1.2.2:
|
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
||||||
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
|
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
|
||||||
@@ -4174,24 +4003,11 @@ source-map-js@^1.0.2, source-map-js@^1.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||||
|
|
||||||
source-map-support@^0.5.21:
|
source-map@~0.6.1:
|
||||||
version "0.5.21"
|
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
|
||||||
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
|
|
||||||
dependencies:
|
|
||||||
buffer-from "^1.0.0"
|
|
||||||
source-map "^0.6.0"
|
|
||||||
|
|
||||||
source-map@^0.6.0, source-map@~0.6.1:
|
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
source-map@^0.7.3:
|
|
||||||
version "0.7.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
|
|
||||||
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
|
|
||||||
|
|
||||||
stdin-discarder@^0.1.0:
|
stdin-discarder@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz#22b3e400393a8e28ebf53f9958f3880622efde21"
|
resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.1.0.tgz#22b3e400393a8e28ebf53f9958f3880622efde21"
|
||||||
@@ -4199,11 +4015,6 @@ stdin-discarder@^0.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
bl "^5.0.0"
|
bl "^5.0.0"
|
||||||
|
|
||||||
stream-slice@^0.1.2:
|
|
||||||
version "0.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b"
|
|
||||||
integrity sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==
|
|
||||||
|
|
||||||
streamsearch@^1.1.0:
|
streamsearch@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
||||||
@@ -4489,11 +4300,6 @@ tslib@^2.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
|
|
||||||
turbo-stream@2.4.0:
|
|
||||||
version "2.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/turbo-stream/-/turbo-stream-2.4.0.tgz#1e4fca6725e90fa14ac4adb782f2d3759a5695f0"
|
|
||||||
integrity sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==
|
|
||||||
|
|
||||||
type-check@^0.4.0, type-check@~0.4.0:
|
type-check@^0.4.0, type-check@~0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
||||||
@@ -4570,11 +4376,6 @@ undici-types@~5.26.4:
|
|||||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||||
|
|
||||||
undici@^6.11.1:
|
|
||||||
version "6.21.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.0.tgz#4b3d3afaef984e07b48e7620c34ed8a285ed4cd4"
|
|
||||||
integrity sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==
|
|
||||||
|
|
||||||
universalify@^2.0.0:
|
universalify@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
|
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
|
||||||
@@ -4610,27 +4411,11 @@ use-sidecar@^1.1.2:
|
|||||||
detect-node-es "^1.1.0"
|
detect-node-es "^1.1.0"
|
||||||
tslib "^2.0.0"
|
tslib "^2.0.0"
|
||||||
|
|
||||||
use-sync-external-store@^1.2.2:
|
|
||||||
version "1.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz#adbc795d8eeb47029963016cefdf89dc799fcebc"
|
|
||||||
integrity sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==
|
|
||||||
|
|
||||||
util-deprecate@^1.0.1, util-deprecate@^1.0.2:
|
util-deprecate@^1.0.1, util-deprecate@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||||
|
|
||||||
util@^0.12.3:
|
|
||||||
version "0.12.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
|
|
||||||
integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
|
|
||||||
dependencies:
|
|
||||||
inherits "^2.0.3"
|
|
||||||
is-arguments "^1.0.4"
|
|
||||||
is-generator-function "^1.0.7"
|
|
||||||
is-typed-array "^1.1.3"
|
|
||||||
which-typed-array "^1.1.2"
|
|
||||||
|
|
||||||
wcwidth@^1.0.1:
|
wcwidth@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
|
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
|
||||||
@@ -4638,16 +4423,7 @@ wcwidth@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
defaults "^1.0.3"
|
defaults "^1.0.3"
|
||||||
|
|
||||||
web-encoding@1.1.5:
|
web-streams-polyfill@^3.0.3:
|
||||||
version "1.1.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864"
|
|
||||||
integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==
|
|
||||||
dependencies:
|
|
||||||
util "^0.12.3"
|
|
||||||
optionalDependencies:
|
|
||||||
"@zxing/text-encoding" "0.9.0"
|
|
||||||
|
|
||||||
web-streams-polyfill@^3.0.3, web-streams-polyfill@^3.1.1:
|
|
||||||
version "3.3.3"
|
version "3.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
|
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
|
||||||
integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==
|
integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==
|
||||||
@@ -4702,17 +4478,6 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9:
|
|||||||
gopd "^1.0.1"
|
gopd "^1.0.1"
|
||||||
has-tostringtag "^1.0.2"
|
has-tostringtag "^1.0.2"
|
||||||
|
|
||||||
which-typed-array@^1.1.2:
|
|
||||||
version "1.1.16"
|
|
||||||
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.16.tgz#db4db429c4706feca2f01677a144278e4a8c216b"
|
|
||||||
integrity sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==
|
|
||||||
dependencies:
|
|
||||||
available-typed-arrays "^1.0.7"
|
|
||||||
call-bind "^1.0.7"
|
|
||||||
for-each "^0.3.3"
|
|
||||||
gopd "^1.0.1"
|
|
||||||
has-tostringtag "^1.0.2"
|
|
||||||
|
|
||||||
which@^2.0.1:
|
which@^2.0.1:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||||
|
|||||||
Reference in New Issue
Block a user