diff --git a/README.md b/README.md index b501e41..167e618 100644 --- a/README.md +++ b/README.md @@ -148,9 +148,17 @@ DATABASE_URL=postgresql://... BLOB_READ_WRITE_TOKEN=... # Stack Auth -STACK_PROJECT_ID=... -STACK_PUBLISHED_CLIENT_KEY=... +NEXT_PUBLIC_STACK_PROJECT_ID=... +NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=... STACK_SECRET_SERVER_KEY=... + +# Stripe Billing +STRIPE_SECRET_KEY=... +STRIPE_WEBHOOK_SECRET=... +STRIPE_PRICE_ID_PRO=... + +# Optional app URL override (used for Stripe redirects) +NEXT_PUBLIC_APP_URL=http://localhost:3000 ``` 4. **Run the development server** diff --git a/app/api/payments/checkout/route.ts b/app/api/payments/checkout/route.ts new file mode 100644 index 0000000..4201934 --- /dev/null +++ b/app/api/payments/checkout/route.ts @@ -0,0 +1,79 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { getCurrentUser } from '@/lib/auth'; +import { getAppBaseUrl, getStripeServerClient, stripePriceByPlan } from '@/lib/stripe'; +import { + getUserSubscription, + markOnboardingStepCompleted, + upsertUserSubscription, +} from '@/lib/queries'; + +export async function POST(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const stripe = getStripeServerClient(); + const plan = ((await request.json().catch(() => ({}))) as { plan?: string }).plan ?? 'pro'; + const normalizedPlan = plan === 'pro' ? 'pro' : 'pro'; + const priceId = stripePriceByPlan[normalizedPlan]; + + if (!stripe || !priceId) { + return NextResponse.json( + { error: 'Stripe checkout is not configured.' }, + { status: 500 } + ); + } + + const existingSubscription = await getUserSubscription(user.id); + let stripeCustomerId = existingSubscription?.stripe_customer_id ?? null; + + if (!stripeCustomerId) { + const customer = await stripe.customers.create({ + email: user.primaryEmail || undefined, + name: user.displayName || undefined, + metadata: { user_id: user.id }, + }); + stripeCustomerId = customer.id; + } + + const baseUrl = getAppBaseUrl(request.nextUrl.origin); + + const checkoutSession = await stripe.checkout.sessions.create({ + mode: 'subscription', + customer: stripeCustomerId, + line_items: [{ price: priceId, quantity: 1 }], + client_reference_id: user.id, + metadata: { + user_id: user.id, + plan: normalizedPlan, + }, + allow_promotion_codes: true, + success_url: `${baseUrl}/dashboard/billing?checkout=success`, + cancel_url: `${baseUrl}/dashboard/billing?checkout=cancelled`, + }); + + await upsertUserSubscription(user.id, { + stripe_customer_id: stripeCustomerId, + plan: existingSubscription?.plan ?? 'free', + status: existingSubscription?.status ?? 'inactive', + stripe_subscription_id: existingSubscription?.stripe_subscription_id ?? null, + current_period_end: existingSubscription?.current_period_end ?? null, + cancel_at_period_end: existingSubscription?.cancel_at_period_end ?? false, + }); + + if (!checkoutSession.url) { + return NextResponse.json( + { error: 'Unable to create checkout URL.' }, + { status: 500 } + ); + } + await markOnboardingStepCompleted(user.id, 'trial_started'); + + return NextResponse.json({ url: checkoutSession.url }); + } catch (error) { + console.error('Error creating checkout session:', error); + return NextResponse.json({ error: 'Failed to start checkout' }, { status: 500 }); + } +} diff --git a/app/api/payments/portal/route.ts b/app/api/payments/portal/route.ts new file mode 100644 index 0000000..d01d54a --- /dev/null +++ b/app/api/payments/portal/route.ts @@ -0,0 +1,53 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { getCurrentUser } from '@/lib/auth'; +import { getAppBaseUrl, getStripeServerClient } from '@/lib/stripe'; +import { getUserSubscription, upsertUserSubscription } from '@/lib/queries'; + +export async function POST(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const stripe = getStripeServerClient(); + if (!stripe) { + return NextResponse.json( + { error: 'Stripe billing portal is not configured.' }, + { status: 500 } + ); + } + + const existingSubscription = await getUserSubscription(user.id); + let customerId = existingSubscription?.stripe_customer_id ?? null; + + if (!customerId) { + const customer = await stripe.customers.create({ + email: user.primaryEmail || undefined, + name: user.displayName || undefined, + metadata: { user_id: user.id }, + }); + customerId = customer.id; + + await upsertUserSubscription(user.id, { + stripe_customer_id: customerId, + status: existingSubscription?.status ?? 'inactive', + plan: existingSubscription?.plan ?? 'free', + stripe_subscription_id: existingSubscription?.stripe_subscription_id ?? null, + current_period_end: existingSubscription?.current_period_end ?? null, + cancel_at_period_end: existingSubscription?.cancel_at_period_end ?? false, + }); + } + + const returnUrl = `${getAppBaseUrl(request.nextUrl.origin)}/dashboard/billing`; + const portal = await stripe.billingPortal.sessions.create({ + customer: customerId, + return_url: returnUrl, + }); + + return NextResponse.json({ url: portal.url }); + } catch (error) { + console.error('Error creating billing portal session:', error); + return NextResponse.json({ error: 'Failed to open billing portal' }, { status: 500 }); + } +} diff --git a/app/api/payments/webhook/route.ts b/app/api/payments/webhook/route.ts new file mode 100644 index 0000000..ac29ddc --- /dev/null +++ b/app/api/payments/webhook/route.ts @@ -0,0 +1,121 @@ +import Stripe from 'stripe'; +import { NextRequest, NextResponse } from 'next/server'; +import { getStripeServerClient, stripePriceByPlan } from '@/lib/stripe'; +import { + getUserSubscriptionByCustomerId, + updateUserSubscriptionByCustomerId, + upsertUserSubscription, +} from '@/lib/queries'; + +export const runtime = 'nodejs'; + +function mapPriceIdToPlan(priceId: string | null | undefined) { + if (!priceId) return 'free'; + if (priceId === stripePriceByPlan.pro) return 'pro'; + return 'free'; +} + +function timestampToIso(value: number | null | undefined) { + if (!value) return null; + return new Date(value * 1000).toISOString(); +} + +export async function POST(request: NextRequest) { + try { + const stripe = getStripeServerClient(); + const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET; + + if (!stripe || !webhookSecret) { + return NextResponse.json( + { error: 'Stripe webhook is not configured.' }, + { status: 500 } + ); + } + + const signature = request.headers.get('stripe-signature'); + if (!signature) { + return NextResponse.json({ error: 'Missing Stripe signature' }, { status: 400 }); + } + + const payload = await request.text(); + const event = stripe.webhooks.constructEvent(payload, signature, webhookSecret); + + if (event.type === 'checkout.session.completed') { + const session = event.data.object as Stripe.Checkout.Session; + const userId = session.metadata?.user_id ?? session.client_reference_id ?? null; + const customerId = typeof session.customer === 'string' ? session.customer : null; + const subscriptionId = + typeof session.subscription === 'string' ? session.subscription : null; + const plan = session.metadata?.plan ?? 'pro'; + + if (userId && customerId) { + await upsertUserSubscription(userId, { + stripe_customer_id: customerId, + stripe_subscription_id: subscriptionId, + status: 'active', + plan, + cancel_at_period_end: false, + }); + } + } + + if ( + event.type === 'customer.subscription.created' || + event.type === 'customer.subscription.updated' || + event.type === 'customer.subscription.deleted' + ) { + const subscription = event.data.object as Stripe.Subscription; + const customerId = + typeof subscription.customer === 'string' + ? subscription.customer + : subscription.customer.id; + + const priceId = subscription.items.data[0]?.price?.id; + const plan = mapPriceIdToPlan(priceId); + const currentPeriodEnd = timestampToIso(subscription.current_period_end); + const status = + event.type === 'customer.subscription.deleted' + ? 'canceled' + : subscription.status; + + const updated = await updateUserSubscriptionByCustomerId(customerId, { + stripe_subscription_id: subscription.id, + status, + plan, + current_period_end: currentPeriodEnd, + cancel_at_period_end: subscription.cancel_at_period_end, + }); + + if (!updated) { + const fromMetadata = subscription.metadata?.user_id; + if (fromMetadata) { + await upsertUserSubscription(fromMetadata, { + stripe_customer_id: customerId, + stripe_subscription_id: subscription.id, + status, + plan, + current_period_end: currentPeriodEnd, + cancel_at_period_end: subscription.cancel_at_period_end, + }); + } else { + const existingByCustomer = await getUserSubscriptionByCustomerId(customerId); + if (existingByCustomer) { + await upsertUserSubscription(existingByCustomer.user_id, { + stripe_customer_id: customerId, + stripe_subscription_id: subscription.id, + status, + plan, + current_period_end: currentPeriodEnd, + cancel_at_period_end: subscription.cancel_at_period_end, + }); + } + } + } + } + + return NextResponse.json({ received: true }); + } catch (error) { + console.error('Stripe webhook error:', error); + return NextResponse.json({ error: 'Webhook handling failed' }, { status: 400 }); + } +} diff --git a/app/api/profile/route.ts b/app/api/profile/route.ts new file mode 100644 index 0000000..392a274 --- /dev/null +++ b/app/api/profile/route.ts @@ -0,0 +1,69 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { getCurrentUser } from '@/lib/auth'; +import { + getUserProfile, + markOnboardingStepCompleted, + upsertUserProfile, +} from '@/lib/queries'; + +function cleanNullableString(value: unknown, maxLength = 255) { + if (typeof value !== 'string') return null; + const trimmed = value.trim(); + if (!trimmed) return null; + return trimmed.slice(0, maxLength); +} + +export async function GET() { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const profile = await getUserProfile(user.id); + if (profile) { + return NextResponse.json(profile); + } + + const created = await upsertUserProfile(user.id, { + display_name: user.displayName ?? null, + billing_email: user.primaryEmail ?? null, + timezone: 'UTC', + }); + + return NextResponse.json(created); + } catch (error) { + console.error('Error fetching profile:', error); + return NextResponse.json({ error: 'Failed to fetch profile' }, { status: 500 }); + } +} + +export async function PUT(request: NextRequest) { + try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const body = (await request.json()) as Record; + + const timezone = + typeof body.timezone === 'string' && body.timezone.trim().length > 0 + ? body.timezone.trim().slice(0, 100) + : 'UTC'; + + const profile = await upsertUserProfile(user.id, { + display_name: cleanNullableString(body.display_name, 255), + company_name: cleanNullableString(body.company_name, 255), + job_title: cleanNullableString(body.job_title, 255), + billing_email: cleanNullableString(body.billing_email, 255), + timezone, + }); + await markOnboardingStepCompleted(user.id, 'profile_completed'); + + return NextResponse.json(profile); + } catch (error) { + console.error('Error updating profile:', error); + return NextResponse.json({ error: 'Failed to update profile' }, { status: 500 }); + } +} diff --git a/app/api/projects/[id]/activity/route.ts b/app/api/projects/[id]/activity/route.ts index 6c2956b..e1c8025 100644 --- a/app/api/projects/[id]/activity/route.ts +++ b/app/api/projects/[id]/activity/route.ts @@ -1,13 +1,22 @@ import { db } from '@/lib/db' import { type NextRequest, NextResponse } from 'next/server' +import { getCurrentUser } from '@/lib/auth' export async function GET( request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { id: projectId } = await params - const limit = request.nextUrl.searchParams.get('limit') || '50' + const parsedLimit = Number.parseInt(request.nextUrl.searchParams.get('limit') || '50', 10) + const limit = Number.isFinite(parsedLimit) + ? Math.min(Math.max(parsedLimit, 1), 200) + : 50 const result = await db.query( `SELECT @@ -18,7 +27,7 @@ export async function GET( WHERE al.project_id = $1 ORDER BY al.created_at DESC LIMIT $2`, - [projectId, parseInt(limit)] + [projectId, limit] ) return NextResponse.json(result.rows) @@ -33,10 +42,15 @@ export async function POST( { params }: { params: Promise<{ id: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { id: projectId } = await params - const { user_id, action, entity_type, entity_id, description, metadata } = await request.json() + const { action, entity_type, entity_id, description, metadata } = await request.json() - if (!user_id || !action || !entity_type) { + if (!action || !entity_type) { return NextResponse.json({ error: 'Missing required fields' }, { status: 400 }) } @@ -44,7 +58,7 @@ export async function POST( `INSERT INTO activity_logs (project_id, user_id, action, entity_type, entity_id, description, metadata) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *`, - [projectId, user_id, action, entity_type, entity_id || null, description || null, JSON.stringify(metadata || {})] + [projectId, user.id, action, entity_type, entity_id || null, description || null, JSON.stringify(metadata || {})] ) return NextResponse.json(result.rows[0], { status: 201 }) diff --git a/app/api/projects/[id]/analytics/route.ts b/app/api/projects/[id]/analytics/route.ts index ddd9be0..2de50e5 100644 --- a/app/api/projects/[id]/analytics/route.ts +++ b/app/api/projects/[id]/analytics/route.ts @@ -1,17 +1,23 @@ import { db } from '@/lib/db' import { type NextRequest, NextResponse } from 'next/server' +import { getCurrentUser } from '@/lib/auth' export async function GET( - request: NextRequest, + _request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { id: projectId } = await params // Get task statistics const tasksResult = await db.query( `SELECT - status, COUNT(*) as count + status, COUNT(*)::int as count FROM tasks WHERE project_id = $1 GROUP BY status`, @@ -21,7 +27,7 @@ export async function GET( // Get priority distribution const priorityResult = await db.query( `SELECT - priority, COUNT(*) as count + priority, COUNT(*)::int as count FROM tasks WHERE project_id = $1 GROUP BY priority`, @@ -31,8 +37,8 @@ export async function GET( // Get task completion rate const completionResult = await db.query( `SELECT - COUNT(CASE WHEN status = 'done' THEN 1 END) as completed, - COUNT(*) as total + COUNT(CASE WHEN status = 'done' THEN 1 END)::int as completed, + COUNT(*)::int as total FROM tasks WHERE project_id = $1`, [projectId] @@ -42,8 +48,8 @@ export async function GET( const teamResult = await db.query( `SELECT u.id, u.name, u.email, - COUNT(t.id) as assigned_tasks, - COUNT(CASE WHEN t.status = 'done' THEN 1 END) as completed_tasks + COUNT(t.id)::int as assigned_tasks, + COUNT(CASE WHEN t.status = 'done' THEN 1 END)::int as completed_tasks FROM neon_auth."user" u LEFT JOIN tasks t ON u.id = t.assigned_to AND t.project_id = $1 JOIN project_members pm ON u.id = pm.user_id AND pm.project_id = $1 @@ -55,7 +61,7 @@ export async function GET( const activityResult = await db.query( `SELECT DATE_TRUNC('day', created_at) as date, - COUNT(*) as count + COUNT(*)::int as count FROM activity_logs WHERE project_id = $1 AND created_at >= NOW() - INTERVAL '30 days' diff --git a/app/api/projects/[id]/members/route.ts b/app/api/projects/[id]/members/route.ts index 60d492c..5b46f61 100644 --- a/app/api/projects/[id]/members/route.ts +++ b/app/api/projects/[id]/members/route.ts @@ -1,11 +1,19 @@ import { db } from '@/lib/db' import { type NextRequest, NextResponse } from 'next/server' +import { getCurrentUser } from '@/lib/auth' + +const VALID_ROLES = new Set(['owner', 'admin', 'member', 'viewer']) export async function GET( - request: NextRequest, + _request: NextRequest, { params }: { params: Promise<{ id: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { id: projectId } = await params const result = await db.query( @@ -31,6 +39,11 @@ export async function POST( { params }: { params: Promise<{ id: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { id: projectId } = await params const { user_id, role } = await request.json() @@ -38,6 +51,10 @@ export async function POST( return NextResponse.json({ error: 'Missing required fields' }, { status: 400 }) } + if (!VALID_ROLES.has(role)) { + return NextResponse.json({ error: 'Invalid role' }, { status: 400 }) + } + const result = await db.query( `INSERT INTO project_members (project_id, user_id, role) VALUES ($1, $2, $3) @@ -55,9 +72,14 @@ export async function POST( export async function DELETE( request: NextRequest, - { params }: { params: Promise<{ id: string }> } + _context: { params: Promise<{ id: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { member_id } = await request.json() if (!member_id) { diff --git a/app/api/projects/[id]/tasks/[taskId]/attachments/route.ts b/app/api/projects/[id]/tasks/[taskId]/attachments/route.ts index 57260d1..caf01fa 100644 --- a/app/api/projects/[id]/tasks/[taskId]/attachments/route.ts +++ b/app/api/projects/[id]/tasks/[taskId]/attachments/route.ts @@ -1,11 +1,17 @@ import { db } from '@/lib/db' import { type NextRequest, NextResponse } from 'next/server' +import { getCurrentUser } from '@/lib/auth' export async function GET( - request: NextRequest, + _request: NextRequest, { params }: { params: Promise<{ id: string; taskId: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { taskId } = await params const result = await db.query( @@ -25,8 +31,13 @@ export async function POST( { params }: { params: Promise<{ id: string; taskId: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const { taskId } = await params - const { file_url, file_name, file_size, mime_type, uploaded_by } = await request.json() + const { file_url, file_name, file_size, mime_type } = await request.json() if (!file_url || !file_name) { return NextResponse.json({ error: 'Missing required fields' }, { status: 400 }) @@ -36,7 +47,7 @@ export async function POST( `INSERT INTO task_attachments (task_id, uploaded_by, file_name, file_url, file_size, mime_type) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`, - [taskId, uploaded_by, file_name, file_url, file_size || null, mime_type || null] + [taskId, user.id, file_name, file_url, file_size || null, mime_type || null] ) return NextResponse.json(result.rows[0], { status: 201 }) @@ -51,13 +62,19 @@ export async function DELETE( { params }: { params: Promise<{ id: string; taskId: string }> } ) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + + const { taskId } = await params const { attachment_id } = await request.json() if (!attachment_id) { return NextResponse.json({ error: 'Missing attachment_id' }, { status: 400 }) } - await db.query('DELETE FROM task_attachments WHERE id = $1', [attachment_id]) + await db.query('DELETE FROM task_attachments WHERE id = $1 AND task_id = $2', [attachment_id, taskId]) return NextResponse.json({ success: true }) } catch (error) { diff --git a/app/api/projects/[id]/tasks/[taskId]/comments/route.ts b/app/api/projects/[id]/tasks/[taskId]/comments/route.ts index 20b40ad..08d4f18 100644 --- a/app/api/projects/[id]/tasks/[taskId]/comments/route.ts +++ b/app/api/projects/[id]/tasks/[taskId]/comments/route.ts @@ -1,12 +1,17 @@ -import { currentUser } from '@stack-auth/nextjs'; import { createTaskComment, getTaskComments } from '@/lib/queries'; import { NextRequest, NextResponse } from 'next/server'; +import { getCurrentUser } from '@/lib/auth'; export async function GET( - request: NextRequest, + _request: NextRequest, { params }: { params: Promise<{ id: string; taskId: string }> } ) { try { + const user = await getCurrentUser(); + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + const { taskId } = await params; const comments = await getTaskComments(taskId); return NextResponse.json(comments); @@ -21,7 +26,7 @@ export async function POST( { params }: { params: Promise<{ id: string; taskId: string }> } ) { try { - const user = await currentUser(); + const user = await getCurrentUser(); const { taskId } = await params; if (!user) { diff --git a/app/api/projects/[id]/tasks/[taskId]/route.ts b/app/api/projects/[id]/tasks/[taskId]/route.ts new file mode 100644 index 0000000..2ee777c --- /dev/null +++ b/app/api/projects/[id]/tasks/[taskId]/route.ts @@ -0,0 +1,46 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { getCurrentUser } from '@/lib/auth'; +import { getTaskById, updateTask } from '@/lib/queries'; + +const updatableFields = new Set([ + 'title', + 'description', + 'status', + 'priority', + 'assigned_to', + 'due_date', + 'order_index', +]); + +export async function PATCH( + request: NextRequest, + { params }: { params: Promise<{ id: string; taskId: string }> } +) { + try { + const user = await getCurrentUser(); + const { id: projectId, taskId } = await params; + + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + } + + const existingTask = await getTaskById(taskId); + if (!existingTask || existingTask.project_id !== projectId) { + return NextResponse.json({ error: 'Task not found' }, { status: 404 }); + } + + const body = (await request.json()) as Record; + const updates = Object.fromEntries( + Object.entries(body).filter(([key]) => updatableFields.has(key)) + ); + + const updatedTask = await updateTask( + taskId, + updates as Parameters[1] + ); + return NextResponse.json(updatedTask); + } catch (error) { + console.error('Error updating task:', error); + return NextResponse.json({ error: 'Failed to update task' }, { status: 500 }); + } +} diff --git a/app/api/projects/[id]/tasks/route.ts b/app/api/projects/[id]/tasks/route.ts index 046d8d0..9fe8016 100644 --- a/app/api/projects/[id]/tasks/route.ts +++ b/app/api/projects/[id]/tasks/route.ts @@ -1,10 +1,10 @@ -import { currentUser } from '@stack-auth/nextjs'; -import { createTask, updateTask } from '@/lib/queries'; +import { createTask, markOnboardingStepCompleted } from '@/lib/queries'; import { NextRequest, NextResponse } from 'next/server'; +import { getCurrentUser } from '@/lib/auth'; export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { try { - const user = await currentUser(); + const user = await getCurrentUser(); const { id: projectId } = await params; if (!user) { @@ -29,6 +29,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ due_date: due_date || null, order_index: 0, }); + await markOnboardingStepCompleted(user.id, 'first_task_created'); return NextResponse.json(task); } catch (error) { @@ -36,22 +37,3 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ return NextResponse.json({ error: 'Failed to create task' }, { status: 500 }); } } - -export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { - try { - const user = await currentUser(); - const { id: taskId } = await params; - - if (!user) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - - const body = await request.json(); - const updatedTask = await updateTask(taskId, body); - - return NextResponse.json(updatedTask); - } catch (error) { - console.error('Error updating task:', error); - return NextResponse.json({ error: 'Failed to update task' }, { status: 500 }); - } -} diff --git a/app/api/projects/route.ts b/app/api/projects/route.ts index 3202ee0..b1ea12c 100644 --- a/app/api/projects/route.ts +++ b/app/api/projects/route.ts @@ -1,12 +1,13 @@ -import { currentUser } from '@stack-auth/nextjs'; -import { createProject } from '@/lib/queries'; +import { createProject, markOnboardingStepCompleted } from '@/lib/queries'; import { NextRequest, NextResponse } from 'next/server'; +import { getCurrentOrganizationId, getCurrentUser } from '@/lib/auth'; export async function POST(request: NextRequest) { try { - const user = await currentUser(); + const user = await getCurrentUser(); + const organizationId = getCurrentOrganizationId(user); - if (!user || !user.activeOrganizationId) { + if (!user || !organizationId) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } @@ -24,7 +25,7 @@ export async function POST(request: NextRequest) { .replace(/^-+|-+$/g, ''); const project = await createProject({ - organization_id: user.activeOrganizationId, + organization_id: organizationId, name: name.trim(), description: description?.trim() || null, slug, @@ -34,6 +35,7 @@ export async function POST(request: NextRequest) { icon: 'P', created_by: user.id, }); + await markOnboardingStepCompleted(user.id, 'first_project_created'); return NextResponse.json(project); } catch (error) { diff --git a/app/api/upload/route.ts b/app/api/upload/route.ts index 4232697..c48e664 100644 --- a/app/api/upload/route.ts +++ b/app/api/upload/route.ts @@ -1,8 +1,14 @@ import { put } from '@vercel/blob' import { type NextRequest, NextResponse } from 'next/server' +import { getCurrentUser } from '@/lib/auth' export async function POST(request: NextRequest) { try { + const user = await getCurrentUser() + if (!user) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + const formData = await request.formData() const file = formData.get('file') as File diff --git a/app/auth/login/page.tsx b/app/auth/login/page.tsx new file mode 100644 index 0000000..5f53a67 --- /dev/null +++ b/app/auth/login/page.tsx @@ -0,0 +1,38 @@ +import Link from 'next/link'; +import { ArrowRight } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { isStackAuthConfigured } from '@/stack'; + +export default function LoginPage() { + return ( +
+
+

