From cb0f75dfb989cbd372f2a333d830c7b4e464c8c1 Mon Sep 17 00:00:00 2001 From: Izan Gil <66965250+SrIzan10@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:00:19 +0200 Subject: [PATCH] feat: bot accounts (without api stuff) --- .gitignore | 4 +- .prettierrc => .prettierrc.json | 0 apps/web/next.config.mjs | 4 + apps/web/package.json | 4 +- apps/web/sentry.edge.config.ts | 1 + .../api/settings/bot/[slug]/apiKey/route.ts | 124 ++++++ .../settings/bot/[slug]/apikeys.tsx | 214 ++++++++++ .../settings/bot/[slug]/gensettings.tsx | 62 +++ .../(protected)/settings/bot/[slug]/page.tsx | 40 ++ .../(protected)/settings/bot/create/page.tsx | 65 +++ .../(ui)/(protected)/settings/bot/page.tsx | 88 ++++ .../channel/[channelName]/page.client.tsx | 2 +- .../{ => settings/channel}/create/page.tsx | 3 +- apps/web/src/app/(ui)/layout.tsx | 31 +- apps/web/src/app/globals.css | 1 + apps/web/src/components/app/NavBar/NavBar.tsx | 2 +- .../app/UniversalForm/UniversalForm.tsx | 7 +- .../src/components/app/UniversalForm/types.ts | 3 +- apps/web/src/instrumentation-client.ts | 1 + apps/web/src/instrumentation.ts | 4 +- apps/web/src/lib/db/resolve.ts | 13 +- apps/web/src/lib/form/actions.ts | 77 +++- apps/web/src/lib/form/zod.ts | 27 +- .../web/src/lib/providers/ConfirmProvider.tsx | 21 + apps/web/tsconfig.json | 2 +- package.json | 1 + .../migration.sql | 42 ++ .../migration.sql | 22 + .../migration.sql | 9 + .../migration.sql | 43 ++ .../migration.sql | 2 + .../migration.sql | 30 ++ .../migration.sql | 8 + packages/db/prisma/schema.prisma | 115 ++++-- yarn.lock | 385 ++++++++++++++---- 35 files changed, 1311 insertions(+), 146 deletions(-) rename .prettierrc => .prettierrc.json (100%) create mode 100644 apps/web/src/app/(ui)/(protected)/api/settings/bot/[slug]/apiKey/route.ts create mode 100644 apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/apikeys.tsx create mode 100644 apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/gensettings.tsx create mode 100644 apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/page.tsx create mode 100644 apps/web/src/app/(ui)/(protected)/settings/bot/create/page.tsx create mode 100644 apps/web/src/app/(ui)/(protected)/settings/bot/page.tsx rename apps/web/src/app/(ui)/(protected)/{ => settings/channel}/create/page.tsx (95%) create mode 100644 apps/web/src/lib/providers/ConfirmProvider.tsx create mode 100644 packages/db/prisma/migrations/20250909181358_bot_accounts_draft/migration.sql create mode 100644 packages/db/prisma/migrations/20250909210506_bot_accounts_on_user/migration.sql create mode 100644 packages/db/prisma/migrations/20250909223644_some_date_stuff/migration.sql create mode 100644 packages/db/prisma/migrations/20250910214339_make_bot_account_singular/migration.sql create mode 100644 packages/db/prisma/migrations/20250910221833_default_bot_account_desc/migration.sql create mode 100644 packages/db/prisma/migrations/20250929141757_bot_api_key_rename/migration.sql create mode 100644 packages/db/prisma/migrations/20250929141857_bot_api_key_name/migration.sql diff --git a/.gitignore b/.gitignore index 2d16642..952a1c8 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,6 @@ packages/db/generated/client *dist slack-import-emojis/target -**/*/emojis.json \ No newline at end of file +**/*/emojis.json + +.idea \ No newline at end of file diff --git a/.prettierrc b/.prettierrc.json similarity index 100% rename from .prettierrc rename to .prettierrc.json diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 4c2513d..7a888cf 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -33,6 +33,9 @@ const nextConfig = { hostname: 'cdn.jsdelivr.net', pathname: '/npm/emoji-datasource-twitter@15.1.2/img/twitter/64/*', }, + { + hostname: 'eoceqrx2r7.ufs.sh' + }, ], minimumCacheTTL: 120, }, @@ -44,6 +47,7 @@ const nextConfig = { reactStrictMode: false, output: 'standalone', outputFileTracingRoot: path.join(__dirname, '../../'), + serverExternalPackages: ['bullmq'], async rewrites() { return [ { diff --git a/apps/web/package.json b/apps/web/package.json index 9886983..ba9f037 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -20,6 +20,7 @@ "@hookform/resolvers": "^3.9.1", "@lucia-auth/adapter-prisma": "^4.0.1", "@node-rs/argon2": "^2.0.2", + "@omit/react-confirm-dialog": "^1.2.0", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-dialog": "^1.1.5", @@ -46,11 +47,10 @@ "clsx": "^2.1.0", "cmdk": "1.0.0", "hls-video-element": "^1.5.0", - "ioredis": "5.7.0", "lucia": "^3.2.2", "lucide-react": "^0.473.0", "media-chrome": "^4.8.0", - "next": "^15.3.4", + "next": "^15.6.0-canary.34", "next-themes": "^0.4.4", "node-cron": "^3.0.3", "nuqs": "^2.4.3", diff --git a/apps/web/sentry.edge.config.ts b/apps/web/sentry.edge.config.ts index fe679ab..ecdd868 100644 --- a/apps/web/sentry.edge.config.ts +++ b/apps/web/sentry.edge.config.ts @@ -16,4 +16,5 @@ Sentry.init({ // Setting this option to true will print useful information to the console while you're setting up Sentry. debug: false, + enabled: process.env.NODE_ENV === 'production', }); diff --git a/apps/web/src/app/(ui)/(protected)/api/settings/bot/[slug]/apiKey/route.ts b/apps/web/src/app/(ui)/(protected)/api/settings/bot/[slug]/apiKey/route.ts new file mode 100644 index 0000000..dd390e0 --- /dev/null +++ b/apps/web/src/app/(ui)/(protected)/api/settings/bot/[slug]/apiKey/route.ts @@ -0,0 +1,124 @@ +import { validateRequest } from "@/lib/auth/validate"; +import { prisma } from "@hctv/db"; +import { NextRequest } from "next/server"; +import { z } from "zod"; + +type Params = Promise<{ slug: string }>; + +export async function POST(request: NextRequest, segmentData: { params: Params }) { + const { slug } = await segmentData.params; + const { user } = await validateRequest(); + if (!user) { + return new Response(JSON.stringify({ success: false, error: 'Unauthorized' }), { status: 401 }); + } + + const bodySchema = z.object({ + action: z.enum(['revoke', 'regenerate', 'create']), + name: z.string().min(3, 'Name must be at least 3 characters long').max(50, 'Name must be at most 50 characters long'), + }); + const body = await request.json(); + const parsedBody = bodySchema.safeParse(body); + if (!parsedBody.success) { + return new Response(JSON.stringify({ success: false, error: parsedBody.error.errors.map(e => e.message).join(', ') }), { status: 400 }); + } + + const { action, name } = parsedBody.data; + + if (action === 'create') { + const exists = await prisma.botApiKey.findFirst({ + where: { + name, + botAccount: { + ownerId: user.id, + slug, + } + } + }); + if (exists) { + return new Response(JSON.stringify({ success: false, error: 'API Key with this name already exists' }), { status: 400 }); + } + const newKey = await prisma.botApiKey.create({ + data: { + name, + botAccount: { + connect: { + ownerId: user.id, + slug, + } + }, + key: generateApiKey(), + } + }); + return new Response(JSON.stringify({ success: true, apiKey: newKey.key, id: newKey.id })); + } + if (action === 'regenerate') { + const existingKey = await prisma.botApiKey.findFirst({ + where: { + name, + botAccount: { + ownerId: user.id, + slug, + } + } + }); + if (!existingKey) { + return new Response(JSON.stringify({ success: false, error: 'API Key not found' }), { status: 404 }); + } + const newKey = generateApiKey(); + await prisma.botApiKey.update({ + where: { id: existingKey.id }, + data: { key: newKey }, + }); + return new Response(JSON.stringify({ success: true, apiKey: newKey, id: existingKey.id })); + } + if (action === 'revoke') { + const existingKey = await prisma.botApiKey.findFirst({ + where: { + name, + botAccount: { + ownerId: user.id, + slug, + } + } + }); + if (!existingKey) { + return new Response(JSON.stringify({ success: false, error: 'API Key not found' }), { status: 404 }); + } + await prisma.botApiKey.delete({ + where: { id: existingKey.id }, + }); + return new Response(JSON.stringify({ success: true })); + } + return new Response(JSON.stringify({ success: false, error: 'Invalid action' }), { status: 400 }); +} + +export async function GET(request: NextRequest, segmentData: { params: Params }) { + const { slug } = await segmentData.params; + const { user } = await validateRequest(); + if (!user) { + return new Response(JSON.stringify({ success: false, error: 'Unauthorized' }), { status: 401 }); + } + + const apiKeys = await prisma.botApiKey.findMany({ + where: { + botAccount: { + ownerId: user.id, + slug, + } + }, + select: { + id: true, + name: true, + createdAt: true, + }, + orderBy: { + createdAt: 'desc', + } + }); + return new Response(JSON.stringify({ success: true, apiKeys })); +} + +function generateApiKey() { + const uuid = crypto.randomUUID().replace(/-/g, ''); + return `hctvb_${uuid}`; +} \ No newline at end of file diff --git a/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/apikeys.tsx b/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/apikeys.tsx new file mode 100644 index 0000000..40a7a67 --- /dev/null +++ b/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/apikeys.tsx @@ -0,0 +1,214 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { Input } from '@/components/ui/input'; +import { Skeleton } from '@/components/ui/skeleton'; +import { fetcher } from '@/lib/services/swr'; +import { useConfirm } from '@omit/react-confirm-dialog'; +import { Plus, RefreshCcw, Trash } from 'lucide-react'; +import { useState } from 'react'; +import { toast } from 'sonner'; +import useSWR from 'swr'; +import useSWRMutation from 'swr/mutation'; + +export function ApiKeys({ slug }: { slug: string }) { + const confirm = useConfirm(); + const [newApiKeyName, setNewApiKeyName] = useState(''); + const { data, error, isLoading, mutate } = useSWR( + `/api/settings/bot/${slug}/apiKey`, + fetcher + ); + const { trigger } = useSWRMutation(`/api/settings/bot/${slug}/apiKey`, createApiKey); + + return ( + + + API Keys + Manage your API keys + + + {isLoading && } + {error &&

Error loading API keys

} + {data && !data.success &&

Error: Could not fetch API keys

} + {data && ( +
+ setNewApiKeyName(e.target.value)} + /> + +
+ )} + {data && data.success && data.apiKeys.length === 0 &&

No API keys found

} + {data && data.success && data.apiKeys.length > 0 && ( +
    + {data.apiKeys.map((key) => ( +
  • +
    + {key.name} +
    +
    + + +
    +
  • + ))} +
+ )} +
+
+ ); +} + +function ApiKeysSkeleton() { + return ( + <> +
+ + +
+
+ {[1, 2, 3].map((i) => ( +
+
+ +
+
+ + +
+
+ ))} +
+ + ) +} + +async function createApiKey(url: string, { arg }: { arg: PostRequest }) { + const res = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(arg), + }); + return res.json(); +} + +interface GetResponse { + success: boolean; + apiKeys: Array<{ id: string; name: string; createdAt: string }>; +} + +interface PostRequest { + action: 'revoke' | 'regenerate' | 'create'; + name: string; +} +interface PostResponse { + success: boolean; + apiKey?: string; + id?: string; + error?: string; +} diff --git a/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/gensettings.tsx b/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/gensettings.tsx new file mode 100644 index 0000000..fb0d1bf --- /dev/null +++ b/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/gensettings.tsx @@ -0,0 +1,62 @@ +'use client'; +import { UniversalForm } from '@/components/app/UniversalForm/UniversalForm'; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { editBot } from '@/lib/form/actions'; +import { BotAccount } from '@hctv/db'; +import { useRouter } from 'next/navigation'; + +export function GeneralSettings(props: BotAccount) { + const router = useRouter(); + return ( + + + General Settings + Edit your bot settings! + + + + + + ) +} \ No newline at end of file diff --git a/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/page.tsx b/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/page.tsx new file mode 100644 index 0000000..eaaef45 --- /dev/null +++ b/apps/web/src/app/(ui)/(protected)/settings/bot/[slug]/page.tsx @@ -0,0 +1,40 @@ +import { getBotBySlug } from '@/lib/db/resolve'; +import { validateRequest } from '@/lib/auth/validate'; +import { redirect } from 'next/navigation'; +import Image from 'next/image'; +import { GeneralSettings } from '@/app/(ui)/(protected)/settings/bot/[slug]/gensettings'; +import { ApiKeys } from '@/app/(ui)/(protected)/settings/bot/[slug]/apikeys'; + +export default async function Page({ params }: { params: Promise<{ slug: string }> }) { + const { user } = await validateRequest(); + const { slug } = await params; + const bot = await getBotBySlug(slug); + + if (!bot || bot.ownerId !== user?.id) { + redirect('/settings/bot'); + } + + return ( +
+
+
+ {'Bot +
+

{bot.displayName}

+

Manage your bot account settings

+
+
+
+
+ + +
+
+ ); +} diff --git a/apps/web/src/app/(ui)/(protected)/settings/bot/create/page.tsx b/apps/web/src/app/(ui)/(protected)/settings/bot/create/page.tsx new file mode 100644 index 0000000..e3e4fd9 --- /dev/null +++ b/apps/web/src/app/(ui)/(protected)/settings/bot/create/page.tsx @@ -0,0 +1,65 @@ +'use client'; + +import { UniversalForm } from '@/components/app/UniversalForm/UniversalForm'; +import { createBot } from '@/lib/form/actions'; +import { Bot } from 'lucide-react'; +import { useRouter } from 'next/navigation'; + +export default function Page() { + const router = useRouter(); + + return ( +
+
+
+
+ +
+

Create Bot Account

+

+ Create an automated bot account to provide custom functionality for your community. +

+
+ +
+ { + router.push(`/settings/bot/${res.slug}`); + }} + /> +
+ + {/* +

+ Your bot will be created with chat permissions. You can configure advanced settings and + permissions after creation. +

+ */} +
+
+ ); +} diff --git a/apps/web/src/app/(ui)/(protected)/settings/bot/page.tsx b/apps/web/src/app/(ui)/(protected)/settings/bot/page.tsx new file mode 100644 index 0000000..3e64d00 --- /dev/null +++ b/apps/web/src/app/(ui)/(protected)/settings/bot/page.tsx @@ -0,0 +1,88 @@ +import { validateRequest } from '@/lib/auth/validate'; +import { prisma } from '@hctv/db'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; +import { Separator } from '@/components/ui/separator'; +import Link from 'next/link'; +import { Plus, Bot, Calendar, Hash } from 'lucide-react'; +import { redirect } from 'next/navigation'; +import Image from 'next/image'; + +export default async function Page() { + const { user } = await validateRequest(); + if (!user) { + redirect('/'); + } + + const bots = await prisma.user.findFirst({ + where: { id: user.id }, + select: { + botAccounts: true, + }, + }); + + return ( +
+
+
+

Bot Accounts

+

Manage your automated bot accounts

+
+ + + +
+ + + + {bots?.botAccounts.length ? ( +
+ {bots.botAccounts.map((bot) => ( + + + +
+ {'Bot + {bot.displayName} +
+
+ +
+ + {bot.slug} +
+
+ + {new Date(bot.createdAt).toLocaleDateString()} +
+
+
+ + ))} +
+ ) : ( + + + +
+ No bot accounts yet + + Get started by creating your first bot account + +
+ + + +
+
+ )} +
+ ); +} diff --git a/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx b/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx index a42536b..dc8d9a4 100644 --- a/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx +++ b/apps/web/src/app/(ui)/(protected)/settings/channel/[channelName]/page.client.tsx @@ -150,7 +150,7 @@ export default function ChannelSettingsClient({ value={channel.name} onSelect={(value) => { if (value === 'create') { - router.push(`/create`); + router.push(`/settings/channel/create`); } else { router.push(`/settings/channel/${value}?tab=${selTab}`); } diff --git a/apps/web/src/app/(ui)/(protected)/create/page.tsx b/apps/web/src/app/(ui)/(protected)/settings/channel/create/page.tsx similarity index 95% rename from apps/web/src/app/(ui)/(protected)/create/page.tsx rename to apps/web/src/app/(ui)/(protected)/settings/channel/create/page.tsx index 562b8c1..2f22ce7 100644 --- a/apps/web/src/app/(ui)/(protected)/create/page.tsx +++ b/apps/web/src/app/(ui)/(protected)/settings/channel/create/page.tsx @@ -32,8 +32,7 @@ function CreateChannelPage() { schemaName="createChannel" action={createChannel} onActionComplete={(r) => { - // @ts-expect-error - const channelName = r?.channel; + const channelName = r.channel; if (channelName) { router.push(`/${channelName}`); } diff --git a/apps/web/src/app/(ui)/layout.tsx b/apps/web/src/app/(ui)/layout.tsx index 9bb17e8..73f15de 100644 --- a/apps/web/src/app/(ui)/layout.tsx +++ b/apps/web/src/app/(ui)/layout.tsx @@ -16,6 +16,7 @@ import { extractRouterConfig } from 'uploadthing/server'; import { ourFileRouter } from '@/lib/services/uploadthing/fileRouter'; import { NuqsAdapter } from 'nuqs/adapters/next/app' import SonnerNewVersion from '@/components/app/SonnerNewVersion/SonnerNewVersion'; +import ConfirmDialogProvider from '@/lib/providers/ConfirmProvider'; const inter = Inter({ subsets: ['latin'] }); @@ -44,20 +45,22 @@ export default async function RootLayout({ - - - - {/* this promise is ugly but i'm lazy to fix the type errors */} - )} /> -
- {/* pt-16 for navbar height */} - -
{children}
-
- -
-
-
+ + + + + {/* this promise is ugly but i'm lazy to fix the type errors */} + )} /> +
+ {/* pt-16 for navbar height */} + +
{children}
+
+ +
+
+
+
diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 2ad5b36..7251b01 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -119,6 +119,7 @@ body { @apply bg-background text-foreground; } + .scrollbar-hide::-webkit-scrollbar { display: none; } .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } } diff --git a/apps/web/src/components/app/NavBar/NavBar.tsx b/apps/web/src/components/app/NavBar/NavBar.tsx index 8b9325c..aa8c332 100644 --- a/apps/web/src/components/app/NavBar/NavBar.tsx +++ b/apps/web/src/components/app/NavBar/NavBar.tsx @@ -51,7 +51,7 @@ export default function Navbar(props: Props) { Follows - + Create channel diff --git a/apps/web/src/components/app/UniversalForm/UniversalForm.tsx b/apps/web/src/components/app/UniversalForm/UniversalForm.tsx index e01230f..6e5bb7d 100644 --- a/apps/web/src/components/app/UniversalForm/UniversalForm.tsx +++ b/apps/web/src/components/app/UniversalForm/UniversalForm.tsx @@ -19,13 +19,18 @@ import React from 'react'; import { toast } from 'sonner'; import { Textarea } from '@/components/ui/textarea'; import { cn } from '@/lib/utils'; -import { createChannelSchema, onboardSchema, streamInfoEditSchema, updateChannelSettingsSchema } from '@/lib/form/zod'; +import { + createBotSchema, + createChannelSchema, editBotSchema, onboardSchema, streamInfoEditSchema, updateChannelSettingsSchema +} from '@/lib/form/zod'; export const schemaDb = [ { name: 'streamInfoEdit', zod: streamInfoEditSchema }, { name: 'onboard', zod: onboardSchema }, { name: 'createChannel', zod: createChannelSchema }, { name: 'updateChannelSettings', zod: updateChannelSettingsSchema }, + { name: 'createBot', zod: createBotSchema }, + { name: 'editBot', zod: editBotSchema } ] as const; export function UniversalForm({ diff --git a/apps/web/src/components/app/UniversalForm/types.ts b/apps/web/src/components/app/UniversalForm/types.ts index 5bafbf0..b547072 100644 --- a/apps/web/src/components/app/UniversalForm/types.ts +++ b/apps/web/src/components/app/UniversalForm/types.ts @@ -14,13 +14,14 @@ export type FormFieldConfig = { textAreaRows?: number; component?: (props: { field: ControllerRenderProps } & any) => React.ReactNode; componentProps?: Record; + required?: boolean; }; export type UniversalFormProps = { fields: FormFieldConfig[]; schemaName: (typeof schemaDb)[number]['name']; action: (prev: any, formData: FormData) => void; - onActionComplete?: (result: unknown) => void; + onActionComplete?: (result: any) => void; defaultValues?: Partial>; submitText?: string; submitClassname?: string; diff --git a/apps/web/src/instrumentation-client.ts b/apps/web/src/instrumentation-client.ts index 4473b78..778a685 100644 --- a/apps/web/src/instrumentation-client.ts +++ b/apps/web/src/instrumentation-client.ts @@ -14,6 +14,7 @@ Sentry.init({ // Setting this option to true will print useful information to the console while you're setting up Sentry. debug: false, + enabled: process.env.NODE_ENV === 'production' }); export const onRouterTransitionStart = Sentry.captureRouterTransitionStart; \ No newline at end of file diff --git a/apps/web/src/instrumentation.ts b/apps/web/src/instrumentation.ts index ffb9990..9ee3a20 100644 --- a/apps/web/src/instrumentation.ts +++ b/apps/web/src/instrumentation.ts @@ -44,8 +44,8 @@ export async function register() { await viewerCountSync(); }, 2000); } - - Sentry.init({ + + process.env.NODE_ENV === 'production' && Sentry.init({ dsn: "https://f3c26671c39af48406c6e23702a4f3dd@o4506961023860736.ingest.us.sentry.io/4509895816773632", // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control. diff --git a/apps/web/src/lib/db/resolve.ts b/apps/web/src/lib/db/resolve.ts index b285b71..16ef871 100644 --- a/apps/web/src/lib/db/resolve.ts +++ b/apps/web/src/lib/db/resolve.ts @@ -1,4 +1,5 @@ -import { prisma } from '@hctv/db'; +import {Prisma, prisma} from '@hctv/db'; +import {validateRequest} from "@/lib/auth/validate"; export async function resolveChannelNameId(channelName: string) { const channel = await prisma.channel.findUnique({ @@ -28,4 +29,14 @@ export async function resolveUserPersonalChannel(userId: string) { } return channel; +} + +export async function getBotBySlug(slug: string) { + const bot = await prisma.botAccount.findFirst({ + where: { + slug, + }, + }); + + return bot; } \ No newline at end of file diff --git a/apps/web/src/lib/form/actions.ts b/apps/web/src/lib/form/actions.ts index 3bcde2b..c15acde 100644 --- a/apps/web/src/lib/form/actions.ts +++ b/apps/web/src/lib/form/actions.ts @@ -4,7 +4,10 @@ import { revalidatePath } from 'next/cache'; import { validateRequest } from '@/lib/auth/validate'; import { prisma } from '@hctv/db'; import zodVerify from '../zodVerify'; -import { createChannelSchema, onboardSchema, streamInfoEditSchema, updateChannelSettingsSchema } from './zod'; +import { + createBotSchema, + createChannelSchema, editBotSchema, onboardSchema, streamInfoEditSchema, updateChannelSettingsSchema +} from './zod'; import { initializeStreamInfo } from '../instrumentation/streamInfo'; import { resolveFollowedChannels, resolveStreamInfo, resolveUserFromPersonalChannelName } from '../auth/resolve'; import { genIdenticonUpload } from '../utils/genIdenticonUpload'; @@ -353,4 +356,76 @@ export async function deleteChannel(channelId: string) { }); return { success: true }; */ +} + +export async function createBot(prev: any, formData: FormData) { + const { user } = await validateRequest(); + if (!user) { + return { success: false, error: 'Unauthorized' }; + } + const zod = await zodVerify(createBotSchema, formData); + if (!zod.success) { + return zod; + } + + const botExists = await prisma.botAccount.findFirst({ + where: { slug: zod.data.slug }, + }); + if (botExists) { + return { success: false, error: 'Bot slug already exists' }; + } + + const createdBot = await prisma.botAccount.create({ + data: { + displayName: zod.data.name, + slug: zod.data.slug, + ownerId: user.id, + description: zod.data.description, + pfpUrl: await genIdenticonUpload(zod.data.slug, 'botpfp'), + } + }); + + return { success: true, slug: createdBot.slug } +} + +export async function editBot(prev: any, formData: FormData) { + const { user } = await validateRequest(); + if (!user) { + return { success: false, error: 'Unauthorized' }; + } + const zod = await zodVerify(editBotSchema, formData); + if (!zod.success) { + return zod; + } + + const bot = await prisma.botAccount.findUnique({ + where: { id: zod.data.from }, + }); + if (!bot) { + return { success: false, error: 'Bot not found' }; + } + if (bot.ownerId !== user.id) { + return { success: false, error: 'Unauthorized' }; + } + if (bot.slug !== zod.data.slug) { + const botExists = await prisma.botAccount.findFirst({ + where: { slug: zod.data.slug }, + }); + if (botExists) { + return { success: false, error: 'Bot slug already exists' }; + } + } + + const updatedBot = await prisma.botAccount.update({ + where: { id: zod.data.from }, + data: { + displayName: zod.data.name, + slug: zod.data.slug, + description: zod.data.description, + } + }); + + revalidatePath(`/settings/bot/${updatedBot.slug}`); + + return { success: true, slug: updatedBot.slug } } \ No newline at end of file diff --git a/apps/web/src/lib/form/zod.ts b/apps/web/src/lib/form/zod.ts index 548ff9e..21e09ca 100644 --- a/apps/web/src/lib/form/zod.ts +++ b/apps/web/src/lib/form/zod.ts @@ -1,9 +1,20 @@ import { z } from 'zod'; +const disallowedUsernames = [ + 'admin', + 'administrator', + 'settings', + 'create', + // i hope this doesn't age well tbh + 'zrl', +]; const username = z .string() .min(1) - .regex(/^[a-z0-9_-]+$/, { message: 'Only characters from a-z, 0-9, underscores and dashes' }); + .regex(/^[a-z0-9_-]+$/, { message: 'Only characters from a-z, 0-9, underscores and dashes' }) + .refine((val) => !disallowedUsernames.includes(val.toLowerCase()), { + message: 'This username is reserved', + }); export const streamInfoEditSchema = z.object({ username: z.string().min(1), @@ -25,4 +36,16 @@ export const updateChannelSettingsSchema = z.object({ pfpUrl: z.string(), description: z.string().min(1).max(500), is247: z.boolean(), -}); \ No newline at end of file +}); + +export const createBotSchema = z.object({ + name: z.string().min(1, { message: 'Name is required' }), + slug: username.refine((val) => val !== 'settings', { message: 'This slug is reserved' }), + description: z.string().max(300).optional(), +}); + +export const editBotSchema = createBotSchema.and( + z.object({ + from: z.string().min(1), + }) +); diff --git a/apps/web/src/lib/providers/ConfirmProvider.tsx b/apps/web/src/lib/providers/ConfirmProvider.tsx new file mode 100644 index 0000000..7a2e882 --- /dev/null +++ b/apps/web/src/lib/providers/ConfirmProvider.tsx @@ -0,0 +1,21 @@ +'use client'; + +import { + ConfirmDialogProvider as BaseConfirmDialogProvider, + ConfirmOptions, +} from '@omit/react-confirm-dialog'; + +interface Props { + children: React.ReactNode; + defaultOptions?: ConfirmOptions; +} + +export const ConfirmDialogProvider = ({ children, defaultOptions }: Props) => { + return ( + + {children} + + ); +}; + +export default ConfirmDialogProvider; diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index f48e7ee..4b6b903 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -14,7 +14,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { diff --git a/package.json b/package.json index 662cd0e..4e88f2f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "r:rtmp": "docker compose -f dev/docker-compose.yml restart nginx-rtmp -t 0" }, "devDependencies": { + "prettier": "^3.6.2", "turbo": "^2.4.4" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" diff --git a/packages/db/prisma/migrations/20250909181358_bot_accounts_draft/migration.sql b/packages/db/prisma/migrations/20250909181358_bot_accounts_draft/migration.sql new file mode 100644 index 0000000..f29f734 --- /dev/null +++ b/packages/db/prisma/migrations/20250909181358_bot_accounts_draft/migration.sql @@ -0,0 +1,42 @@ +-- CreateTable +CREATE TABLE "BotAccounts" ( + "id" TEXT NOT NULL, + "displayName" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "description" TEXT NOT NULL, + "pfpUrl" TEXT NOT NULL, + "channelId" TEXT NOT NULL, + + CONSTRAINT "BotAccounts_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ApiKey" ( + "id" TEXT NOT NULL, + "key" TEXT NOT NULL, + "botAccountId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "ApiKey_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "BotAccounts_slug_key" ON "BotAccounts"("slug"); + +-- CreateIndex +CREATE INDEX "BotAccounts_channelId_idx" ON "BotAccounts"("channelId"); + +-- CreateIndex +CREATE INDEX "BotAccounts_slug_idx" ON "BotAccounts"("slug"); + +-- CreateIndex +CREATE UNIQUE INDEX "ApiKey_key_key" ON "ApiKey"("key"); + +-- CreateIndex +CREATE INDEX "ApiKey_botAccountId_idx" ON "ApiKey"("botAccountId"); + +-- AddForeignKey +ALTER TABLE "BotAccounts" ADD CONSTRAINT "BotAccounts_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "Channel"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_botAccountId_fkey" FOREIGN KEY ("botAccountId") REFERENCES "BotAccounts"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/db/prisma/migrations/20250909210506_bot_accounts_on_user/migration.sql b/packages/db/prisma/migrations/20250909210506_bot_accounts_on_user/migration.sql new file mode 100644 index 0000000..689f80f --- /dev/null +++ b/packages/db/prisma/migrations/20250909210506_bot_accounts_on_user/migration.sql @@ -0,0 +1,22 @@ +/* + Warnings: + + - You are about to drop the column `channelId` on the `BotAccounts` table. All the data in the column will be lost. + - Added the required column `ownerId` to the `BotAccounts` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE "BotAccounts" DROP CONSTRAINT "BotAccounts_channelId_fkey"; + +-- DropIndex +DROP INDEX "BotAccounts_channelId_idx"; + +-- AlterTable +ALTER TABLE "BotAccounts" DROP COLUMN "channelId", +ADD COLUMN "ownerId" TEXT NOT NULL; + +-- CreateIndex +CREATE INDEX "BotAccounts_ownerId_idx" ON "BotAccounts"("ownerId"); + +-- AddForeignKey +ALTER TABLE "BotAccounts" ADD CONSTRAINT "BotAccounts_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/packages/db/prisma/migrations/20250909223644_some_date_stuff/migration.sql b/packages/db/prisma/migrations/20250909223644_some_date_stuff/migration.sql new file mode 100644 index 0000000..74f3900 --- /dev/null +++ b/packages/db/prisma/migrations/20250909223644_some_date_stuff/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - Added the required column `updatedAt` to the `BotAccounts` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "BotAccounts" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL; diff --git a/packages/db/prisma/migrations/20250910214339_make_bot_account_singular/migration.sql b/packages/db/prisma/migrations/20250910214339_make_bot_account_singular/migration.sql new file mode 100644 index 0000000..a009417 --- /dev/null +++ b/packages/db/prisma/migrations/20250910214339_make_bot_account_singular/migration.sql @@ -0,0 +1,43 @@ +/* + Warnings: + + - You are about to drop the `BotAccounts` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "ApiKey" DROP CONSTRAINT "ApiKey_botAccountId_fkey"; + +-- DropForeignKey +ALTER TABLE "BotAccounts" DROP CONSTRAINT "BotAccounts_ownerId_fkey"; + +-- DropTable +DROP TABLE "BotAccounts"; + +-- CreateTable +CREATE TABLE "BotAccount" ( + "id" TEXT NOT NULL, + "displayName" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "description" TEXT NOT NULL, + "pfpUrl" TEXT NOT NULL, + "ownerId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "BotAccount_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "BotAccount_slug_key" ON "BotAccount"("slug"); + +-- CreateIndex +CREATE INDEX "BotAccount_ownerId_idx" ON "BotAccount"("ownerId"); + +-- CreateIndex +CREATE INDEX "BotAccount_slug_idx" ON "BotAccount"("slug"); + +-- AddForeignKey +ALTER TABLE "BotAccount" ADD CONSTRAINT "BotAccount_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_botAccountId_fkey" FOREIGN KEY ("botAccountId") REFERENCES "BotAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/db/prisma/migrations/20250910221833_default_bot_account_desc/migration.sql b/packages/db/prisma/migrations/20250910221833_default_bot_account_desc/migration.sql new file mode 100644 index 0000000..5236e31 --- /dev/null +++ b/packages/db/prisma/migrations/20250910221833_default_bot_account_desc/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "BotAccount" ALTER COLUMN "description" SET DEFAULT 'A hctv bot account'; diff --git a/packages/db/prisma/migrations/20250929141757_bot_api_key_rename/migration.sql b/packages/db/prisma/migrations/20250929141757_bot_api_key_rename/migration.sql new file mode 100644 index 0000000..ab9ee36 --- /dev/null +++ b/packages/db/prisma/migrations/20250929141757_bot_api_key_rename/migration.sql @@ -0,0 +1,30 @@ +/* + Warnings: + + - You are about to drop the `ApiKey` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "ApiKey" DROP CONSTRAINT "ApiKey_botAccountId_fkey"; + +-- DropTable +DROP TABLE "ApiKey"; + +-- CreateTable +CREATE TABLE "BotApiKey" ( + "id" TEXT NOT NULL, + "key" TEXT NOT NULL, + "botAccountId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BotApiKey_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "BotApiKey_key_key" ON "BotApiKey"("key"); + +-- CreateIndex +CREATE INDEX "BotApiKey_botAccountId_idx" ON "BotApiKey"("botAccountId"); + +-- AddForeignKey +ALTER TABLE "BotApiKey" ADD CONSTRAINT "BotApiKey_botAccountId_fkey" FOREIGN KEY ("botAccountId") REFERENCES "BotAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/db/prisma/migrations/20250929141857_bot_api_key_name/migration.sql b/packages/db/prisma/migrations/20250929141857_bot_api_key_name/migration.sql new file mode 100644 index 0000000..3e849c2 --- /dev/null +++ b/packages/db/prisma/migrations/20250929141857_bot_api_key_name/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `name` to the `BotApiKey` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "BotApiKey" ADD COLUMN "name" TEXT NOT NULL; diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index 7d0dc23..7538fd4 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -5,55 +5,56 @@ // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init generator client { - provider = "prisma-client-js" - output = "../generated/client" + provider = "prisma-client-js" + output = "../generated/client" binaryTargets = ["native", "linux-musl-openssl-3.0.x"] } datasource db { - provider = "postgresql" - url = env("DATABASE_URL") + provider = "postgresql" + url = env("DATABASE_URL") directUrl = env("DATABASE_DIRECT_URL") } model User { - id String @id @default(cuid()) - slack_id String - pfpUrl String - hasOnboarded Boolean @default(false) + id String @id @default(cuid()) + slack_id String + pfpUrl String + hasOnboarded Boolean @default(false) - personalChannel Channel? @relation("PersonalChannel", fields: [personalChannelId], references: [id]) - personalChannelId String? @unique + personalChannel Channel? @relation("PersonalChannel", fields: [personalChannelId], references: [id]) + personalChannelId String? @unique - ownedChannels Channel[] @relation("ChannelOwner") - managedChannels Channel[] @relation("ChannelManagers") - sessions Session[] - streams StreamInfo[] - followers Follow[] @relation("UserFollows") + ownedChannels Channel[] @relation("ChannelOwner") + managedChannels Channel[] @relation("ChannelManagers") + sessions Session[] + streams StreamInfo[] + followers Follow[] @relation("UserFollows") + botAccounts BotAccount[] @@index([personalChannelId]) } model Channel { - id String @id @default(cuid()) - name String @unique + id String @id @default(cuid()) + name String @unique description String @default("A hctv channel") - pfpUrl String + pfpUrl String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt personalFor User? @relation("PersonalChannel") - owner User @relation("ChannelOwner", fields: [ownerId], references: [id]) - ownerId String - managers User[] @relation("ChannelManagers") - streamInfo StreamInfo[] - followers Follow[] @relation("ChannelFollowers") - streamKey StreamKey? - obsChatGrantToken String @unique @default(cuid()) - is247 Boolean @default(false) - + owner User @relation("ChannelOwner", fields: [ownerId], references: [id]) + ownerId String + managers User[] @relation("ChannelManagers") + streamInfo StreamInfo[] + followers Follow[] @relation("ChannelFollowers") + streamKey StreamKey? + obsChatGrantToken String @unique @default(cuid()) + is247 Boolean @default(false) + @@index([ownerId]) } @@ -65,20 +66,20 @@ model Session { } model StreamInfo { - id String @id @default(cuid()) - username String @unique + id String @id @default(cuid()) + username String @unique title String thumbnail String viewers Int category String startedAt DateTime isLive Boolean - + channelId String channel Channel @relation(fields: [channelId], references: [id]) - ownedBy User @relation(fields: [userId], references: [id]) - userId String + ownedBy User @relation(fields: [userId], references: [id]) + userId String enableNotifications Boolean @default(true) @@ -88,13 +89,13 @@ model StreamInfo { model Follow { id String @id @default(cuid()) createdAt DateTime @default(now()) - - user User @relation("UserFollows", fields: [userId], references: [id], onDelete: Cascade) - userId String - - channel Channel @relation("ChannelFollowers", fields: [channelId], references: [id], onDelete: Cascade) + + user User @relation("UserFollows", fields: [userId], references: [id], onDelete: Cascade) + userId String + + channel Channel @relation("ChannelFollowers", fields: [channelId], references: [id], onDelete: Cascade) channelId String - + notifyStream Boolean @default(false) @@unique([userId, channelId]) @@ -103,9 +104,37 @@ model Follow { } model StreamKey { - id String @id @default(cuid()) - key String @unique + id String @id @default(cuid()) + key String @unique - channelId String @unique - channel Channel @relation(fields: [channelId], references: [id]) -} \ No newline at end of file + channelId String @unique + channel Channel @relation(fields: [channelId], references: [id]) +} + +model BotAccount { + id String @id @default(cuid()) + displayName String + slug String @unique + description String @default("A hctv bot account") + pfpUrl String + owner User @relation(fields: [ownerId], references: [id]) + ownerId String + apiKeys BotApiKey[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([ownerId]) + @@index([slug]) +} + +model BotApiKey { + id String @id @default(cuid()) + name String + key String @unique + botAccount BotAccount @relation(fields: [botAccountId], references: [id], onDelete: Cascade) + botAccountId String + createdAt DateTime @default(now()) + + @@index([botAccountId]) +} diff --git a/yarn.lock b/yarn.lock index 895712f..4125301 100644 --- a/yarn.lock +++ b/yarn.lock @@ -747,7 +747,7 @@ "@emnapi/wasi-threads" "1.0.1" tslib "^2.4.0" -"@emnapi/runtime@^1.2.0", "@emnapi/runtime@^1.4.4": +"@emnapi/runtime@^1.2.0", "@emnapi/runtime@^1.4.4", "@emnapi/runtime@^1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.5.0.tgz#9aebfcb9b17195dce3ab53c86787a6b7d058db73" integrity sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ== @@ -1130,6 +1130,11 @@ local-pkg "^1.0.0" mlly "^1.7.4" +"@img/colour@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.0.0.tgz#d2fabb223455a793bf3bf9c70de3d28526aa8311" + integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== + "@img/sharp-darwin-arm64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08" @@ -1151,6 +1156,13 @@ optionalDependencies: "@img/sharp-libvips-darwin-arm64" "1.2.0" +"@img/sharp-darwin-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz#8a0dcac9e621ff533fbf2e830f6a977b38d67a0c" + integrity sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.3" + "@img/sharp-darwin-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61" @@ -1172,6 +1184,13 @@ optionalDependencies: "@img/sharp-libvips-darwin-x64" "1.2.0" +"@img/sharp-darwin-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz#0ba2bd9dbf07f7300fab73305b787e66156f7752" + integrity sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.3" + "@img/sharp-libvips-darwin-arm64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f" @@ -1187,6 +1206,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz#e20e9041031acde1de19da121dc5162c7d2cf251" integrity sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ== +"@img/sharp-libvips-darwin-arm64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz#f43c9aa3b74fd307e4318da63ebbe0ed4c34e744" + integrity sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw== + "@img/sharp-libvips-darwin-x64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062" @@ -1202,6 +1226,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz#918ca81c5446f31114834cb908425a7532393185" integrity sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg== +"@img/sharp-libvips-darwin-x64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz#c42ff786d4a1f42ef8929dba4a989dd5df6417f0" + integrity sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA== + "@img/sharp-libvips-linux-arm64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704" @@ -1217,6 +1246,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz#1a5beafc857b43f378c3030427aa981ee3edbc54" integrity sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA== +"@img/sharp-libvips-linux-arm64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz#c9073e5c4b629ee417f777db21c552910d84ed77" + integrity sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ== + "@img/sharp-libvips-linux-arm@1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197" @@ -1232,6 +1266,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz#bff51182d5238ca35c5fe9e9f594a18ad6a5480d" integrity sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw== +"@img/sharp-libvips-linux-arm@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz#3cbc333fd6b8f224a14d69b03a1dd11df897c799" + integrity sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA== + "@img/sharp-libvips-linux-ppc64@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz#682334595f2ca00e0a07a675ba170af165162802" @@ -1242,6 +1281,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz#10c53ccf6f2d47d71fb3fa282697072c8fe9e40e" integrity sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ== +"@img/sharp-libvips-linux-ppc64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz#68e0e0076299f43d838468675674fabcc7161d16" + integrity sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg== + "@img/sharp-libvips-linux-s390x@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce" @@ -1257,6 +1301,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz#392fd7557ddc5c901f1bed7ab3c567c08833ef3b" integrity sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw== +"@img/sharp-libvips-linux-s390x@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz#7da9ab11a50c0ca905979f0aae14a4ccffab27b2" + integrity sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w== + "@img/sharp-libvips-linux-x64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0" @@ -1272,6 +1321,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz#9315cf90a2fdcdc0e29ea7663cbd8b0f15254400" integrity sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg== +"@img/sharp-libvips-linux-x64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz#3b162d6b190cf77926819040e09fb15eec42135e" + integrity sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg== + "@img/sharp-libvips-linuxmusl-arm64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5" @@ -1287,6 +1341,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz#705e03e67d477f6f842f37eb7f66285b1150dc06" integrity sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q== +"@img/sharp-libvips-linuxmusl-arm64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz#ac99576630dd8e33cb598d7c4586f6e0655912ea" + integrity sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw== + "@img/sharp-libvips-linuxmusl-x64@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff" @@ -1302,6 +1361,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz#ec905071cc538df64848d5900e0d386d77c55f13" integrity sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q== +"@img/sharp-libvips-linuxmusl-x64@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz#93e9495af7bf6c4e0d41dd71d0196c35c3753a1c" + integrity sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g== + "@img/sharp-linux-arm64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22" @@ -1323,6 +1387,13 @@ optionalDependencies: "@img/sharp-libvips-linux-arm64" "1.2.0" +"@img/sharp-linux-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz#0570ff1a4fa6e1d6779456fca8b5e8c18a6a9cf2" + integrity sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.3" + "@img/sharp-linux-arm@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff" @@ -1344,6 +1415,13 @@ optionalDependencies: "@img/sharp-libvips-linux-arm" "1.2.0" +"@img/sharp-linux-arm@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz#5f020d933f54f3fc49203d32c3b7dd0ec11ffcdb" + integrity sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.3" + "@img/sharp-linux-ppc64@0.34.3": version "0.34.3" resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz#6a7cd4c608011333a0ddde6d96e03ac042dd9079" @@ -1351,6 +1429,13 @@ optionalDependencies: "@img/sharp-libvips-linux-ppc64" "1.2.0" +"@img/sharp-linux-ppc64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz#8d5775f6dc7e30ea3a1efa43798b7690bb5cb344" + integrity sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.3" + "@img/sharp-linux-s390x@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667" @@ -1372,6 +1457,13 @@ optionalDependencies: "@img/sharp-libvips-linux-s390x" "1.2.0" +"@img/sharp-linux-s390x@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz#740aa5b369188ee2c1913b1015e7f830f4dfdb50" + integrity sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.3" + "@img/sharp-linux-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb" @@ -1393,6 +1485,13 @@ optionalDependencies: "@img/sharp-libvips-linux-x64" "1.2.0" +"@img/sharp-linux-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz#573ce4196b2d0771bba32acc13a37b7adc9b6212" + integrity sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.3" + "@img/sharp-linuxmusl-arm64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b" @@ -1414,6 +1513,13 @@ optionalDependencies: "@img/sharp-libvips-linuxmusl-arm64" "1.2.0" +"@img/sharp-linuxmusl-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz#3c91bc8348cc3b42b43c6fca14f9dbb5cb47bd0d" + integrity sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.3" + "@img/sharp-linuxmusl-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48" @@ -1435,6 +1541,13 @@ optionalDependencies: "@img/sharp-libvips-linuxmusl-x64" "1.2.0" +"@img/sharp-linuxmusl-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz#33de7d476ac9e2db7ef654331b54cc679b806bda" + integrity sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.3" + "@img/sharp-wasm32@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1" @@ -1456,6 +1569,13 @@ dependencies: "@emnapi/runtime" "^1.4.4" +"@img/sharp-wasm32@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz#d617f7b3f851f899802298f360667c20605c0198" + integrity sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA== + dependencies: + "@emnapi/runtime" "^1.5.0" + "@img/sharp-win32-arm64@0.34.2": version "0.34.2" resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz#f37bee0f60c167f825a09d2b8de6849b823e8b30" @@ -1466,6 +1586,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz#3e8654e368bb349d45799a0d7aeb29db2298628e" integrity sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ== +"@img/sharp-win32-arm64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz#38e2c8a88826eac647f7c3f99efefb39897a8f5c" + integrity sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA== + "@img/sharp-win32-ia32@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9" @@ -1481,6 +1606,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz#9d4c105e8d5074a351a81a0b6d056e0af913bf76" integrity sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw== +"@img/sharp-win32-ia32@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz#003a7eb0fdaba600790c3007cfd756e41a9cf749" + integrity sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw== + "@img/sharp-win32-x64@0.33.5": version "0.33.5" resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342" @@ -1496,6 +1626,11 @@ resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz#d20c89bd41b1dd3d76d8575714aaaa3c43204b6a" integrity sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g== +"@img/sharp-win32-x64@0.34.4": + version "0.34.4" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz#b19f1f88ace8bfc20784a0ad31767f3438e025d1" + integrity sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig== + "@inquirer/confirm@^5.0.0": version "5.1.12" resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-5.1.12.tgz#387037889a5a558ceefe52e978228630aa6e7d0e" @@ -1811,10 +1946,10 @@ "@emnapi/runtime" "^1.3.1" "@tybys/wasm-util" "^0.9.0" -"@next/env@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/env/-/env-15.3.4.tgz#5b41485596d5bfea0918db73f90b7a6db734da3f" - integrity sha512-ZkdYzBseS6UjYzz6ylVKPOK+//zLWvD6Ta+vpoye8cW11AjiQjGYVibF0xuvT4L0iJfAPfZLFidaEzAOywyOAQ== +"@next/env@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.6.0-canary.34.tgz#e97bce92f8918239fce88a688b260c81cc043720" + integrity sha512-OpjhOCarzTE7c5GvNGYrpVlPh60seQDwa1Vau76ZDgFx8BLwODL7wpOkgKaWqHepu68zV9EuLQy1IkrU34Vjcw== "@next/eslint-plugin-next@15.1.3": version "15.1.3" @@ -1823,45 +1958,45 @@ dependencies: fast-glob "3.3.1" -"@next/swc-darwin-arm64@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.4.tgz#cb2849b8374eb6b52376d4e7abed2a21a2ff24d6" - integrity sha512-z0qIYTONmPRbwHWvpyrFXJd5F9YWLCsw3Sjrzj2ZvMYy9NPQMPZ1NjOJh4ojr4oQzcGYwgJKfidzehaNa1BpEg== +"@next/swc-darwin-arm64@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.6.0-canary.34.tgz#553d843b8da5ece93cbd6f5d2f5eb327e9601544" + integrity sha512-YAGGiAJyfqISxu+0vTvZO6wNnjHpPDqQ/Km9HuoUgdFa9Gl02qgYenkl0wtLv4ULizpvDP4An2ik1S63JzFasw== -"@next/swc-darwin-x64@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.4.tgz#aa7fd968af7e53aa17d4f234cf7722b3899712cf" - integrity sha512-Z0FYJM8lritw5Wq+vpHYuCIzIlEMjewG2aRkc3Hi2rcbULknYL/xqfpBL23jQnCSrDUGAo/AEv0Z+s2bff9Zkw== +"@next/swc-darwin-x64@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.6.0-canary.34.tgz#995ebc272fb8c6b79e565ade0b738b361f173f58" + integrity sha512-7Ils05FOT0jLL/zpvobtqlodswfpTe28z4a701ZIUxUcRMb0p3F3aySjd3oc/1ZElQf2buGabxbJZIsoPKNXrw== -"@next/swc-linux-arm64-gnu@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.4.tgz#5da3d6d6055665d0c3a2dab0bc0471064bc9eece" - integrity sha512-l8ZQOCCg7adwmsnFm8m5q9eIPAHdaB2F3cxhufYtVo84pymwKuWfpYTKcUiFcutJdp9xGHC+F1Uq3xnFU1B/7g== +"@next/swc-linux-arm64-gnu@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.6.0-canary.34.tgz#dca81392730b3fbab59df6ee7a1a39929c992a05" + integrity sha512-MWqankIvInIQlWclHOZwC5FHJ7dx6OFrtpqJCtThabncSy7imkKBTzfL/Bytb8WQw6e85YzNwUzH1PGA8voHrw== -"@next/swc-linux-arm64-musl@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.4.tgz#9043ccc397746c94c2452d301e8f95a33aec22e8" - integrity sha512-wFyZ7X470YJQtpKot4xCY3gpdn8lE9nTlldG07/kJYexCUpX1piX+MBfZdvulo+t1yADFVEuzFfVHfklfEx8kw== +"@next/swc-linux-arm64-musl@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.6.0-canary.34.tgz#2c7bbb7ed2028321772e220e213ce8f399d8d78f" + integrity sha512-8Cv+0TS8m3S7n4LBDe+GLn/6GZyutPxuHFaeZouFOgU7uHwXo/CRzRwPh10RoxyobooRoDIovVeA9moKy/JqiQ== -"@next/swc-linux-x64-gnu@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.4.tgz#49a33f904a51a8c665406ca7e5a748f480bf195d" - integrity sha512-gEbH9rv9o7I12qPyvZNVTyP/PWKqOp8clvnoYZQiX800KkqsaJZuOXkWgMa7ANCCh/oEN2ZQheh3yH8/kWPSEg== +"@next/swc-linux-x64-gnu@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.6.0-canary.34.tgz#2e1825a9c13d339561262103b6f6109bde605766" + integrity sha512-TJ/cCYk/aXp7Gxz6WtmuiklTpojfhikqEFrZRzNt4vLB+s1/6BdOx7FgIp2Y6m0Xjxqqq+i+3DI094L392ssFw== -"@next/swc-linux-x64-musl@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.4.tgz#8beaff35d8f11961ea80d12a10226581df4c5a74" - integrity sha512-Cf8sr0ufuC/nu/yQ76AnarbSAXcwG/wj+1xFPNbyNo8ltA6kw5d5YqO8kQuwVIxk13SBdtgXrNyom3ZosHAy4A== +"@next/swc-linux-x64-musl@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.6.0-canary.34.tgz#a2a2a04eb3dd43b270e2c712e519d96cb550d39b" + integrity sha512-+zpMXFVGspAYfTR30v6EM0pOPaTjBSwwDbcRg2hOsI1PdFGVLwvljdDw2jZrS9JwyaIF7btCfTUi4w636G66TQ== -"@next/swc-win32-arm64-msvc@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.4.tgz#149d9a35068ecda317af138814539929c9c269af" - integrity sha512-ay5+qADDN3rwRbRpEhTOreOn1OyJIXS60tg9WMYTWCy3fB6rGoyjLVxc4dR9PYjEdR2iDYsaF5h03NA+XuYPQQ== +"@next/swc-win32-arm64-msvc@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.6.0-canary.34.tgz#80f9cf75616f7d3dae54839c0795a03a0cd84100" + integrity sha512-f40lriU/Zqy5v5QqmdTaCZywCeH/sg5Q5gE1rTFpJXfSf3O7uDAfh960A//Yatl/ADeNGNvY1BdA/NXdKntEsQ== -"@next/swc-win32-x64-msvc@15.3.4": - version "15.3.4" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.4.tgz#a652327782d838c2b875eaf216187c51b8409775" - integrity sha512-4kDt31Bc9DGyYs41FTL1/kNpDeHyha2TC0j5sRRoKCyrhNcfZ/nRQkAUlF27mETwm8QyHqIjHJitfcza2Iykfg== +"@next/swc-win32-x64-msvc@15.6.0-canary.34": + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.6.0-canary.34.tgz#bc1eb485053f3fe869dcc7c2bacf01c8348a9a75" + integrity sha512-2V5q/qv9s70IQjhzaRZG6X22qdI67gBknBeNAD6/TR7JB2dCpPjsUXt8JpR+LiUueth26GR8Hbn+w68S3hNHug== "@node-rs/argon2-android-arm-eabi@2.0.2": version "2.0.2" @@ -1981,6 +2116,17 @@ resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== +"@omit/react-confirm-dialog@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@omit/react-confirm-dialog/-/react-confirm-dialog-1.2.0.tgz#fff9c47570a91411d8cd8a1dc64385b09fbd12b7" + integrity sha512-FXfEnOLPQdGwPXe0zTjgVVbS6OZdAZ+Qs+tSBU819CwtXLNjvx+mimvYvnGnm6dIHK4PGV17D7ViSn+KI8HPRg== + dependencies: + "@radix-ui/react-alert-dialog" "^1.1.13" + "@radix-ui/react-slot" "^1.2.2" + class-variance-authority "^0.7.1" + clsx "^2.1.1" + tailwind-merge "^2.6.0" + "@open-draft/deferred-promise@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd" @@ -2435,6 +2581,23 @@ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.2.tgz#83f415c4425f21e3d27914c12b3272a32e3dae65" integrity sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA== +"@radix-ui/primitive@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.3.tgz#e2dbc13bdc5e4168f4334f75832d7bdd3e2de5ba" + integrity sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg== + +"@radix-ui/react-alert-dialog@^1.1.13": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz#fa751d0fdd9aa2a90961c9901dba18e638dd4b41" + integrity sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw== + dependencies: + "@radix-ui/primitive" "1.1.3" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dialog" "1.1.15" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-arrow@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz#30c0d574d7bb10eed55cd7007b92d38b03c6b2ab" @@ -2548,6 +2711,26 @@ aria-hidden "^1.1.1" react-remove-scroll "2.5.5" +"@radix-ui/react-dialog@1.1.15": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz#1de3d7a7e9a17a9874d29c07f5940a18a119b632" + integrity sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw== + dependencies: + "@radix-ui/primitive" "1.1.3" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dismissable-layer" "1.1.11" + "@radix-ui/react-focus-guards" "1.1.3" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.5" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + "@radix-ui/react-dialog@^1.1.5": version "1.1.6" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz#65b4465e99ad900f28a98eed9a94bb21ec644bf7" @@ -2601,6 +2784,17 @@ "@radix-ui/react-use-callback-ref" "1.1.1" "@radix-ui/react-use-escape-keydown" "1.1.1" +"@radix-ui/react-dismissable-layer@1.1.11": + version "1.1.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz#e33ab6f6bdaa00f8f7327c408d9f631376b88b37" + integrity sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg== + dependencies: + "@radix-ui/primitive" "1.1.3" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-escape-keydown" "1.1.1" + "@radix-ui/react-dismissable-layer@1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz#96dde2be078c694a621e55e047406c58cd5fe774" @@ -2637,6 +2831,11 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe" integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg== +"@radix-ui/react-focus-guards@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz#2a5669e464ad5fde9f86d22f7fdc17781a4dfa7f" + integrity sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw== + "@radix-ui/react-focus-scope@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525" @@ -2656,6 +2855,15 @@ "@radix-ui/react-primitive" "2.0.2" "@radix-ui/react-use-callback-ref" "1.1.0" +"@radix-ui/react-focus-scope@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz#dfe76fc103537d80bf42723a183773fd07bfb58d" + integrity sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-hover-card@^1.1.14": version "1.1.14" resolved "https://registry.yarnpkg.com/@radix-ui/react-hover-card/-/react-hover-card-1.1.14.tgz#a557cda6470e214e744e46ede839496e8b291843" @@ -2826,6 +3034,14 @@ "@radix-ui/react-compose-refs" "1.1.2" "@radix-ui/react-use-layout-effect" "1.1.1" +"@radix-ui/react-presence@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.5.tgz#5d8f28ac316c32f078afce2996839250c10693db" + integrity sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-primitive@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" @@ -2927,7 +3143,7 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.1" -"@radix-ui/react-slot@1.2.3": +"@radix-ui/react-slot@1.2.3", "@radix-ui/react-slot@^1.2.2": version "1.2.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz#502d6e354fc847d4169c3bc5f189de777f68cfe1" integrity sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A== @@ -4101,11 +4317,6 @@ resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.0.0.tgz#f193b73dc316c4170f2e82a881da0f550d551b9c" integrity sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA== -"@swc/counter@0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" - integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== - "@swc/helpers@0.5.15": version "0.5.15" resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7" @@ -5498,13 +5709,6 @@ bundle-require@^5.1.0: dependencies: load-tsconfig "^0.2.3" -busboy@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" - bytes@3.1.2, bytes@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -6486,6 +6690,11 @@ detect-libc@^2.0.3, detect-libc@^2.0.4: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== +detect-libc@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.1.tgz#9f1e511ace6bb525efea4651345beac424dac7b9" + integrity sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw== + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" @@ -9815,28 +10024,26 @@ next-themes@^0.4.4: resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.4.6.tgz#8d7e92d03b8fea6582892a50a928c9b23502e8b6" integrity sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA== -next@^15.3.4: - version "15.3.4" - resolved "https://registry.yarnpkg.com/next/-/next-15.3.4.tgz#7a4863be14c998f1ec1e6d8d4e9e1a1291c8cbe3" - integrity sha512-mHKd50C+mCjam/gcnwqL1T1vPx/XQNFlXqFIVdgQdVAFY9iIQtY0IfaVflEYzKiqjeA7B0cYYMaCrmAYFjs4rA== +next@^15.6.0-canary.34: + version "15.6.0-canary.34" + resolved "https://registry.yarnpkg.com/next/-/next-15.6.0-canary.34.tgz#37dfec95a7cdb6edd87d3559667ec28674d55576" + integrity sha512-H2lVHtMc8TSMvQe3zu66AlLGYM3Jn22KW+TpIFIIQaplZZQyyPN8hcq76fO/iIIb0KI5902rHesmoPxxlFAWYA== dependencies: - "@next/env" "15.3.4" - "@swc/counter" "0.1.3" + "@next/env" "15.6.0-canary.34" "@swc/helpers" "0.5.15" - busboy "1.6.0" caniuse-lite "^1.0.30001579" postcss "8.4.31" styled-jsx "5.1.6" optionalDependencies: - "@next/swc-darwin-arm64" "15.3.4" - "@next/swc-darwin-x64" "15.3.4" - "@next/swc-linux-arm64-gnu" "15.3.4" - "@next/swc-linux-arm64-musl" "15.3.4" - "@next/swc-linux-x64-gnu" "15.3.4" - "@next/swc-linux-x64-musl" "15.3.4" - "@next/swc-win32-arm64-msvc" "15.3.4" - "@next/swc-win32-x64-msvc" "15.3.4" - sharp "^0.34.1" + "@next/swc-darwin-arm64" "15.6.0-canary.34" + "@next/swc-darwin-x64" "15.6.0-canary.34" + "@next/swc-linux-arm64-gnu" "15.6.0-canary.34" + "@next/swc-linux-arm64-musl" "15.6.0-canary.34" + "@next/swc-linux-x64-gnu" "15.6.0-canary.34" + "@next/swc-linux-x64-musl" "15.6.0-canary.34" + "@next/swc-win32-arm64-msvc" "15.6.0-canary.34" + "@next/swc-win32-x64-msvc" "15.6.0-canary.34" + sharp "^0.34.4" nlcst-to-string@^4.0.0: version "4.0.0" @@ -10566,6 +10773,11 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prettier@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== + pretty-bytes@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-6.1.1.tgz#38cd6bb46f47afbf667c202cfc754bffd2016a3b" @@ -11548,7 +11760,7 @@ sharp@^0.33.3: "@img/sharp-win32-ia32" "0.33.5" "@img/sharp-win32-x64" "0.33.5" -sharp@^0.34.1, sharp@^0.34.2: +sharp@^0.34.2: version "0.34.2" resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.2.tgz#648bd639854dbe48047b0b420213c186d036b32d" integrity sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg== @@ -11611,6 +11823,38 @@ sharp@^0.34.3: "@img/sharp-win32-ia32" "0.34.3" "@img/sharp-win32-x64" "0.34.3" +sharp@^0.34.4: + version "0.34.4" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.4.tgz#73c2c5a425e98250b8b927e5537f711da8966e38" + integrity sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA== + dependencies: + "@img/colour" "^1.0.0" + detect-libc "^2.1.0" + semver "^7.7.2" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.4" + "@img/sharp-darwin-x64" "0.34.4" + "@img/sharp-libvips-darwin-arm64" "1.2.3" + "@img/sharp-libvips-darwin-x64" "1.2.3" + "@img/sharp-libvips-linux-arm" "1.2.3" + "@img/sharp-libvips-linux-arm64" "1.2.3" + "@img/sharp-libvips-linux-ppc64" "1.2.3" + "@img/sharp-libvips-linux-s390x" "1.2.3" + "@img/sharp-libvips-linux-x64" "1.2.3" + "@img/sharp-libvips-linuxmusl-arm64" "1.2.3" + "@img/sharp-libvips-linuxmusl-x64" "1.2.3" + "@img/sharp-linux-arm" "0.34.4" + "@img/sharp-linux-arm64" "0.34.4" + "@img/sharp-linux-ppc64" "0.34.4" + "@img/sharp-linux-s390x" "0.34.4" + "@img/sharp-linux-x64" "0.34.4" + "@img/sharp-linuxmusl-arm64" "0.34.4" + "@img/sharp-linuxmusl-x64" "0.34.4" + "@img/sharp-wasm32" "0.34.4" + "@img/sharp-win32-arm64" "0.34.4" + "@img/sharp-win32-ia32" "0.34.4" + "@img/sharp-win32-x64" "0.34.4" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -11805,11 +12049,6 @@ stream-replace-string@^2.0.0: resolved "https://registry.yarnpkg.com/stream-replace-string/-/stream-replace-string-2.0.0.tgz#e49fd584bd1c633613e010bc73b9db49cb5024ad" integrity sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w== -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - strict-event-emitter@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" @@ -12048,7 +12287,7 @@ tabbable@^6.2.0: resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== -tailwind-merge@^2.2.2, tailwind-merge@^2.5.5: +tailwind-merge@^2.2.2, tailwind-merge@^2.5.5, tailwind-merge@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.6.0.tgz#ac5fb7e227910c038d458f396b7400d93a3142d5" integrity sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==