Sign in

+

+ Access your workspace to manage projects, profile details, and billing. +

+ + {!isStackAuthConfigured && ( +
+ Stack Auth keys are missing. Set NEXT_PUBLIC_STACK_PROJECT_ID, + NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY, and STACK_SECRET_SERVER_KEY. +
+ )} + + + + + +

+ New here?{' '} + + Create an account + +

+
+
+ ); +} diff --git a/app/auth/signup/page.tsx b/app/auth/signup/page.tsx new file mode 100644 index 0000000..ab2a39f --- /dev/null +++ b/app/auth/signup/page.tsx @@ -0,0 +1,38 @@ +import Link from 'next/link'; +import { ArrowRight } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { isStackAuthConfigured } from '@/stack'; + +export default function SignUpPage() { + return ( +
+
+

Create your account

+

+ Sign up to set up your profile, collaborate with your team, and activate billing. +

+ + {!isStackAuthConfigured && ( +
+ Stack Auth keys are missing. Set NEXT_PUBLIC_STACK_PROJECT_ID, + NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY, and STACK_SECRET_SERVER_KEY. +
+ )} + + + + + +

+ Already have an account?{' '} + + Sign in + +

+
+
+ ); +} diff --git a/app/dashboard/billing/page.tsx b/app/dashboard/billing/page.tsx new file mode 100644 index 0000000..1c98f35 --- /dev/null +++ b/app/dashboard/billing/page.tsx @@ -0,0 +1,34 @@ +import { BillingSettings } from '@/components/billing-settings'; +import { requireCurrentUser } from '@/lib/auth'; +import { getUserSubscription } from '@/lib/queries'; +import { isStripeConfigured } from '@/lib/stripe'; + +export default async function BillingPage() { + const user = await requireCurrentUser(); + const subscription = await getUserSubscription(user.id); + + return ( +
+
+

Billing

+

+ Configure payments, upgrade plans, and manage your subscription. +

+
+ + +
+ ); +} diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index a6bc995..80a6405 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -1,111 +1,21 @@ -'use client'; +import { DashboardShell } from '@/components/dashboard-shell'; +import { requireCurrentUser } from '@/lib/auth'; -import { useUser } from '@stack-auth/nextjs'; -import { redirect } from 'next/navigation'; -import { LayoutDashboard, Settings, LogOut, Menu, X } from 'lucide-react'; -import { useState } from 'react'; -import Link from 'next/link'; -import { Button } from '@/components/ui/button'; - -export default function DashboardLayout({ children }: { children: React.ReactNode }) { - const user = useUser(); - const [sidebarOpen, setSidebarOpen] = useState(false); - - if (!user) { - redirect('/auth/login'); - } +export default async function DashboardLayout({ + children, +}: { + children: React.ReactNode; +}) { + const user = await requireCurrentUser(); return ( -
- {/* Sidebar */} - - - {/* Main content */} -
- {/* Top navigation */} -
-
- -
-
-
- - {/* Page content */} -
- {children} -
-
- - {/* Mobile overlay */} - {sidebarOpen && ( -
setSidebarOpen(false)} - /> - )} -
+ + {children} + ); } diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index f8a6cdd..6dd350c 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,16 +1,18 @@ -import { getProjectsByOrganization } from '@/lib/queries'; -import { currentUser } from '@stack-auth/nextjs'; +import { getOnboardingChecklist, getProjectsByOrganization } from '@/lib/queries'; +import { getCurrentOrganizationId, requireCurrentUser } from '@/lib/auth'; import { Button } from '@/components/ui/button'; import { Plus, Folder, Users } from 'lucide-react'; import Link from 'next/link'; +import { OnboardingChecklist } from '@/components/onboarding-checklist'; export default async function DashboardPage() { - const user = await currentUser(); - if (!user) return null; + const user = await requireCurrentUser(); - // Get the organization ID from user's active organization - const orgId = user.activeOrganizationId; - const projects = orgId ? await getProjectsByOrganization(orgId) : []; + const orgId = getCurrentOrganizationId(user); + const [projects, onboardingChecklist] = await Promise.all([ + orgId ? getProjectsByOrganization(orgId) : Promise.resolve([]), + getOnboardingChecklist(user.id, orgId), + ]); return (
@@ -51,14 +53,18 @@ export default async function DashboardPage() {
+ + {/* Projects section */}

Your Projects

- + + +
{projects.length === 0 ? ( @@ -68,7 +74,9 @@ export default async function DashboardPage() {

Get started by creating your first project to organize your tasks.

- + + +
) : (
diff --git a/app/dashboard/profile/page.tsx b/app/dashboard/profile/page.tsx new file mode 100644 index 0000000..cf5ef3f --- /dev/null +++ b/app/dashboard/profile/page.tsx @@ -0,0 +1,29 @@ +import { ProfileSettingsForm } from '@/components/profile-settings-form'; +import { getUserProfile } from '@/lib/queries'; +import { requireCurrentUser } from '@/lib/auth'; + +export default async function ProfilePage() { + const user = await requireCurrentUser(); + const profile = await getUserProfile(user.id); + + return ( +
+
+

Profile

+

+ Update your identity and billing contact details. +

+
+ + +
+ ); +} diff --git a/app/dashboard/projects/[id]/page.tsx b/app/dashboard/projects/[id]/page.tsx index 0b7d527..3d24038 100644 --- a/app/dashboard/projects/[id]/page.tsx +++ b/app/dashboard/projects/[id]/page.tsx @@ -1,6 +1,6 @@ import { getProjectById, getTasksByProject, getProjectMembers } from '@/lib/queries' import { notFound } from 'next/navigation' -import { ArrowLeft, Users, Settings, Plus, BarChart3, ListTodo, MessageSquare } from 'lucide-react' +import { ArrowLeft, Settings, Plus, BarChart3, ListTodo, MessageSquare } from 'lucide-react' import Link from 'next/link' import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' diff --git a/app/dashboard/projects/[id]/settings/page.tsx b/app/dashboard/projects/[id]/settings/page.tsx index 1ae8979..cb228fe 100644 --- a/app/dashboard/projects/[id]/settings/page.tsx +++ b/app/dashboard/projects/[id]/settings/page.tsx @@ -1,5 +1,6 @@ import { TeamSettings } from '@/components/team-settings' import { Card } from '@/components/ui/card' +import { requireCurrentUser } from '@/lib/auth' interface Props { params: Promise<{ id: string }> @@ -7,9 +8,7 @@ interface Props { export default async function SettingsPage({ params }: Props) { const { id: projectId } = await params - - // TODO: Get current user from auth context - const currentUserId = 'temp-user-id' + const currentUser = await requireCurrentUser() return (
@@ -42,7 +41,7 @@ export default async function SettingsPage({ params }: Props) {
- +
) diff --git a/app/dashboard/projects/[id]/tasks/[taskId]/page.tsx b/app/dashboard/projects/[id]/tasks/[taskId]/page.tsx index f32321d..e3a0c9f 100644 --- a/app/dashboard/projects/[id]/tasks/[taskId]/page.tsx +++ b/app/dashboard/projects/[id]/tasks/[taskId]/page.tsx @@ -1,8 +1,7 @@ import { getProjectById, getTaskById, getTaskComments } from '@/lib/queries'; import { notFound } from 'next/navigation'; -import { ArrowLeft, Calendar, User, AlertCircle } from 'lucide-react'; +import { ArrowLeft, Calendar, User } from 'lucide-react'; import Link from 'next/link'; -import { Button } from '@/components/ui/button'; import { TaskComments } from '@/components/task-comments'; interface TaskDetailPageProps { @@ -67,7 +66,7 @@ export default async function TaskDetailPage({ params }: TaskDetailPageProps) { {/* Task Comments */} - + {/* Sidebar */} diff --git a/app/dashboard/projects/page.tsx b/app/dashboard/projects/page.tsx index 4800771..d34fb9e 100644 --- a/app/dashboard/projects/page.tsx +++ b/app/dashboard/projects/page.tsx @@ -1,12 +1,11 @@ import { getProjectsByOrganization } from '@/lib/queries'; -import { currentUser } from '@stack-auth/nextjs'; +import { getCurrentOrganizationId, requireCurrentUser } from '@/lib/auth'; import { ProjectsList } from '@/components/projects-list'; export default async function ProjectsPage() { - const user = await currentUser(); - if (!user) return null; + const user = await requireCurrentUser(); - const orgId = user.activeOrganizationId; + const orgId = getCurrentOrganizationId(user); const projects = orgId ? await getProjectsByOrganization(orgId) : []; return ; diff --git a/app/handler/[...stack]/page.tsx b/app/handler/[...stack]/page.tsx new file mode 100644 index 0000000..dbc1396 --- /dev/null +++ b/app/handler/[...stack]/page.tsx @@ -0,0 +1,6 @@ +import { StackHandler } from '@stackframe/stack'; +import { stackServerApp } from '@/stack'; + +export default function HandlerPage() { + return ; +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..510f9ca --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,63 @@ +import Link from 'next/link'; +import { ArrowRight, CreditCard, ShieldCheck, UserRound } from 'lucide-react'; +import { Button } from '@/components/ui/button'; + +export default function HomePage() { + return ( +
+
+

TaskFlow SaaS

+

+ Launch-ready onboarding, profiles, and billing +

+

+ New users can sign up, sign in, set up their profile, and manage paid plans from a + single dashboard experience. +

+
+ + + + + + + + + +
+
+ +
+
+ +

Profile management

+

+ Capture display name, company, job title, and timezone so accounts are immediately + usable. +

+
+
+ +

Payments & subscriptions

+

+ Start checkout, manage billing portal access, and sync subscription events via webhooks. +

+
+
+ +

Secure auth flow

+

+ Stack Auth handler routes provide robust sign-up, sign-in, and session management. +

+
+
+
+ ); +} diff --git a/components/analytics-dashboard.tsx b/components/analytics-dashboard.tsx index 389c304..d8db550 100644 --- a/components/analytics-dashboard.tsx +++ b/components/analytics-dashboard.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import { Card } from '@/components/ui/card' -import { BarChart, Bar, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts' +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts' import { Users, ListTodo, CheckCircle2, TrendingUp } from 'lucide-react' interface AnalyticsData { diff --git a/components/billing-settings.tsx b/components/billing-settings.tsx new file mode 100644 index 0000000..dff13c8 --- /dev/null +++ b/components/billing-settings.tsx @@ -0,0 +1,161 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { useSearchParams } from 'next/navigation'; +import { ArrowRight, CreditCard, ExternalLink } from 'lucide-react'; +import { Button } from '@/components/ui/button'; + +interface BillingSettingsProps { + stripeConfigured: boolean; + subscription: { + status: string; + plan: string; + current_period_end: string | null; + cancel_at_period_end: boolean; + } | null; +} + +export function BillingSettings({ stripeConfigured, subscription }: BillingSettingsProps) { + const searchParams = useSearchParams(); + const [loadingAction, setLoadingAction] = useState<'checkout' | 'portal' | null>(null); + const [error, setError] = useState(null); + + const isActive = useMemo(() => { + const status = subscription?.status; + return status === 'active' || status === 'trialing' || status === 'past_due'; + }, [subscription?.status]); + + const statusText = subscription?.status ?? 'inactive'; + const checkoutState = searchParams.get('checkout'); + + const startCheckout = async () => { + setLoadingAction('checkout'); + setError(null); + try { + const response = await fetch('/api/payments/checkout', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ plan: 'pro' }), + }); + + const body = (await response.json().catch(() => null)) as + | { url?: string; error?: string } + | null; + + if (!response.ok || !body?.url) { + throw new Error(body?.error || 'Unable to start checkout'); + } + + window.location.href = body.url; + } catch (err) { + console.error('Checkout failed:', err); + setError(err instanceof Error ? err.message : 'Checkout failed'); + } finally { + setLoadingAction(null); + } + }; + + const openPortal = async () => { + setLoadingAction('portal'); + setError(null); + try { + const response = await fetch('/api/payments/portal', { method: 'POST' }); + const body = (await response.json().catch(() => null)) as + | { url?: string; error?: string } + | null; + + if (!response.ok || !body?.url) { + throw new Error(body?.error || 'Unable to open billing portal'); + } + + window.location.href = body.url; + } catch (err) { + console.error('Billing portal failed:', err); + setError(err instanceof Error ? err.message : 'Billing portal failed'); + } finally { + setLoadingAction(null); + } + }; + + return ( +
+
+ +
+

Subscription & billing

+

+ Manage plan activation, payment method updates, and subscription lifecycle. +

+
+
+ + {!stripeConfigured && ( +
+ Stripe is not configured. Set STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, and + STRIPE_PRICE_ID_PRO. +
+ )} + + {checkoutState === 'success' && ( +
+ Checkout completed. Your subscription status will refresh automatically after webhook + processing. +
+ )} + + {checkoutState === 'cancelled' && ( +
+ Checkout was cancelled. You can restart it at any time. +
+ )} + +
+
+

Current plan

+

{subscription?.plan ?? 'free'}

+
+
+

Status

+

{statusText.replace('_', ' ')}

+
+
+

Period end

+

+ {subscription?.current_period_end + ? new Date(subscription.current_period_end).toLocaleDateString() + : 'N/A'} +

+
+
+ + {error &&

{error}

} + +
+ + + +
+ + {subscription?.cancel_at_period_end && ( +

+ Your subscription is set to cancel at the end of the current billing period. +

+ )} +
+ ); +} diff --git a/components/dashboard-shell.tsx b/components/dashboard-shell.tsx new file mode 100644 index 0000000..6e56e39 --- /dev/null +++ b/components/dashboard-shell.tsx @@ -0,0 +1,140 @@ +'use client'; + +import { useState } from 'react'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { + LayoutDashboard, + FolderKanban, + UserCircle2, + CreditCard, + LogOut, + Menu, + X, +} from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/utils'; + +interface DashboardShellProps { + children: React.ReactNode; + user: { + displayName: string | null; + primaryEmail: string | null; + }; +} + +const navigation = [ + { href: '/dashboard', label: 'Dashboard', icon: LayoutDashboard }, + { href: '/dashboard/projects', label: 'Projects', icon: FolderKanban }, + { href: '/dashboard/profile', label: 'Profile', icon: UserCircle2 }, + { href: '/dashboard/billing', label: 'Billing', icon: CreditCard }, +]; + +export function DashboardShell({ children, user }: DashboardShellProps) { + const pathname = usePathname(); + const [sidebarOpen, setSidebarOpen] = useState(false); + + return ( +
+ + +
+
+
+ +
+
+
+ +
{children}
+
+ + {sidebarOpen && ( +
setSidebarOpen(false)} + /> + )} +
+ ); +} diff --git a/components/file-uploader.tsx b/components/file-uploader.tsx index f76206a..f303617 100644 --- a/components/file-uploader.tsx +++ b/components/file-uploader.tsx @@ -7,21 +7,19 @@ import { Upload, X, File, Loader2 } from 'lucide-react' interface FileUploaderProps { projectId: string taskId: string - userId: string onFileUploaded?: (file: any) => void } export function FileUploader({ projectId, taskId, - userId, onFileUploaded, }: FileUploaderProps) { const [isUploading, setIsUploading] = useState(false) const [uploadedFiles, setUploadedFiles] = useState([]) const fileInputRef = useRef(null) - const handleFileSelect = async (files: FileList | null) { + const handleFileSelect = async (files: FileList | null) => { if (!files) return for (const file of Array.from(files)) { @@ -57,7 +55,6 @@ export function FileUploader({ file_name: filename, file_size: size, mime_type: type, - uploaded_by: userId, }), } ) @@ -74,7 +71,7 @@ export function FileUploader({ } } - const deleteFile = async (attachmentId: string, fileUrl: string) => { + const deleteFile = async (attachmentId: string) => { try { await fetch( `/api/projects/${projectId}/tasks/${taskId}/attachments`, @@ -147,7 +144,7 @@ export function FileUploader({
+ + )} + + ))} + + + ); +} diff --git a/components/profile-settings-form.tsx b/components/profile-settings-form.tsx new file mode 100644 index 0000000..225b03e --- /dev/null +++ b/components/profile-settings-form.tsx @@ -0,0 +1,128 @@ +'use client'; + +import { useState } from 'react'; +import { Save } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; + +interface ProfileSettingsFormProps { + initialProfile: { + display_name: string | null; + company_name: string | null; + job_title: string | null; + timezone: string; + billing_email: string | null; + }; +} + +export function ProfileSettingsForm({ initialProfile }: ProfileSettingsFormProps) { + const [form, setForm] = useState({ + display_name: initialProfile.display_name ?? '', + company_name: initialProfile.company_name ?? '', + job_title: initialProfile.job_title ?? '', + timezone: initialProfile.timezone || 'UTC', + billing_email: initialProfile.billing_email ?? '', + }); + const [saving, setSaving] = useState(false); + const [statusMessage, setStatusMessage] = useState(null); + const [statusError, setStatusError] = useState(null); + + const updateField = (key: keyof typeof form, value: string) => { + setForm((prev) => ({ ...prev, [key]: value })); + }; + + const onSave = async () => { + setSaving(true); + setStatusMessage(null); + setStatusError(null); + + try { + const response = await fetch('/api/profile', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(form), + }); + + if (!response.ok) { + const body = (await response.json().catch(() => null)) as { error?: string } | null; + throw new Error(body?.error || 'Failed to save profile'); + } + + setStatusMessage('Profile saved successfully.'); + } catch (error) { + console.error('Failed to save profile:', error); + setStatusError(error instanceof Error ? error.message : 'Failed to save profile'); + } finally { + setSaving(false); + } + }; + + return ( +
+
+

Profile details

+

+ Keep account information up to date for onboarding and billing. +

+
+ +
+
+ + updateField('display_name', e.target.value)} + /> +
+ +
+ + updateField('job_title', e.target.value)} + /> +
+ +
+ + updateField('company_name', e.target.value)} + /> +
+ +
+ + updateField('timezone', e.target.value)} + placeholder="UTC" + /> +
+
+ +
+ + updateField('billing_email', e.target.value)} + /> +
+ + {statusMessage &&

{statusMessage}

} + {statusError &&

{statusError}

} + + +
+ ); +} diff --git a/components/projects-list.tsx b/components/projects-list.tsx index 8d8a5b3..dba0aa8 100644 --- a/components/projects-list.tsx +++ b/components/projects-list.tsx @@ -1,7 +1,8 @@ 'use client'; import { useState } from 'react'; -import { Plus, Search, MoreVertical, Trash2, Edit } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { Plus, Search, MoreVertical } from 'lucide-react'; import { Button } from '@/components/ui/button'; import Link from 'next/link'; import { @@ -31,8 +32,11 @@ interface ProjectsPageProps { } export function ProjectsList({ projects }: ProjectsPageProps) { + const router = useRouter(); const [searchQuery, setSearchQuery] = useState(''); const [isOpen, setIsOpen] = useState(false); + const [isCreating, setIsCreating] = useState(false); + const [createError, setCreateError] = useState(null); const [newProject, setNewProject] = useState({ name: '', description: '' }); const filteredProjects = projects.filter( @@ -44,13 +48,32 @@ export function ProjectsList({ projects }: ProjectsPageProps) { const handleCreateProject = async () => { if (!newProject.name.trim()) return; + setIsCreating(true); + setCreateError(null); + try { - // This will be connected to the API route - // For now, just reset the form + const response = await fetch('/api/projects', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + name: newProject.name.trim(), + description: newProject.description.trim() || null, + }), + }); + + if (!response.ok) { + const body = (await response.json().catch(() => null)) as { error?: string } | null; + throw new Error(body?.error || 'Failed to create project'); + } + setNewProject({ name: '', description: '' }); setIsOpen(false); + router.refresh(); } catch (error) { console.error('Failed to create project:', error); + setCreateError(error instanceof Error ? error.message : 'Failed to create project'); + } finally { + setIsCreating(false); } }; @@ -94,11 +117,18 @@ export function ProjectsList({ projects }: ProjectsPageProps) { /> + {createError && ( +

+ {createError} +

+ )} - + diff --git a/components/task-comments.tsx b/components/task-comments.tsx index 472724e..45c4e2f 100644 --- a/components/task-comments.tsx +++ b/components/task-comments.tsx @@ -1,6 +1,7 @@ 'use client'; import { useState } from 'react'; +import { useRouter } from 'next/navigation'; import { Send, MessageCircle } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -15,21 +16,28 @@ interface TaskComment { } interface TaskCommentsProps { + projectId: string; taskId: string; comments: TaskComment[]; onCommentAdded?: () => void; } -export function TaskComments({ taskId, comments, onCommentAdded }: TaskCommentsProps) { +export function TaskComments({ + projectId, + taskId, + comments, + onCommentAdded, +}: TaskCommentsProps) { const [newComment, setNewComment] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); + const router = useRouter(); const handleAddComment = async () => { if (!newComment.trim()) return; setIsSubmitting(true); try { - const response = await fetch(`/api/projects/[id]/tasks/${taskId}/comments`, { + const response = await fetch(`/api/projects/${projectId}/tasks/${taskId}/comments`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: newComment }), @@ -37,6 +45,7 @@ export function TaskComments({ taskId, comments, onCommentAdded }: TaskCommentsP if (response.ok) { setNewComment(''); + router.refresh(); onCommentAdded?.(); } } catch (error) { diff --git a/components/team-settings.tsx b/components/team-settings.tsx index a64a938..8d82f05 100644 --- a/components/team-settings.tsx +++ b/components/team-settings.tsx @@ -3,7 +3,7 @@ import { useState, useEffect } from 'react' import { Card } from '@/components/ui/card' import { Button } from '@/components/ui/button' -import { Users, Trash2, Shield, Edit2 } from 'lucide-react' +import { Users, Trash2, Edit2 } from 'lucide-react' interface TeamMember { id: string diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..566f5b7 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,23 @@ +import nextPlugin from '@next/eslint-plugin-next'; +import tseslint from 'typescript-eslint'; + +export default [ + { + ignores: ['.next/**', 'node_modules/**', 'out/**', 'dist/**'], + }, + ...tseslint.configs.recommended, + nextPlugin.configs.recommended, + nextPlugin.configs['core-web-vitals'], + { + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + }, + ], + }, + }, +]; diff --git a/lib/auth.ts b/lib/auth.ts new file mode 100644 index 0000000..04fae48 --- /dev/null +++ b/lib/auth.ts @@ -0,0 +1,28 @@ +import 'server-only'; + +import { redirect } from 'next/navigation'; +import { isStackAuthConfigured, stackServerApp } from '@/stack'; + +export async function getCurrentUser() { + if (!isStackAuthConfigured) { + return null; + } + + return stackServerApp.getUser({ or: 'return-null' }); +} + +export async function requireCurrentUser() { + const user = await getCurrentUser(); + + if (!user) { + redirect('/auth/login'); + } + + return user; +} + +export function getCurrentOrganizationId( + user: { selectedTeam: { id: string } | null } | null +) { + return user?.selectedTeam?.id ?? null; +} diff --git a/lib/db.ts b/lib/db.ts index 8f0c7b3..d171399 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -1,5 +1,28 @@ -import { neon } from '@neondatabase/serverless'; +import { Pool, type QueryResult, type QueryResultRow } from 'pg'; -const sql = neon(process.env.DATABASE_URL || ''); +const DATABASE_URL = process.env.DATABASE_URL; -export { sql }; +if (!DATABASE_URL) { + // Keep this as a runtime warning so builds still succeed in CI + // where secrets may not be present. + console.warn('DATABASE_URL is not set. Database queries will fail until it is configured.'); +} + +const pool = new Pool({ + connectionString: DATABASE_URL, + ssl: DATABASE_URL?.includes('localhost') ? false : { rejectUnauthorized: false }, +}); + +export const db = { + query(text: string, params?: unknown[]) { + return pool.query(text, params); + }, +}; + +export async function sql( + text: string, + params?: unknown[] +): Promise { + const result: QueryResult = await db.query(text, params); + return result.rows; +} diff --git a/lib/queries.ts b/lib/queries.ts index 47c805d..3a9b662 100644 --- a/lib/queries.ts +++ b/lib/queries.ts @@ -54,6 +54,8 @@ export interface ProjectMember { id: string; project_id: string; user_id: string; + name?: string | null; + email?: string | null; role: 'owner' | 'admin' | 'member' | 'viewer'; added_at: string; } @@ -66,10 +68,63 @@ export interface ActivityLog { entity_type: string; entity_id: string | null; description: string | null; - metadata: Record | null; + metadata: Record | null; created_at: string; } +export interface UserProfile { + user_id: string; + display_name: string | null; + company_name: string | null; + job_title: string | null; + timezone: string; + billing_email: string | null; + created_at: string; + updated_at: string; +} + +export interface UserSubscription { + user_id: string; + stripe_customer_id: string | null; + stripe_subscription_id: string | null; + status: string; + plan: string; + current_period_end: string | null; + cancel_at_period_end: boolean; + created_at: string; + updated_at: string; +} + +export type OnboardingStepKey = + | 'profile_completed' + | 'first_project_created' + | 'first_task_created' + | 'trial_started'; + +export interface OnboardingProgress { + user_id: string; + profile_completed_at: string | null; + first_project_created_at: string | null; + first_task_created_at: string | null; + trial_started_at: string | null; + created_at: string; + updated_at: string; +} + +export interface OnboardingChecklistStep { + key: OnboardingStepKey; + title: string; + description: string; + href: string; + completed: boolean; +} + +export interface OnboardingChecklist { + steps: OnboardingChecklistStep[]; + completedCount: number; + totalCount: number; +} + // Project queries export async function getProjectsByOrganization(orgId: string): Promise { const projects = await sql('SELECT * FROM projects WHERE organization_id = $1 AND status != $2 ORDER BY created_at DESC', [ @@ -127,7 +182,7 @@ export async function createTask(data: Omit): Promise { const updates: string[] = []; - const values: any[] = []; + const values: unknown[] = []; let paramIndex = 1; Object.entries(data).forEach(([key, value]) => { @@ -138,6 +193,14 @@ export async function updateTask(taskId: string, data: Partial): Promise { - const members = await sql('SELECT * FROM project_members WHERE project_id = $1', [projectId]); + const members = await sql( + `SELECT + pm.id, + pm.project_id, + pm.user_id, + pm.role, + pm.added_at, + u.name as name, + u.email as email + FROM project_members pm + LEFT JOIN neon_auth."user" u ON u.id = pm.user_id + WHERE pm.project_id = $1 + ORDER BY pm.added_at DESC`, + [projectId] + ); return members as ProjectMember[]; } @@ -181,3 +258,238 @@ export async function logActivity(data: Omit): ); return result[0] as ActivityLog; } + +// User profile queries +export async function getUserProfile(userId: string): Promise { + const profiles = await sql('SELECT * FROM user_profiles WHERE user_id = $1', [userId]); + return (profiles[0] as UserProfile) || null; +} + +export async function upsertUserProfile( + userId: string, + data: Partial> +): Promise { + const result = await sql( + `INSERT INTO user_profiles (user_id, display_name, company_name, job_title, timezone, billing_email) + VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT(user_id) DO UPDATE SET + display_name = EXCLUDED.display_name, + company_name = EXCLUDED.company_name, + job_title = EXCLUDED.job_title, + timezone = EXCLUDED.timezone, + billing_email = EXCLUDED.billing_email, + updated_at = CURRENT_TIMESTAMP + RETURNING *`, + [ + userId, + data.display_name ?? null, + data.company_name ?? null, + data.job_title ?? null, + data.timezone ?? 'UTC', + data.billing_email ?? null, + ] + ); + + return result[0] as UserProfile; +} + +// Subscription queries +export async function getUserSubscription(userId: string): Promise { + const subscriptions = await sql('SELECT * FROM user_subscriptions WHERE user_id = $1', [userId]); + return (subscriptions[0] as UserSubscription) || null; +} + +export async function getUserSubscriptionByCustomerId( + customerId: string +): Promise { + const subscriptions = await sql( + 'SELECT * FROM user_subscriptions WHERE stripe_customer_id = $1', + [customerId] + ); + return (subscriptions[0] as UserSubscription) || null; +} + +export async function upsertUserSubscription( + userId: string, + data: Partial> +): Promise { + const result = await sql( + `INSERT INTO user_subscriptions ( + user_id, stripe_customer_id, stripe_subscription_id, status, plan, current_period_end, cancel_at_period_end + ) + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT(user_id) DO UPDATE SET + stripe_customer_id = EXCLUDED.stripe_customer_id, + stripe_subscription_id = EXCLUDED.stripe_subscription_id, + status = EXCLUDED.status, + plan = EXCLUDED.plan, + current_period_end = EXCLUDED.current_period_end, + cancel_at_period_end = EXCLUDED.cancel_at_period_end, + updated_at = CURRENT_TIMESTAMP + RETURNING *`, + [ + userId, + data.stripe_customer_id ?? null, + data.stripe_subscription_id ?? null, + data.status ?? 'inactive', + data.plan ?? 'free', + data.current_period_end ?? null, + data.cancel_at_period_end ?? false, + ] + ); + + return result[0] as UserSubscription; +} + +export async function updateUserSubscriptionByCustomerId( + customerId: string, + data: Partial> +): Promise { + const result = await sql( + `UPDATE user_subscriptions + SET + stripe_subscription_id = COALESCE($2, stripe_subscription_id), + status = COALESCE($3, status), + plan = COALESCE($4, plan), + current_period_end = COALESCE($5, current_period_end), + cancel_at_period_end = COALESCE($6, cancel_at_period_end), + updated_at = CURRENT_TIMESTAMP + WHERE stripe_customer_id = $1 + RETURNING *`, + [ + customerId, + data.stripe_subscription_id ?? null, + data.status ?? null, + data.plan ?? null, + data.current_period_end ?? null, + data.cancel_at_period_end ?? null, + ] + ); + + return (result[0] as UserSubscription) || null; +} + +// Onboarding queries +const onboardingStepColumnMap: Record = { + profile_completed: 'profile_completed_at', + first_project_created: 'first_project_created_at', + first_task_created: 'first_task_created_at', + trial_started: 'trial_started_at', +}; + +export async function getOnboardingProgress( + userId: string +): Promise { + const rows = await sql('SELECT * FROM onboarding_progress WHERE user_id = $1', [userId]); + return (rows[0] as OnboardingProgress) || null; +} + +export async function markOnboardingStepCompleted( + userId: string, + step: OnboardingStepKey +): Promise { + const columnName = onboardingStepColumnMap[step]; + + const result = await sql( + `INSERT INTO onboarding_progress (user_id, ${columnName}) + VALUES ($1, CURRENT_TIMESTAMP) + ON CONFLICT(user_id) DO UPDATE SET + ${columnName} = COALESCE(onboarding_progress.${columnName}, EXCLUDED.${columnName}), + updated_at = CURRENT_TIMESTAMP + RETURNING *`, + [userId] + ); + + return result[0] as OnboardingProgress; +} + +export async function getOnboardingChecklist( + userId: string, + organizationId: string | null +): Promise { + const [progress, profile, subscription, projectCountRows, taskCountRows] = await Promise.all([ + getOnboardingProgress(userId), + getUserProfile(userId), + getUserSubscription(userId), + organizationId + ? sql<{ count: number }>( + `SELECT COUNT(*)::int as count + FROM projects + WHERE organization_id = $1 + AND status != 'deleted'`, + [organizationId] + ) + : Promise.resolve([{ count: 0 }]), + organizationId + ? sql<{ count: number }>( + `SELECT COUNT(*)::int as count + FROM tasks t + INNER JOIN projects p ON p.id = t.project_id + WHERE p.organization_id = $1 + AND t.created_by = $2`, + [organizationId, userId] + ) + : Promise.resolve([{ count: 0 }]), + ]); + + const projectCount = Number(projectCountRows[0]?.count ?? 0); + const taskCount = Number(taskCountRows[0]?.count ?? 0); + + const profileCompleted = Boolean( + progress?.profile_completed_at || + (profile && + (profile.display_name || + profile.company_name || + profile.job_title || + profile.billing_email)) + ); + const firstProjectCreated = Boolean( + progress?.first_project_created_at || projectCount > 0 + ); + const firstTaskCreated = Boolean(progress?.first_task_created_at || taskCount > 0); + const trialStarted = Boolean( + progress?.trial_started_at || + subscription?.status === 'trialing' || + subscription?.status === 'active' || + subscription?.stripe_customer_id + ); + + const steps: OnboardingChecklistStep[] = [ + { + key: 'profile_completed', + title: 'Complete your profile', + description: 'Add your personal details and billing contact information.', + href: '/dashboard/profile', + completed: profileCompleted, + }, + { + key: 'first_project_created', + title: 'Create your first project', + description: 'Start a workspace project to organize tasks and activity.', + href: '/dashboard/projects', + completed: firstProjectCreated, + }, + { + key: 'first_task_created', + title: 'Create your first task', + description: 'Add a task in your project to start execution.', + href: '/dashboard/projects', + completed: firstTaskCreated, + }, + { + key: 'trial_started', + title: 'Start your trial', + description: 'Open billing and start checkout to activate paid features.', + href: '/dashboard/billing', + completed: trialStarted, + }, + ]; + + const completedCount = steps.filter((step) => step.completed).length; + + return { + steps, + completedCount, + totalCount: steps.length, + }; +} diff --git a/lib/stripe.ts b/lib/stripe.ts new file mode 100644 index 0000000..66adc91 --- /dev/null +++ b/lib/stripe.ts @@ -0,0 +1,35 @@ +import 'server-only'; + +import Stripe from 'stripe'; + +const stripeSecretKey = process.env.STRIPE_SECRET_KEY ?? null; + +export const stripePriceByPlan = { + pro: process.env.STRIPE_PRICE_ID_PRO ?? null, +}; + +export const isStripeConfigured = Boolean( + stripeSecretKey && + process.env.STRIPE_WEBHOOK_SECRET && + stripePriceByPlan.pro +); + +let stripeClient: Stripe | null = null; + +export function getStripeServerClient() { + if (!stripeSecretKey) { + return null; + } + + if (!stripeClient) { + stripeClient = new Stripe(stripeSecretKey); + } + + return stripeClient; +} + +export function getAppBaseUrl(origin?: string | null) { + if (origin) return origin; + if (process.env.NEXT_PUBLIC_APP_URL) return process.env.NEXT_PUBLIC_APP_URL; + return 'http://localhost:3000'; +} diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..9edff1c --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/package.json b/package.json index 3633a57..cd0d414 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,6 @@ }, "dependencies": { "@hookform/resolvers": "^3.9.1", - "@vercel/analytics": "1.6.1", - "@vercel/blob": "^0.21.0", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-aspect-ratio": "1.1.8", @@ -39,6 +37,10 @@ "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", + "@stackframe/stack": "^2.8.71", + "@stripe/stripe-js": "^8.8.0", + "@vercel/analytics": "1.6.1", + "@vercel/blob": "^0.21.0", "autoprefixer": "^10.4.20", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -57,18 +59,23 @@ "react-resizable-panels": "^2.1.7", "recharts": "2.15.0", "sonner": "^1.7.1", + "stripe": "^20.3.1", "tailwind-merge": "^3.3.1", "vaul": "^1.1.2", "zod": "^3.24.1" }, "devDependencies": { + "@eslint/js": "^10.0.1", + "@next/eslint-plugin-next": "^16.1.6", "@tailwindcss/postcss": "^4.2.0", "@types/node": "^22", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", + "eslint": "^10.0.2", "postcss": "^8.5", "tailwindcss": "^4.2.0", "tw-animate-css": "1.3.3", - "typescript": "5.7.3" + "typescript": "5.7.3", + "typescript-eslint": "^8.56.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d726aae..8d1e8f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,9 +92,15 @@ importers: '@radix-ui/react-tooltip': specifier: 1.2.8 version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@stackframe/stack': + specifier: ^2.8.71 + version: 2.8.71(@aws-sdk/credential-provider-web-identity@3.972.11)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.2.0) + '@stripe/stripe-js': + specifier: ^8.8.0 + version: 8.8.0 '@vercel/analytics': specifier: 1.6.1 - version: 1.6.1(next@16.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + version: 1.6.1(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) '@vercel/blob': specifier: ^0.21.0 version: 0.21.0 @@ -124,7 +130,7 @@ importers: version: 0.564.0(react@19.2.4) next: specifier: 16.1.6 - version: 16.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -152,6 +158,9 @@ importers: sonner: specifier: ^1.7.1 version: 1.7.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + stripe: + specifier: ^20.3.1 + version: 20.3.1(@types/node@22.19.11) tailwind-merge: specifier: ^3.3.1 version: 3.5.0 @@ -162,6 +171,12 @@ importers: specifier: ^3.24.1 version: 3.25.76 devDependencies: + '@eslint/js': + specifier: ^10.0.1 + version: 10.0.1(eslint@10.0.2(jiti@2.6.1)) + '@next/eslint-plugin-next': + specifier: ^16.1.6 + version: 16.1.6 '@tailwindcss/postcss': specifier: ^4.2.0 version: 4.2.0 @@ -174,6 +189,9 @@ importers: '@types/react-dom': specifier: 19.2.3 version: 19.2.3(@types/react@19.2.14) + eslint: + specifier: ^10.0.2 + version: 10.0.2(jiti@2.6.1) postcss: specifier: ^8.5 version: 8.5.6 @@ -186,6 +204,9 @@ importers: typescript: specifier: 5.7.3 version: 5.7.3 + typescript-eslint: + specifier: ^8.56.1 + version: 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) packages: @@ -193,16 +214,391 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-kms@3.997.0': + resolution: {integrity: sha512-9Tc9TjS159b7THJnGvTc27tZ2ywh98yinpoCIxltfqmviRsQgQbveb8PT1k2UsJEQVG3YG0yDME6ZCLwjUJmLg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.973.13': + resolution: {integrity: sha512-eCFiLyBhJR7c/i8hZOETdzj2wsLFzi2L/w9/jajOgwmGqO8xrUExqkTZqdjROkwU62owqeqSuw4sIzlCv1E/ww==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.11': + resolution: {integrity: sha512-hbyoFuVm3qOAGfIPS9t7jCs8GFLFoaOs8ZmYp/chqciuHDyEGv+J365ip7YSvXSrxxUbeW9NyB1hTLt40NBMRg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.13': + resolution: {integrity: sha512-a864QxQWFkdCZ5wQF0QZNKTbqAc/DFQNeARp4gOyZZdql5RHjj4CppUSfwAzS9cpw2IPY3eeJjWqLZ1QiDB/6w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.11': + resolution: {integrity: sha512-kvPFn626ABLzxmjFMoqMRtmFKMeiUdWPhwxhmuPu233tqHnNuXzHv0MtrZlkzHd+rwlh9j0zCbQo89B54wIazQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.11': + resolution: {integrity: sha512-stdy09EpBTmsxGiXe1vB5qtXNww9wact36/uWLlSV0/vWbCOUAY2JjhPXoDVLk8n+E6r0M5HeZseLk+iTtifxg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.12': + resolution: {integrity: sha512-gMWGnHbNSKWRj+PAiuSg0EDpEwpyIgk0v9U6EuZ1C/5/BUv25Way+E+UFB7r+YYkscuBJMJ+ai8E2K0Q8dx50g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.11': + resolution: {integrity: sha512-B049fvbv41vf0Fs5bCtbzHpruBDp61sPiFDxUmkAJ/zvgSAturpj2rqzV1rj2clg4mb44Uxp9rgpcODexNFlFA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.11': + resolution: {integrity: sha512-vX9z8skN8vPtamVWmSCm4KQohub+1uMuRzIo4urZ2ZUMBAl1bqHatVD/roCb3qRfAyIGvZXCA/AWS03BQRMyCQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.11': + resolution: {integrity: sha512-VR2Ju/QBdOjnWNIYuxRml63eFDLGc6Zl8aDwLi1rzgWo3rLBgtaWhWVBAijhVXzyPdQIOqdL8hvll5ybqumjeQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-host-header@3.972.4': + resolution: {integrity: sha512-4q2Vg7/zOB10huDBLjzzTwVjBpG22X3J3ief2XrJEgTaANZrNfA3/cGbCVNAibSbu/nIYA7tDk8WCdsIzDDc4Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-logger@3.972.4': + resolution: {integrity: sha512-xFqPvTysuZAHSkdygT+ken/5rzkR7fhOoDPejAJQslZpp0XBepmCJnDOqA57ERtCTBpu8wpjTFI1ETd4S0AXEw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.972.4': + resolution: {integrity: sha512-tVbRaayUZ7y2bOb02hC3oEPTqQf2A0HpPDwdMl1qTmye/q8Mq1F1WiIoFkQwG/YQFvbyErYIDMbYzIlxzzLtjQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-user-agent@3.972.13': + resolution: {integrity: sha512-p1kVYbzBxRmhuOHoL/ANJPCedqUxnVgkEjxPoxt5pQv/yzppHM7aBWciYEE9TZY59M421D3GjLfZIZBoEFboVQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/nested-clients@3.996.1': + resolution: {integrity: sha512-XHVLFRGkuV2gh2uwBahCt65ALMb5wMpqplXEZIvFnWOCPlk60B7h7M5J9Em243K8iICDiWY6KhBEqVGfjTqlLA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/region-config-resolver@3.972.4': + resolution: {integrity: sha512-3GrJYv5eI65oCKveBZP7Q246dVP+tqeys9aKMB0dfX1glUWfppWlxIu52derqdNb9BX9lxYmeiaBcBIqOAYSgQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.997.0': + resolution: {integrity: sha512-UdG36F7lU9aTqGFRieEyuRUJlgEJBqKeKKekC0esH21DbUSKhPR1kZBah214kYasIaWe1hLJLaqUigoTa5hZAQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.2': + resolution: {integrity: sha512-maTZwGsALtnAw4TJr/S6yERAosTwPduu0XhUV+SdbvRZtCOgSgk1ttL2R0XYzvkYSpvbtJocn77tBXq2AKglBw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-endpoints@3.996.1': + resolution: {integrity: sha512-7cJyd+M5i0IoqWkJa1KFx8KNCGIx+Ywu+lT53KpqX7ReVwz03DCKUqvZ/y65vdKwo9w9/HptSAeLDluO5MpGIg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.4': + resolution: {integrity: sha512-H1onv5SkgPBK2P6JR2MjGgbOnttoNzSPIRoeZTNPZYyaplwGg50zS3amXvXqF0/qfXpWEC9rLWU564QTB9bSog==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-user-agent-browser@3.972.4': + resolution: {integrity: sha512-GHb+8XHv6hfLWKQKAKaSOm+vRvogg07s+FWtbR3+eCXXPSFn9XVmiYF4oypAxH7dGIvoxkVG/buHEnzYukyJiA==} + + '@aws-sdk/util-user-agent-node@3.972.12': + resolution: {integrity: sha512-c1n3wBK6te+Vd9qU86nF8AsYuiBsxLn0AADGWyFX7vEADr3btaAg5iPQT6GYj6rvzSOEVVisvaAatOWInlJUbQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/xml-builder@3.972.6': + resolution: {integrity: sha512-YrXu+UnfC8IdARa4ZkrpcyuRmA/TVgYW6Lcdtvi34NQgRjM1hTirNirN+rGb+s/kNomby8oJiIAu0KNbiZC7PA==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.3': + resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} + engines: {node: '>=18.0.0'} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/runtime@7.28.6': resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@date-fns/tz@1.4.1': resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} '@emnapi/runtime@1.8.1': resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.2': + resolution: {integrity: sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.5.2': + resolution: {integrity: sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.1.0': + resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + + '@eslint/object-schema@3.0.2': + resolution: {integrity: sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.6.0': + resolution: {integrity: sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} @@ -227,6 +623,27 @@ packages: peerDependencies: react-hook-form: ^7.0.0 + '@hookform/resolvers@5.2.2': + resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} + peerDependencies: + react-hook-form: ^7.55.0 + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -257,105 +674,89 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -399,6 +800,9 @@ packages: '@next/env@16.1.6': resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} + '@next/eslint-plugin-next@16.1.6': + resolution: {integrity: sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==} + '@next/swc-darwin-arm64@16.1.6': resolution: {integrity: sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==} engines: {node: '>= 10'} @@ -416,28 +820,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@next/swc-linux-arm64-musl@16.1.6': resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@next/swc-linux-x64-gnu@16.1.6': resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@next/swc-linux-x64-musl@16.1.6': resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@next/swc-win32-arm64-msvc@16.1.6': resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} @@ -451,6 +851,37 @@ packages: cpu: [x64] os: [win32] + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@oslojs/asn1@1.0.0': + resolution: {integrity: sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==} + + '@oslojs/binary@1.0.0': + resolution: {integrity: sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==} + + '@oslojs/crypto@1.0.0': + resolution: {integrity: sha512-dVz8TkkgYdr3tlwxHd7SCYGxoN7ynwHLA0nei/Aq9C+ERU0BK+U8+/3soEzBUxUNKYBf42351DyJUZ2REla50w==} + + '@oslojs/encoding@1.0.0': + resolution: {integrity: sha512-dyIB0SdZgMm5BhGwdSp8rMxEFIopLKxDG1vxIBaiogyom6ZqH2aXPb6DEC2WzOOWKdPSq1cxdNeRx2wAn1Z+ZQ==} + + '@oslojs/otp@1.1.0': + resolution: {integrity: sha512-tpdxlnCLcY6IZLLqH8kGD8PSvIVyev/+Gbglgvrk9e4YzgKO7+7FL8NWBofL7LZI6MgQ1HnNUuotRG6t1JJ0dg==} + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -684,6 +1115,11 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-icons@1.3.2': + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + '@radix-ui/react-id@1.1.1': resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: @@ -1107,79 +1543,337 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - - '@tailwindcss/node@4.2.0': - resolution: {integrity: sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==} + '@simplewebauthn/browser@11.0.0': + resolution: {integrity: sha512-KEGCStrl08QC2I561BzxqGiwoknblP6O1YW7jApdXLPtIqZ+vgJYAv8ssLCdm1wD8HGAHd49CJLkUF8X70x/pg==} - '@tailwindcss/oxide-android-arm64@4.2.0': - resolution: {integrity: sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] + '@simplewebauthn/browser@13.2.2': + resolution: {integrity: sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==} - '@tailwindcss/oxide-darwin-arm64@4.2.0': - resolution: {integrity: sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] + '@simplewebauthn/types@11.0.0': + resolution: {integrity: sha512-b2o0wC5u2rWts31dTgBkAtSNKGX0cvL6h8QedNsKmj8O4QoLFQFR3DBVBUlpyVEhYKA+mXGUaXbcOc4JdQ3HzA==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - '@tailwindcss/oxide-darwin-x64@4.2.0': - resolution: {integrity: sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] + '@smithy/abort-controller@4.2.10': + resolution: {integrity: sha512-qocxM/X4XGATqQtUkbE9SPUB6wekBi+FyJOMbPj0AhvyvFGYEmOlz6VB22iMePCQsFmMIvFSeViDvA7mZJG47g==} + engines: {node: '>=18.0.0'} - '@tailwindcss/oxide-freebsd-x64@4.2.0': - resolution: {integrity: sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] + '@smithy/config-resolver@4.4.9': + resolution: {integrity: sha512-ejQvXqlcU30h7liR9fXtj7PIAau1t/sFbJpgWPfiYDs7zd16jpH0IsSXKcba2jF6ChTXvIjACs27kNMc5xxE2Q==} + engines: {node: '>=18.0.0'} - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0': - resolution: {integrity: sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] + '@smithy/core@3.23.6': + resolution: {integrity: sha512-4xE+0L2NrsFKpEVFlFELkIHQddBvMbQ41LRIP74dGCXnY1zQ9DgksrBcRBDJT+iOzGy4VEJIeU3hkUK5mn06kg==} + engines: {node: '>=18.0.0'} - '@tailwindcss/oxide-linux-arm64-gnu@4.2.0': - resolution: {integrity: sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [glibc] + '@smithy/credential-provider-imds@4.2.10': + resolution: {integrity: sha512-3bsMLJJLTZGZqVGGeBVFfLzuRulVsGTj12BzRKODTHqUABpIr0jMN1vN3+u6r2OfyhAQ2pXaMZWX/swBK5I6PQ==} + engines: {node: '>=18.0.0'} - '@tailwindcss/oxide-linux-arm64-musl@4.2.0': - resolution: {integrity: sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [musl] + '@smithy/fetch-http-handler@5.3.11': + resolution: {integrity: sha512-wbTRjOxdFuyEg0CpumjZO0hkUl+fetJFqxNROepuLIoijQh51aMBmzFLfoQdwRjxsuuS2jizzIUTjPWgd8pd7g==} + engines: {node: '>=18.0.0'} - '@tailwindcss/oxide-linux-x64-gnu@4.2.0': - resolution: {integrity: sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [glibc] + '@smithy/hash-node@4.2.10': + resolution: {integrity: sha512-1VzIOI5CcsvMDvP3iv1vG/RfLJVVVc67dCRyLSB2Hn9SWCZrDO3zvcIzj3BfEtqRW5kcMg5KAeVf1K3dR6nD3w==} + engines: {node: '>=18.0.0'} - '@tailwindcss/oxide-linux-x64-musl@4.2.0': - resolution: {integrity: sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [musl] + '@smithy/invalid-dependency@4.2.10': + resolution: {integrity: sha512-vy9KPNSFUU0ajFYk0sDZIYiUlAWGEAhRfehIr5ZkdFrRFTAuXEPUd41USuqHU6vvLX4r6Q9X7MKBco5+Il0Org==} + engines: {node: '>=18.0.0'} - '@tailwindcss/oxide-wasm32-wasi@4.2.0': - resolution: {integrity: sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==} + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' + + '@smithy/is-array-buffer@4.2.1': + resolution: {integrity: sha512-Yfu664Qbf1B4IYIsYgKoABt010daZjkaCRvdU/sPnZG6TtHOB0md0RjNdLGzxe5UIdn9js4ftPICzmkRa9RJ4Q==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.2.10': + resolution: {integrity: sha512-TQZ9kX5c6XbjhaEBpvhSvMEZ0klBs1CFtOdPFwATZSbC9UeQfKHPLPN9Y+I6wZGMOavlYTOlHEPDrt42PMSH9w==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.4.20': + resolution: {integrity: sha512-9W6Np4ceBP3XCYAGLoMCmn8t2RRVzuD1ndWPLBbv7H9CrwM9Bprf6Up6BM9ZA/3alodg0b7Kf6ftBK9R1N04vw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.4.37': + resolution: {integrity: sha512-/1psZZllBBSQ7+qo5+hhLz7AEPGLx3Z0+e3ramMBEuPK2PfvLK4SrncDB9VegX5mBn+oP/UTDrM6IHrFjvX1ZA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.11': + resolution: {integrity: sha512-STQdONGPwbbC7cusL60s7vOa6He6A9w2jWhoapL0mgVjmR19pr26slV+yoSP76SIssMTX/95e5nOZ6UQv6jolg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.2.10': + resolution: {integrity: sha512-pmts/WovNcE/tlyHa8z/groPeOtqtEpp61q3W0nW1nDJuMq/x+hWa/OVQBtgU0tBqupeXq0VBOLA4UZwE8I0YA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.3.10': + resolution: {integrity: sha512-UALRbJtVX34AdP2VECKVlnNgidLHA2A7YgcJzwSBg1hzmnO/bZBHl/LDQQyYifzUwp1UOODnl9JJ3KNawpUJ9w==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.4.12': + resolution: {integrity: sha512-zo1+WKJkR9x7ZtMeMDAAsq2PufwiLDmkhcjpWPRRkmeIuOm6nq1qjFICSZbnjBvD09ei8KMo26BWxsu2BUU+5w==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.10': + resolution: {integrity: sha512-5jm60P0CU7tom0eNrZ7YrkgBaoLFXzmqB0wVS+4uK8PPGmosSrLNf6rRd50UBvukztawZ7zyA8TxlrKpF5z9jw==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.3.10': + resolution: {integrity: sha512-2NzVWpYY0tRdfeCJLsgrR89KE3NTWT2wGulhNUxYlRmtRmPwLQwKzhrfVaiNlA9ZpJvbW7cjTVChYKgnkqXj1A==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.2.10': + resolution: {integrity: sha512-HeN7kEvuzO2DmAzLukE9UryiUvejD3tMp9a1D1NJETerIfKobBUCLfviP6QEk500166eD2IATaXM59qgUI+YDA==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.2.10': + resolution: {integrity: sha512-4Mh18J26+ao1oX5wXJfWlTT+Q1OpDR8ssiC9PDOuEgVBGloqg18Fw7h5Ct8DyT9NBYwJgtJ2nLjKKFU6RP1G1Q==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.2.10': + resolution: {integrity: sha512-0R/+/Il5y8nB/By90o8hy/bWVYptbIfvoTYad0igYQO5RefhNCDmNzqxaMx7K1t/QWo0d6UynqpqN5cCQt1MCg==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.4.5': + resolution: {integrity: sha512-pHgASxl50rrtOztgQCPmOXFjRW+mCd7ALr/3uXNzRrRoGV5G2+78GOsQ3HlQuBVHCh9o6xqMNvlIKZjWn4Euug==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.10': + resolution: {integrity: sha512-Wab3wW8468WqTKIxI+aZe3JYO52/RYT/8sDOdzkUhjnLakLe9qoQqIcfih/qxcF4qWEFoWBszY0mj5uxffaVXA==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.12.0': + resolution: {integrity: sha512-R8bQ9K3lCcXyZmBnQqUZJF4ChZmtWT5NLi6x5kgWx5D+/j0KorXcA0YcFg/X5TOgnTCy1tbKc6z2g2y4amFupQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.13.0': + resolution: {integrity: sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.10': + resolution: {integrity: sha512-uypjF7fCDsRk26u3qHmFI/ePL7bxxB9vKkE+2WKEciHhz+4QtbzWiHRVNRJwU3cKhrYDYQE3b0MRFtqfLYdA4A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.3.1': + resolution: {integrity: sha512-BKGuawX4Doq/bI/uEmg+Zyc36rJKWuin3py89PquXBIBqmbnJwBBsmKhdHfNEp0+A4TDgLmT/3MSKZ1SxHcR6w==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.2.1': + resolution: {integrity: sha512-SiJeLiozrAoCrgDBUgsVbmqHmMgg/2bA15AzcbcW+zan7SuyAVHN4xTSbq0GlebAIwlcaX32xacnrG488/J/6g==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.2.2': + resolution: {integrity: sha512-4rHqBvxtJEBvsZcFQSPQqXP2b/yy/YlB66KlcEgcH2WNoOKCKB03DSLzXmOsXjbl8dJ4OEYTn31knhdznwk7zw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.1': + resolution: {integrity: sha512-/swhmt1qTiVkaejlmMPPDgZhEaWb/HWMGRBheaxwuVkusp/z+ErJyQxO6kaXumOciZSWlmq6Z5mNylCd33X7Ig==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.2.1': + resolution: {integrity: sha512-462id/00U8JWFw6qBuTSWfN5TxOHvDu4WliI97qOIOnuC/g+NDAknTU8eoGXEPlLkRVgWEr03jJBLV4o2FL8+A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.3.36': + resolution: {integrity: sha512-R0smq7EHQXRVMxkAxtH5akJ/FvgAmNF6bUy/GwY/N20T4GrwjT633NFm0VuRpC+8Bbv8R9A0DoJ9OiZL/M3xew==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.2.39': + resolution: {integrity: sha512-otWuoDm35btJV1L8MyHrPl462B07QCdMTktKc7/yM+Psv6KbED/ziXiHnmr7yPHUjfIwE9S8Max0LO24Mo3ZVg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.3.1': + resolution: {integrity: sha512-xyctc4klmjmieQiF9I1wssBWleRV0RhJ2DpO8+8yzi2LO1Z+4IWOZNGZGNj4+hq9kdo+nyfrRLmQTzc16Op2Vg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.1': + resolution: {integrity: sha512-c1hHtkgAWmE35/50gmdKajgGAKV3ePJ7t6UtEmpfCWJmQE9BQAQPz0URUVI89eSkcDqCtzqllxzG28IQoZPvwA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.10': + resolution: {integrity: sha512-LxaQIWLp4y0r72eA8mwPNQ9va4h5KeLM0I3M/HV9klmFaY2kN766wf5vsTzmaOpNNb7GgXAd9a25P3h8T49PSA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.2.10': + resolution: {integrity: sha512-HrBzistfpyE5uqTwiyLsFHscgnwB0kgv8vySp7q5kZ0Eltn/tjosaSGGDj/jJ9ys7pWzIP/icE2d+7vMKXLv7A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.15': + resolution: {integrity: sha512-OlOKnaqnkU9X+6wEkd7mN+WB7orPbCVDauXOj22Q7VtiTkvy7ZdSsOg4QiNAZMgI4OkvNf+/VLUC3VXkxuWJZw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.2.1': + resolution: {integrity: sha512-YmiUDn2eo2IOiWYYvGQkgX5ZkBSiTQu4FlDo5jNPpAxng2t6Sjb6WutnZV9l6VR4eJul1ABmCrnWBC9hKHQa6Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.1': + resolution: {integrity: sha512-DSIwNaWtmzrNQHv8g7DBGR9mulSit65KSj5ymGEIAknmIN8IpbZefEep10LaMG/P/xquwbmJ1h9ectz8z6mV6g==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.1.1': + resolution: {integrity: sha512-dSfDCeihDmZlV2oyr0yWPTUfh07suS+R5OB+FZGiv/hHyK3hrFBW5rR1UYjfa57vBsrP9lciFkRPzebaV1Qujw==} + engines: {node: '>=18.0.0'} + + '@stackframe/stack-sc@2.8.71': + resolution: {integrity: sha512-Et0dTgqsm0GO7JhdmMaBES6SeqFBHtRiBMhUAGoxYLYaS8lCx2igv/NTFw9eykbIQmsZsR34EVuPiJKO4hoChw==} + peerDependencies: + '@types/react': '>=19.0.0' + '@types/react-dom': '>=19.0.0' + next: '>=14.1 || >=15.0.0-rc.0' + react: '>=19.0.0' + react-dom: '>=19.0.0' + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@stackframe/stack-shared@2.8.71': + resolution: {integrity: sha512-WIvodrQf8RGGwwMqKUYDS/WmjAkwOlrNhhvDc7T//WWDtyiKMKVKQkonGfKkB+9MY0w+hjw4LJDb6inCt3KNVA==} + peerDependencies: + '@types/react': '>=19.0.0' + '@types/react-dom': '>=19.0.0' + react: '>=19.0.0' + react-dom: '>=19.0.0' + yup: ^1.7.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + react: + optional: true + yup: + optional: true + + '@stackframe/stack-ui@2.8.71': + resolution: {integrity: sha512-2sLWyiaziWZ1bfVmtUSBYgH4XcKVtYMaKF+nfhDgBbxYoJlgp5675HtLDSzXS6H6yWzMrZrEYRVPIfpU3Bt8uA==} + peerDependencies: + '@types/react': '>=19.0.0' + '@types/react-dom': '>=19.0.0' + react: '>=19.0.0' + react-dom: '>=19.0.0' + yup: ^1.7.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + yup: + optional: true + + '@stackframe/stack@2.8.71': + resolution: {integrity: sha512-12HbcCCiIMkghf3i1OGOFJFhUwWA2NHVsm0Z7SUU71YV2xxIuBm/MyD5bJJ4Qf136KrRKJpzq8oj2zssy6+VXQ==} + peerDependencies: + '@types/react': '>=18.3.0' + '@types/react-dom': '>=18.3.0' + next: '>=14.1 || >=15.0.0-canary.0 || >=15.0.0-rc.0' + react: '>=18.3.0' + react-dom: '>=18.3.0' + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@stripe/react-stripe-js@3.10.0': + resolution: {integrity: sha512-UPqHZwMwDzGSax0ZI7XlxR3tZSpgIiZdk3CiwjbTK978phwR/fFXeAXQcN/h8wTAjR4ZIAzdlI9DbOqJhuJdeg==} + peerDependencies: + '@stripe/stripe-js': '>=1.44.1 <8.0.0' + react: '>=16.8.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@stripe/stripe-js@7.9.0': + resolution: {integrity: sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ==} + engines: {node: '>=12.16'} + + '@stripe/stripe-js@8.8.0': + resolution: {integrity: sha512-NNYuyW8qmLjyHnpyFgs/23wUrjB8k0xN9YIZFOMLewCa/pIkIji9e9aY/EgdNryEDDRptc6TcPIHRvG1R0ClFw==} + engines: {node: '>=12.16'} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/node@4.2.0': + resolution: {integrity: sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==} + + '@tailwindcss/oxide-android-arm64@4.2.0': + resolution: {integrity: sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.0': + resolution: {integrity: sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.0': + resolution: {integrity: sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.0': + resolution: {integrity: sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0': + resolution: {integrity: sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.0': + resolution: {integrity: sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.0': + resolution: {integrity: sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.0': + resolution: {integrity: sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.2.0': + resolution: {integrity: sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.2.0': + resolution: {integrity: sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' - '@emnapi/wasi-threads' - tslib @@ -1202,6 +1896,20 @@ packages: '@tailwindcss/postcss@4.2.0': resolution: {integrity: sha512-u6YBacGpOm/ixPfKqfgrJEjMfrYmPD7gEFRoygS/hnQaRtV0VCBdpkx5Ouw9pnaLRwwlgGCuJw8xLpaR0hOrQg==} + '@tanstack/react-table@8.21.3': + resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + + '@types/css-font-loading-module@0.0.7': + resolution: {integrity: sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==} + '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -1229,6 +1937,18 @@ packages: '@types/d3-timer@3.0.2': resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@22.19.11': resolution: {integrity: sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==} @@ -1240,6 +1960,65 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@typescript-eslint/eslint-plugin@8.56.1': + resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.56.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.56.1': + resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.56.1': + resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vercel/analytics@1.6.1': resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} peerDependencies: @@ -1270,10 +2049,50 @@ packages: resolution: {integrity: sha512-uTVskvD94ZtKsX28M6TSt6GJKe7TOumys4H6GMwa+olBsQt9WGx6+ex1g+OR8bjhnA3EuF8MCehM3ZMtIblUDg==} engines: {node: '>=16.14'} + '@vercel/functions@2.2.13': + resolution: {integrity: sha512-14ArBSIIcOBx9nrEgaJb4Bw+en1gl6eSoJWh8qjifLl5G3E4dRXCFOT8HP+w66vb9Wqyd1lAQBrmRhRwOj9X9A==} + engines: {node: '>= 18'} + peerDependencies: + '@aws-sdk/credential-provider-web-identity': '*' + peerDependenciesMeta: + '@aws-sdk/credential-provider-web-identity': + optional: true + + '@vercel/oidc@2.0.2': + resolution: {integrity: sha512-59PBFx3T+k5hLTEWa3ggiMpGRz1OVvl9eN8SUai+A43IsqiOuAe7qPBf+cray/Fj6mkgnxm/D7IAtjc8zSHi7g==} + engines: {node: '>= 18'} + + '@xstate/fsm@1.6.5': + resolution: {integrity: sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + aria-hidden@1.2.6: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} @@ -1284,11 +2103,43 @@ packages: peerDependencies: postcss: ^8.1.0 + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-arraybuffer@1.0.2: + resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} + engines: {node: '>= 0.6.0'} + baseline-browser-mapping@2.10.0: resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} engines: {node: '>=6.0.0'} hasBin: true + bcryptjs@3.0.3: + resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==} + hasBin: true + + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + brace-expansion@5.0.3: + resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browser-image-compression@2.0.2: + resolution: {integrity: sha512-pBLlQyUf6yB8SmmngrcOw3EoS4RpQ1BcylI3T9Yqn7+4nrQTXJD4sJDe5ODnJdrvNMaio5OicFo75rDyJD2Ucw==} + browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -1298,6 +2149,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + caniuse-lite@1.0.30001770: resolution: {integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==} @@ -1307,6 +2162,9 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1317,6 +2175,49 @@ packages: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-convert@3.1.3: + resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} + engines: {node: '>=14.6'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-name@2.1.0: + resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} + engines: {node: '>=12.20'} + + color-string@2.1.4: + resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} + engines: {node: '>=18'} + + color@5.0.3: + resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} + engines: {node: '>=18'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + crc@4.3.2: + resolution: {integrity: sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==} + engines: {node: '>=12'} + peerDependencies: + buffer: '>=6.0.3' + peerDependenciesMeta: + buffer: + optional: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -1367,12 +2268,31 @@ packages: date-fns-jalali@4.1.0-0: resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -1380,12 +2300,18 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} electron-to-chromium@1.5.302: resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + embla-carousel-react@8.6.0: resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==} peerDependencies: @@ -1399,31 +2325,198 @@ packages: embla-carousel@8.6.0: resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + enhanced-resolve@5.19.0: resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} + esbuild-wasm@0.20.2: + resolution: {integrity: sha512-7o6nmsEqlcXJXMNqnx5K+M4w4OPx7yTFXQHcJyeP3SkXb8p2T8N9E1ayK4vd/qDBepH6fuPoZwiFvZm8x5qv+w==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-scope@9.1.1: + resolution: {integrity: sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.0.2: + resolution: {integrity: sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.1.1: + resolution: {integrity: sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + export-to-csv@1.4.0: + resolution: {integrity: sha512-6CX17Cu+rC2Fi2CyZ4CkgVG3hLl6BFsdAxfXiZkmDFIDY4mRx2y2spdeH6dqPHI9rP+AsHEfGeKz84Uuw7+Pmg==} + engines: {node: ^v12.20.0 || >=v14.13.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-equals@5.4.0: resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} engines: {node: '>=6.0.0'} + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-xml-parser@5.3.6: + resolution: {integrity: sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==} + hasBin: true + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + input-otp@1.4.2: resolution: {integrity: sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==} peerDependencies: @@ -1434,13 +2527,69 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} + ip-regex@5.0.0: + resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + lightningcss-android-arm64@1.31.1: resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} engines: {node: '>= 12.0.0'} @@ -1476,28 +2625,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.31.1: resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.31.1: resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.31.1: resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.31.1: resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} @@ -1515,6 +2660,14 @@ packages: resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} engines: {node: '>= 12.0.0'} + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + lodash@4.17.23: resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} @@ -1522,6 +2675,23 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.378.0: + resolution: {integrity: sha512-u6EPU8juLUk9ytRcyapkWI18epAv3RU+6+TC23ivjR0e+glWKBobFeSgRwOIJihzktILQuy6E0E80P2jVTDR5g==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + + lucide-react@0.508.0: + resolution: {integrity: sha512-gcP16PnexqtOFrTtv98kVsGzTfnbPekzZiQfByi2S89xfk7E/4uKE1USZqccIp58v42LqkO7MuwpCqshwSrJCg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lucide-react@0.564.0: resolution: {integrity: sha512-JJ8GVTQqFwuliifD48U6+h7DXEHdkhJ/E87kksGByII3qHxtPciVb8T8woQONHBQgHVOl7rSMrrip3SeVNy7Fg==} peerDependencies: @@ -1530,11 +2700,42 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@10.2.2: + resolution: {integrity: sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==} + engines: {node: 18 || 20 || >=22} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mitt@1.2.0: + resolution: {integrity: sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + next-themes@0.4.6: resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} peerDependencies: @@ -1565,10 +2766,55 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + normalize-wheel@1.0.1: + resolution: {integrity: sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==} + + oauth4webapi@3.8.5: + resolution: {integrity: sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -1606,6 +2852,18 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -1633,9 +2891,28 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-expr@2.0.6: + resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-day-picker@9.13.2: resolution: {integrity: sha512-IMPiXfXVIAuR5Yk58DDPBC8QKClrhdXV+Tr/alBrwrHUw0qDDYB1m5zPNuTnnPIr/gmJ4ChMxmtqPdxm8+R4Eg==} engines: {node: '>=18'} @@ -1647,6 +2924,12 @@ packages: peerDependencies: react: ^19.2.4 + react-easy-crop@5.5.6: + resolution: {integrity: sha512-Jw3/ozs8uXj3NpL511Suc4AHY+mLRO23rUgipXvNYKqezcFSYHxe4QXibBymkOoY6oOtLVMPO2HNPRHYvMPyTw==} + peerDependencies: + react: '>=16.4.0' + react-dom: '>=16.4.0' + react-hook-form@7.71.2: resolution: {integrity: sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==} engines: {node: '>=18.0.0'} @@ -1721,22 +3004,65 @@ packages: react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@6.1.3: + resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} + engines: {node: 20 || >=22} + hasBin: true + + rrweb-snapshot@1.1.14: + resolution: {integrity: sha512-eP5pirNjP5+GewQfcOQY4uBiDnpqxNRc65yKPW0eSoU1XamDfc4M8oqpXGMyUyvLyxFDB0q0+DChuxxiU2FXBQ==} + + rrweb@1.1.3: + resolution: {integrity: sha512-F2qp8LteJLyycsv+lCVJqtVpery63L3U+/ogqMA0da8R7Jx57o6gT+HpjrzdeeGMIBZR7kKNaKyJwDupTTu5KA==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + semver@7.7.4: resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + sharp@0.34.5: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + sonner@1.7.4: resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} peerDependencies: @@ -1751,6 +3077,26 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + stripe@20.3.1: + resolution: {integrity: sha512-k990yOT5G5rhX3XluRPw5Y8RLdJDW4dzQ29wWT66piHrbnM2KyamJ1dKgPsw4HzGHRWjDiSSdcI2WdxQUPV3aQ==} + engines: {node: '>=16'} + peerDependencies: + '@types/node': '>=16' + peerDependenciesMeta: + '@types/node': + optional: true + + strnum@2.1.2: + resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} + styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -1764,9 +3110,17 @@ packages: babel-plugin-macros: optional: true + tailwind-merge@2.6.1: + resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} + tailwind-merge@3.5.0: resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + tailwindcss@4.2.0: resolution: {integrity: sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q==} @@ -1774,15 +3128,55 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tiny-case@1.0.3: + resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toposort@2.0.2: + resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} + + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + tw-animate-css@1.3.3: resolution: {integrity: sha512-tXE2TRWrskc4TU3RDd7T8n8Np/wCfoeH9gz22c7PzYqNPQ9FBGFbWWzwL0JyHcFp+jHozmF76tbHfPAx22ua2Q==} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + typescript-eslint@8.56.1: + resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + typescript@5.7.3: resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} engines: {node: '>=14.17'} @@ -1801,6 +3195,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -1826,6 +3223,13 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + + uzip@0.20201231.0: + resolution: {integrity: sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng==} + vaul@1.1.2: resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} peerDependencies: @@ -1835,10 +3239,47 @@ packages: victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yup@1.7.1: + resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==} + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -1846,8 +3287,432 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.2 + '@aws-sdk/util-locate-window': 3.965.4 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.2 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.2 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-kms@3.997.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.13 + '@aws-sdk/credential-provider-node': 3.972.12 + '@aws-sdk/middleware-host-header': 3.972.4 + '@aws-sdk/middleware-logger': 3.972.4 + '@aws-sdk/middleware-recursion-detection': 3.972.4 + '@aws-sdk/middleware-user-agent': 3.972.13 + '@aws-sdk/region-config-resolver': 3.972.4 + '@aws-sdk/types': 3.973.2 + '@aws-sdk/util-endpoints': 3.996.1 + '@aws-sdk/util-user-agent-browser': 3.972.4 + '@aws-sdk/util-user-agent-node': 3.972.12 + '@smithy/config-resolver': 4.4.9 + '@smithy/core': 3.23.6 + '@smithy/fetch-http-handler': 5.3.11 + '@smithy/hash-node': 4.2.10 + '@smithy/invalid-dependency': 4.2.10 + '@smithy/middleware-content-length': 4.2.10 + '@smithy/middleware-endpoint': 4.4.20 + '@smithy/middleware-retry': 4.4.37 + '@smithy/middleware-serde': 4.2.11 + '@smithy/middleware-stack': 4.2.10 + '@smithy/node-config-provider': 4.3.10 + '@smithy/node-http-handler': 4.4.12 + '@smithy/protocol-http': 5.3.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + '@smithy/util-base64': 4.3.1 + '@smithy/util-body-length-browser': 4.2.1 + '@smithy/util-body-length-node': 4.2.2 + '@smithy/util-defaults-mode-browser': 4.3.36 + '@smithy/util-defaults-mode-node': 4.2.39 + '@smithy/util-endpoints': 3.3.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-retry': 4.2.10 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.973.13': + dependencies: + '@aws-sdk/types': 3.973.2 + '@aws-sdk/xml-builder': 3.972.6 + '@smithy/core': 3.23.6 + '@smithy/node-config-provider': 4.3.10 + '@smithy/property-provider': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/signature-v4': 5.3.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.11': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/types': 3.973.2 + '@smithy/property-provider': 4.2.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.13': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/types': 3.973.2 + '@smithy/fetch-http-handler': 5.3.11 + '@smithy/node-http-handler': 4.4.12 + '@smithy/property-provider': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/util-stream': 4.5.15 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.11': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/credential-provider-env': 3.972.11 + '@aws-sdk/credential-provider-http': 3.972.13 + '@aws-sdk/credential-provider-login': 3.972.11 + '@aws-sdk/credential-provider-process': 3.972.11 + '@aws-sdk/credential-provider-sso': 3.972.11 + '@aws-sdk/credential-provider-web-identity': 3.972.11 + '@aws-sdk/nested-clients': 3.996.1 + '@aws-sdk/types': 3.973.2 + '@smithy/credential-provider-imds': 4.2.10 + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-login@3.972.11': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/nested-clients': 3.996.1 + '@aws-sdk/types': 3.973.2 + '@smithy/property-provider': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.972.12': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.11 + '@aws-sdk/credential-provider-http': 3.972.13 + '@aws-sdk/credential-provider-ini': 3.972.11 + '@aws-sdk/credential-provider-process': 3.972.11 + '@aws-sdk/credential-provider-sso': 3.972.11 + '@aws-sdk/credential-provider-web-identity': 3.972.11 + '@aws-sdk/types': 3.973.2 + '@smithy/credential-provider-imds': 4.2.10 + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.972.11': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/types': 3.973.2 + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.11': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/nested-clients': 3.996.1 + '@aws-sdk/token-providers': 3.997.0 + '@aws-sdk/types': 3.973.2 + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.972.11': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/nested-clients': 3.996.1 + '@aws-sdk/types': 3.973.2 + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/middleware-host-header@3.972.4': + dependencies: + '@aws-sdk/types': 3.973.2 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.972.4': + dependencies: + '@aws-sdk/types': 3.973.2 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.972.4': + dependencies: + '@aws-sdk/types': 3.973.2 + '@aws/lambda-invoke-store': 0.2.3 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.972.13': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/types': 3.973.2 + '@aws-sdk/util-endpoints': 3.996.1 + '@smithy/core': 3.23.6 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.996.1': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.13 + '@aws-sdk/middleware-host-header': 3.972.4 + '@aws-sdk/middleware-logger': 3.972.4 + '@aws-sdk/middleware-recursion-detection': 3.972.4 + '@aws-sdk/middleware-user-agent': 3.972.13 + '@aws-sdk/region-config-resolver': 3.972.4 + '@aws-sdk/types': 3.973.2 + '@aws-sdk/util-endpoints': 3.996.1 + '@aws-sdk/util-user-agent-browser': 3.972.4 + '@aws-sdk/util-user-agent-node': 3.972.12 + '@smithy/config-resolver': 4.4.9 + '@smithy/core': 3.23.6 + '@smithy/fetch-http-handler': 5.3.11 + '@smithy/hash-node': 4.2.10 + '@smithy/invalid-dependency': 4.2.10 + '@smithy/middleware-content-length': 4.2.10 + '@smithy/middleware-endpoint': 4.4.20 + '@smithy/middleware-retry': 4.4.37 + '@smithy/middleware-serde': 4.2.11 + '@smithy/middleware-stack': 4.2.10 + '@smithy/node-config-provider': 4.3.10 + '@smithy/node-http-handler': 4.4.12 + '@smithy/protocol-http': 5.3.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + '@smithy/util-base64': 4.3.1 + '@smithy/util-body-length-browser': 4.2.1 + '@smithy/util-body-length-node': 4.2.2 + '@smithy/util-defaults-mode-browser': 4.3.36 + '@smithy/util-defaults-mode-node': 4.2.39 + '@smithy/util-endpoints': 3.3.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-retry': 4.2.10 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.972.4': + dependencies: + '@aws-sdk/types': 3.973.2 + '@smithy/config-resolver': 4.4.9 + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.997.0': + dependencies: + '@aws-sdk/core': 3.973.13 + '@aws-sdk/nested-clients': 3.996.1 + '@aws-sdk/types': 3.973.2 + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.973.2': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.996.1': + dependencies: + '@aws-sdk/types': 3.973.2 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + '@smithy/util-endpoints': 3.3.1 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.4': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.972.4': + dependencies: + '@aws-sdk/types': 3.973.2 + '@smithy/types': 4.13.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.972.12': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.13 + '@aws-sdk/types': 3.973.2 + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.6': + dependencies: + '@smithy/types': 4.13.0 + fast-xml-parser: 5.3.6 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.3': {} + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + '@babel/runtime@7.28.6': {} + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@date-fns/tz@1.4.1': {} '@emnapi/runtime@1.8.1': @@ -1855,6 +3720,118 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@10.0.2(jiti@2.6.1))': + dependencies: + eslint: 10.0.2(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.2': + dependencies: + '@eslint/object-schema': 3.0.2 + debug: 4.4.3 + minimatch: 10.2.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.5.2': + dependencies: + '@eslint/core': 1.1.0 + + '@eslint/core@1.1.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/js@10.0.1(eslint@10.0.2(jiti@2.6.1))': + optionalDependencies: + eslint: 10.0.2(jiti@2.6.1) + + '@eslint/object-schema@3.0.2': {} + + '@eslint/plugin-kit@0.6.0': + dependencies: + '@eslint/core': 1.1.0 + levn: 0.4.1 + '@fastify/busboy@2.1.1': {} '@floating-ui/core@1.7.4': @@ -1878,6 +3855,22 @@ snapshots: dependencies: react-hook-form: 7.71.2(react@19.2.4) + '@hookform/resolvers@5.2.2(react-hook-form@7.71.2(react@19.2.4))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.71.2(react@19.2.4) + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@img/colour@1.0.0': optional: true @@ -1996,6 +3989,10 @@ snapshots: '@next/env@16.1.6': {} + '@next/eslint-plugin-next@16.1.6': + dependencies: + fast-glob: 3.3.1 + '@next/swc-darwin-arm64@16.1.6': optional: true @@ -2020,6 +4017,39 @@ snapshots: '@next/swc-win32-x64-msvc@16.1.6': optional: true + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@opentelemetry/api@1.9.0': {} + + '@oslojs/asn1@1.0.0': + dependencies: + '@oslojs/binary': 1.0.0 + + '@oslojs/binary@1.0.0': {} + + '@oslojs/crypto@1.0.0': + dependencies: + '@oslojs/asn1': 1.0.0 + '@oslojs/binary': 1.0.0 + + '@oslojs/encoding@1.0.0': {} + + '@oslojs/otp@1.1.0': + dependencies: + '@oslojs/binary': 1.0.0 + '@oslojs/crypto': 1.0.0 + '@oslojs/encoding': 1.0.0 + '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.3': {} @@ -2252,6 +4282,10 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) + '@radix-ui/react-icons@1.3.2(react@19.2.4)': + dependencies: + react: 19.2.4 + '@radix-ui/react-id@1.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) @@ -2715,6 +4749,438 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@simplewebauthn/browser@11.0.0': + dependencies: + '@simplewebauthn/types': 11.0.0 + + '@simplewebauthn/browser@13.2.2': {} + + '@simplewebauthn/types@11.0.0': {} + + '@smithy/abort-controller@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/config-resolver@4.4.9': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-config-provider': 4.2.1 + '@smithy/util-endpoints': 3.3.1 + '@smithy/util-middleware': 4.2.10 + tslib: 2.8.1 + + '@smithy/core@3.23.6': + dependencies: + '@smithy/middleware-serde': 4.2.11 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + '@smithy/util-body-length-browser': 4.2.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-stream': 4.5.15 + '@smithy/util-utf8': 4.2.1 + '@smithy/uuid': 1.1.1 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.2.10': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/property-provider': 4.2.10 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.3.11': + dependencies: + '@smithy/protocol-http': 5.3.10 + '@smithy/querystring-builder': 4.2.10 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + tslib: 2.8.1 + + '@smithy/hash-node@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + '@smithy/util-buffer-from': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.2.10': + dependencies: + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.4.20': + dependencies: + '@smithy/core': 3.23.6 + '@smithy/middleware-serde': 4.2.11 + '@smithy/node-config-provider': 4.3.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + '@smithy/url-parser': 4.2.10 + '@smithy/util-middleware': 4.2.10 + tslib: 2.8.1 + + '@smithy/middleware-retry@4.4.37': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/service-error-classification': 4.2.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-retry': 4.2.10 + '@smithy/uuid': 1.1.1 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.2.11': + dependencies: + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.3.10': + dependencies: + '@smithy/property-provider': 4.2.10 + '@smithy/shared-ini-file-loader': 4.4.5 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.4.12': + dependencies: + '@smithy/abort-controller': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/querystring-builder': 4.2.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.3.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + '@smithy/util-uri-escape': 4.2.1 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/service-error-classification@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + + '@smithy/shared-ini-file-loader@4.4.5': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.3.10': + dependencies: + '@smithy/is-array-buffer': 4.2.1 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-hex-encoding': 4.2.1 + '@smithy/util-middleware': 4.2.10 + '@smithy/util-uri-escape': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/smithy-client@4.12.0': + dependencies: + '@smithy/core': 3.23.6 + '@smithy/middleware-endpoint': 4.4.20 + '@smithy/middleware-stack': 4.2.10 + '@smithy/protocol-http': 5.3.10 + '@smithy/types': 4.13.0 + '@smithy/util-stream': 4.5.15 + tslib: 2.8.1 + + '@smithy/types@4.13.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.2.10': + dependencies: + '@smithy/querystring-parser': 4.2.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.3.1': + dependencies: + '@smithy/util-buffer-from': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.2.1': + dependencies: + '@smithy/is-array-buffer': 4.2.1 + tslib: 2.8.1 + + '@smithy/util-config-provider@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@4.3.36': + dependencies: + '@smithy/property-provider': 4.2.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.2.39': + dependencies: + '@smithy/config-resolver': 4.4.9 + '@smithy/credential-provider-imds': 4.2.10 + '@smithy/node-config-provider': 4.3.10 + '@smithy/property-provider': 4.2.10 + '@smithy/smithy-client': 4.12.0 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-endpoints@3.3.1': + dependencies: + '@smithy/node-config-provider': 4.3.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@4.2.10': + dependencies: + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-retry@4.2.10': + dependencies: + '@smithy/service-error-classification': 4.2.10 + '@smithy/types': 4.13.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.5.15': + dependencies: + '@smithy/fetch-http-handler': 5.3.11 + '@smithy/node-http-handler': 4.4.12 + '@smithy/types': 4.13.0 + '@smithy/util-base64': 4.3.1 + '@smithy/util-buffer-from': 4.2.1 + '@smithy/util-hex-encoding': 4.2.1 + '@smithy/util-utf8': 4.2.1 + tslib: 2.8.1 + + '@smithy/util-uri-escape@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.2.1': + dependencies: + '@smithy/util-buffer-from': 4.2.1 + tslib: 2.8.1 + + '@smithy/uuid@1.1.1': + dependencies: + tslib: 2.8.1 + + '@stackframe/stack-sc@2.8.71(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + next: 16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + + '@stackframe/stack-shared@2.8.71(@aws-sdk/credential-provider-web-identity@3.972.11)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yup@1.7.1)': + dependencies: + '@aws-sdk/client-kms': 3.997.0 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@opentelemetry/api': 1.9.0 + '@simplewebauthn/browser': 11.0.0 + '@vercel/functions': 2.2.13(@aws-sdk/credential-provider-web-identity@3.972.11) + async-mutex: 0.5.0 + bcryptjs: 3.0.3 + crc: 4.3.2 + elliptic: 6.6.1 + esbuild-wasm: 0.20.2 + ip-regex: 5.0.0 + jose: 6.1.3 + oauth4webapi: 3.8.5 + react-dom: 19.2.4(react@19.2.4) + semver: 7.7.4 + uuid: 9.0.1 + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + react: 19.2.4 + yup: 1.7.1 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-web-identity' + - aws-crt + - buffer + - supports-color + + '@stackframe/stack-ui@2.8.71(@aws-sdk/credential-provider-web-identity@3.972.11)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yup@1.7.1)': + dependencies: + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-aspect-ratio': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-avatar': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-context': 1.1.3(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-icons': 1.3.2(react@19.2.4) + '@radix-ui/react-label': 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-progress': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-select': 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-separator': 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@stackframe/stack-shared': 2.8.71(@aws-sdk/credential-provider-web-identity@3.972.11)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yup@1.7.1) + '@tanstack/react-table': 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + cmdk: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + date-fns: 3.6.0 + export-to-csv: 1.4.0 + input-otp: 1.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + lucide-react: 0.508.0(react@19.2.4) + react: 19.2.4 + react-day-picker: 9.13.2(react@19.2.4) + react-dom: 19.2.4(react@19.2.4) + react-hook-form: 7.71.2(react@19.2.4) + react-resizable-panels: 2.1.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + tailwind-merge: 2.6.1 + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + yup: 1.7.1 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-web-identity' + - aws-crt + - buffer + - supports-color + + '@stackframe/stack@2.8.71(@aws-sdk/credential-provider-web-identity@3.972.11)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.2.0)': + dependencies: + '@hookform/resolvers': 5.2.2(react-hook-form@7.71.2(react@19.2.4)) + '@oslojs/otp': 1.1.0 + '@simplewebauthn/browser': 13.2.2 + '@stackframe/stack-sc': 2.8.71(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@stackframe/stack-shared': 2.8.71(@aws-sdk/credential-provider-web-identity@3.972.11)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yup@1.7.1) + '@stackframe/stack-ui': 2.8.71(@aws-sdk/credential-provider-web-identity@3.972.11)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(yup@1.7.1) + '@stripe/react-stripe-js': 3.10.0(@stripe/stripe-js@7.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@stripe/stripe-js': 7.9.0 + '@tanstack/react-table': 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + browser-image-compression: 2.0.2 + color: 5.0.3 + cookie: 1.1.1 + jose: 6.1.3 + js-cookie: 3.0.5 + lucide-react: 0.378.0(react@19.2.4) + next: 16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + oauth4webapi: 3.8.5 + qrcode: 1.5.4 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-easy-crop: 5.5.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-hook-form: 7.71.2(react@19.2.4) + rimraf: 6.1.3 + rrweb: 1.1.3 + tailwindcss-animate: 1.0.7(tailwindcss@4.2.0) + tsx: 4.21.0 + yup: 1.7.1 + optionalDependencies: + '@types/react': 19.2.14 + '@types/react-dom': 19.2.3(@types/react@19.2.14) + transitivePeerDependencies: + - '@aws-sdk/credential-provider-web-identity' + - aws-crt + - buffer + - supports-color + - tailwindcss + + '@standard-schema/utils@0.3.0': {} + + '@stripe/react-stripe-js@3.10.0(@stripe/stripe-js@7.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@stripe/stripe-js': 7.9.0 + prop-types: 15.8.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@stripe/stripe-js@7.9.0': {} + + '@stripe/stripe-js@8.8.0': {} + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -2788,6 +5254,16 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.2.0 + '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/table-core': 8.21.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/table-core@8.21.3': {} + + '@types/css-font-loading-module@0.0.7': {} + '@types/d3-array@3.2.2': {} '@types/d3-color@3.1.3': {} @@ -2812,33 +5288,168 @@ snapshots: '@types/d3-timer@3.0.2': {} + '@types/esrecurse@4.3.1': {} + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/ms@2.1.0': {} + '@types/node@22.19.11': dependencies: - undici-types: 6.21.0 + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3))(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/type-utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) + '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.56.1 + eslint: 10.0.2(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.56.1 + debug: 4.4.3 + eslint: 10.0.2(jiti@2.6.1) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.56.1(typescript@5.7.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.7.3) + '@typescript-eslint/types': 8.56.1 + debug: 4.4.3 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.7.3)': + dependencies: + typescript: 5.7.3 + + '@typescript-eslint/type-utils@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3) + '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) + debug: 4.4.3 + eslint: 10.0.2(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.56.1': {} + + '@typescript-eslint/typescript-estree@8.56.1(typescript@5.7.3)': + dependencies: + '@typescript-eslint/project-service': 8.56.1(typescript@5.7.3) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.7.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + debug: 4.4.3 + minimatch: 10.2.2 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3) + eslint: 10.0.2(jiti@2.6.1) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + eslint-visitor-keys: 5.0.1 + + '@vercel/analytics@1.6.1(next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + optionalDependencies: + next: 16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + + '@vercel/blob@0.21.0': + dependencies: + async-retry: 1.3.3 + bytes: 3.1.2 + undici: 5.28.2 + + '@vercel/functions@2.2.13(@aws-sdk/credential-provider-web-identity@3.972.11)': + dependencies: + '@vercel/oidc': 2.0.2 + optionalDependencies: + '@aws-sdk/credential-provider-web-identity': 3.972.11 + + '@vercel/oidc@2.0.2': + dependencies: + '@types/ms': 2.1.0 + ms: 2.1.3 - '@types/react-dom@19.2.3(@types/react@19.2.14)': + '@xstate/fsm@1.6.5': {} + + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - '@types/react': 19.2.14 + acorn: 8.16.0 - '@types/react@19.2.14': + acorn@8.16.0: {} + + ajv@6.14.0: dependencies: - csstype: 3.2.3 + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 - '@vercel/analytics@1.6.1(next@16.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': - optionalDependencies: - next: 16.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 + ansi-regex@5.0.1: {} - '@vercel/blob@0.21.0': + ansi-styles@4.3.0: dependencies: - async-retry: 1.3.3 - bytes: 3.1.2 - undici: 5.28.2 + color-convert: 2.0.1 aria-hidden@1.2.6: dependencies: tslib: 2.8.1 + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + async-retry@1.3.3: dependencies: retry: 0.13.1 @@ -2852,8 +5463,32 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 + balanced-match@4.0.4: {} + + base64-arraybuffer@1.0.2: {} + baseline-browser-mapping@2.10.0: {} + bcryptjs@3.0.3: {} + + bn.js@4.12.3: {} + + bowser@2.14.1: {} + + brace-expansion@5.0.3: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brorand@1.1.0: {} + + browser-image-compression@2.0.2: + dependencies: + uzip: 0.20201231.0 + browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.10.0 @@ -2864,6 +5499,8 @@ snapshots: bytes@3.1.2: {} + camelcase@5.3.1: {} + caniuse-lite@1.0.30001770: {} class-variance-authority@0.7.1: @@ -2872,6 +5509,12 @@ snapshots: client-only@0.0.1: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + clsx@2.1.1: {} cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): @@ -2886,6 +5529,39 @@ snapshots: - '@types/react' - '@types/react-dom' + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-convert@3.1.3: + dependencies: + color-name: 2.1.0 + + color-name@1.1.4: {} + + color-name@2.1.0: {} + + color-string@2.1.4: + dependencies: + color-name: 2.1.0 + + color@5.0.3: + dependencies: + color-convert: 3.1.3 + color-string: 2.1.4 + + convert-source-map@2.0.0: {} + + cookie@1.1.1: {} + + crc@4.3.2: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + csstype@3.2.3: {} d3-array@3.2.4: @@ -2928,14 +5604,26 @@ snapshots: date-fns-jalali@4.1.0-0: {} + date-fns@3.6.0: {} + date-fns@4.1.0: {} + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + decimal.js-light@2.5.1: {} + deep-is@0.1.4: {} + detect-libc@2.1.2: {} detect-node-es@1.1.0: {} + dijkstrajs@1.0.3: {} + dom-helpers@5.2.1: dependencies: '@babel/runtime': 7.28.6 @@ -2943,6 +5631,16 @@ snapshots: electron-to-chromium@1.5.302: {} + elliptic@6.6.1: + dependencies: + bn.js: 4.12.3 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + embla-carousel-react@8.6.0(react@19.2.4): dependencies: embla-carousel: 8.6.0 @@ -2955,23 +5653,223 @@ snapshots: embla-carousel@8.6.0: {} + emoji-regex@8.0.0: {} + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 + esbuild-wasm@0.20.2: {} + + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + escalade@3.2.0: {} + escape-string-regexp@4.0.0: {} + + eslint-scope@9.1.1: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.8 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.0.2(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.2 + '@eslint/config-helpers': 0.5.2 + '@eslint/core': 1.1.0 + '@eslint/plugin-kit': 0.6.0 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.14.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.1 + eslint-visitor-keys: 5.0.1 + espree: 11.1.1 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@11.1.1: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + eventemitter3@4.0.7: {} + export-to-csv@1.4.0: {} + + fast-deep-equal@3.1.3: {} + fast-equals@5.4.0: {} + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-xml-parser@5.3.6: + dependencies: + strnum: 2.1.2 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fflate@0.4.8: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + fraction.js@5.3.4: {} + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + get-nonce@1.0.1: {} + get-tsconfig@4.13.6: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@13.0.6: + dependencies: + minimatch: 10.2.2 + minipass: 7.1.3 + path-scurry: 2.0.2 + graceful-fs@4.2.11: {} + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + input-otp@1.4.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -2979,10 +5877,47 @@ snapshots: internmap@2.0.3: {} + ip-regex@5.0.0: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + isexe@2.0.0: {} + jiti@2.6.1: {} + jose@6.1.3: {} + + js-cookie@3.0.5: {} + js-tokens@4.0.0: {} + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + lightningcss-android-arm64@1.31.1: optional: true @@ -3032,12 +5967,34 @@ snapshots: lightningcss-win32-arm64-msvc: 1.31.1 lightningcss-win32-x64-msvc: 1.31.1 + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + lodash@4.17.23: {} loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + lru-cache@11.2.6: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.378.0(react@19.2.4): + dependencies: + react: 19.2.4 + + lucide-react@0.508.0(react@19.2.4): + dependencies: + react: 19.2.4 + lucide-react@0.564.0(react@19.2.4): dependencies: react: 19.2.4 @@ -3046,14 +6003,37 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@10.2.2: + dependencies: + brace-expansion: 5.0.3 + + minipass@7.1.3: {} + + mitt@1.2.0: {} + + ms@2.1.3: {} + nanoid@3.3.11: {} + natural-compare@1.4.0: {} + next-themes@0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - next@16.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@next/env': 16.1.6 '@swc/helpers': 0.5.15 @@ -3062,7 +6042,7 @@ snapshots: postcss: 8.4.31 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - styled-jsx: 5.1.6(react@19.2.4) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) optionalDependencies: '@next/swc-darwin-arm64': 16.1.6 '@next/swc-darwin-x64': 16.1.6 @@ -3072,6 +6052,7 @@ snapshots: '@next/swc-linux-x64-musl': 16.1.6 '@next/swc-win32-arm64-msvc': 16.1.6 '@next/swc-win32-x64-msvc': 16.1.6 + '@opentelemetry/api': 1.9.0 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' @@ -3079,8 +6060,50 @@ snapshots: node-releases@2.0.27: {} + normalize-wheel@1.0.1: {} + + oauth4webapi@3.8.5: {} + object-assign@4.1.1: {} + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.2.6 + minipass: 7.1.3 + pg-cloudflare@1.3.0: optional: true @@ -3118,6 +6141,12 @@ snapshots: picocolors@1.1.1: {} + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pngjs@5.0.0: {} + postcss-value-parser@4.2.0: {} postcss@8.4.31: @@ -3142,12 +6171,26 @@ snapshots: dependencies: xtend: 4.0.2 + prelude-ls@1.2.1: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + property-expr@2.0.6: {} + + punycode@2.3.1: {} + + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + queue-microtask@1.2.3: {} + react-day-picker@9.13.2(react@19.2.4): dependencies: '@date-fns/tz': 1.4.1 @@ -3160,6 +6203,13 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 + react-easy-crop@5.5.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + normalize-wheel: 1.0.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tslib: 2.8.1 + react-hook-form@7.71.2(react@19.2.4): dependencies: react: 19.2.4 @@ -3236,12 +6286,43 @@ snapshots: tiny-invariant: 1.3.3 victory-vendor: 36.9.2 + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + + resolve-pkg-maps@1.0.0: {} + retry@0.13.1: {} + reusify@1.1.0: {} + + rimraf@6.1.3: + dependencies: + glob: 13.0.6 + package-json-from-dist: 1.0.1 + + rrweb-snapshot@1.1.14: {} + + rrweb@1.1.3: + dependencies: + '@types/css-font-loading-module': 0.0.7 + '@xstate/fsm': 1.6.5 + base64-arraybuffer: 1.0.2 + fflate: 0.4.8 + mitt: 1.2.0 + rrweb-snapshot: 1.1.14 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + scheduler@0.27.0: {} - semver@7.7.4: - optional: true + semver@6.3.1: {} + + semver@7.7.4: {} + + set-blocking@2.0.0: {} sharp@0.34.5: dependencies: @@ -3275,6 +6356,12 @@ snapshots: '@img/sharp-win32-x64': 0.34.5 optional: true + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + sonner@1.7.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -3284,23 +6371,88 @@ snapshots: split2@4.2.0: {} - styled-jsx@5.1.6(react@19.2.4): + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + stripe@20.3.1(@types/node@22.19.11): + optionalDependencies: + '@types/node': 22.19.11 + + strnum@2.1.2: {} + + styled-jsx@5.1.6(@babel/core@7.29.0)(react@19.2.4): dependencies: client-only: 0.0.1 react: 19.2.4 + optionalDependencies: + '@babel/core': 7.29.0 + + tailwind-merge@2.6.1: {} tailwind-merge@3.5.0: {} + tailwindcss-animate@1.0.7(tailwindcss@4.2.0): + dependencies: + tailwindcss: 4.2.0 + tailwindcss@4.2.0: {} tapable@2.3.0: {} + tiny-case@1.0.3: {} + tiny-invariant@1.3.3: {} + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toposort@2.0.2: {} + + ts-api-utils@2.4.0(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + tslib@2.8.1: {} + tsx@4.21.0: + dependencies: + esbuild: 0.27.3 + get-tsconfig: 4.13.6 + optionalDependencies: + fsevents: 2.3.3 + tw-animate-css@1.3.3: {} + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@2.19.0: {} + + typescript-eslint@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3))(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) + '@typescript-eslint/parser': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.7.3) + '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.7.3) + eslint: 10.0.2(jiti@2.6.1) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + typescript@5.7.3: {} undici-types@6.21.0: {} @@ -3315,6 +6467,10 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): dependencies: react: 19.2.4 @@ -3334,6 +6490,10 @@ snapshots: dependencies: react: 19.2.4 + uuid@9.0.1: {} + + uzip@0.20201231.0: {} + vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -3360,6 +6520,52 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + which-module@2.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + xtend@4.0.2: {} + y18n@4.0.3: {} + + yallist@3.1.1: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yocto-queue@0.1.0: {} + + yup@1.7.1: + dependencies: + property-expr: 2.0.6 + tiny-case: 1.0.3 + toposort: 2.0.2 + type-fest: 2.19.0 + zod@3.25.76: {} diff --git a/scripts/02-user-readiness.sql b/scripts/02-user-readiness.sql new file mode 100644 index 0000000..cd604f1 --- /dev/null +++ b/scripts/02-user-readiness.sql @@ -0,0 +1,36 @@ +-- User onboarding readiness: profile + subscription persistence + +CREATE TABLE IF NOT EXISTS public.user_profiles ( + user_id UUID PRIMARY KEY REFERENCES neon_auth."user"(id) ON DELETE CASCADE, + display_name VARCHAR(255), + company_name VARCHAR(255), + job_title VARCHAR(255), + timezone VARCHAR(100) NOT NULL DEFAULT 'UTC', + billing_email VARCHAR(255), + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS public.user_subscriptions ( + user_id UUID PRIMARY KEY REFERENCES neon_auth."user"(id) ON DELETE CASCADE, + stripe_customer_id TEXT UNIQUE, + stripe_subscription_id TEXT UNIQUE, + status VARCHAR(50) NOT NULL DEFAULT 'inactive', + plan VARCHAR(100) NOT NULL DEFAULT 'free', + current_period_end TIMESTAMP WITH TIME ZONE, + cancel_at_period_end BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX IF NOT EXISTS idx_user_profiles_billing_email + ON public.user_profiles(billing_email); + +CREATE INDEX IF NOT EXISTS idx_user_subscriptions_status + ON public.user_subscriptions(status); + +CREATE INDEX IF NOT EXISTS idx_user_subscriptions_customer + ON public.user_subscriptions(stripe_customer_id); + +ALTER TABLE public.user_profiles ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.user_subscriptions ENABLE ROW LEVEL SECURITY; diff --git a/scripts/03-onboarding.sql b/scripts/03-onboarding.sql new file mode 100644 index 0000000..34d1589 --- /dev/null +++ b/scripts/03-onboarding.sql @@ -0,0 +1,14 @@ +-- Onboarding progress tracking for activation checklist + +CREATE TABLE IF NOT EXISTS public.onboarding_progress ( + user_id UUID PRIMARY KEY REFERENCES neon_auth."user"(id) ON DELETE CASCADE, + profile_completed_at TIMESTAMP WITH TIME ZONE, + first_project_created_at TIMESTAMP WITH TIME ZONE, + first_task_created_at TIMESTAMP WITH TIME ZONE, + trial_started_at TIMESTAMP WITH TIME ZONE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX IF NOT EXISTS idx_onboarding_progress_updated_at + ON public.onboarding_progress(updated_at DESC); diff --git a/stack.ts b/stack.ts new file mode 100644 index 0000000..262310f --- /dev/null +++ b/stack.ts @@ -0,0 +1,45 @@ +import 'server-only'; + +import { StackServerApp } from '@stackframe/stack'; + +const stackProjectId = + process.env.NEXT_PUBLIC_STACK_PROJECT_ID ?? + process.env.STACK_PROJECT_ID ?? + null; + +const stackPublishableClientKey = + process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY ?? + process.env.STACK_PUBLISHED_CLIENT_KEY ?? + process.env.STACK_PUBLISHABLE_CLIENT_KEY ?? + null; + +const stackSecretServerKey = process.env.STACK_SECRET_SERVER_KEY ?? null; + +// Keep auth routes functional in build/test environments where secrets may be missing. +const fallbackProjectId = '123e4567-e89b-12d3-a456-426614174000'; +const fallbackPublishableKey = + 'pck_test_0000000000000000000000000000000000000000'; +const fallbackSecretKey = + 'ssk_test_0000000000000000000000000000000000000000'; + +export const isStackAuthConfigured = Boolean( + stackProjectId && stackPublishableClientKey && stackSecretServerKey +); + +if (!isStackAuthConfigured) { + console.warn( + 'Stack Auth is not fully configured. Set NEXT_PUBLIC_STACK_PROJECT_ID, NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY, and STACK_SECRET_SERVER_KEY.' + ); +} + +export const stackServerApp = new StackServerApp({ + tokenStore: 'nextjs-cookie', + projectId: stackProjectId ?? fallbackProjectId, + publishableClientKey: stackPublishableClientKey ?? fallbackPublishableKey, + secretServerKey: stackSecretServerKey ?? fallbackSecretKey, + urls: { + afterSignIn: '/dashboard', + afterSignUp: '/dashboard', + afterSignOut: '/', + }, +}); diff --git a/tsconfig.json b/tsconfig.json index 4b2dc7b..48d6d82 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "target": "ES6", "skipLibCheck": true, @@ -11,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -19,9 +23,19 @@ } ], "paths": { - "@/*": ["./*"] + "@/*": [ + "./*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] }