From ef38f622c374077e9b44a986b868a6495f31f04a Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:20:18 -0400 Subject: [PATCH 001/152] security: remove exposed configuration and unauthenticated test/admin routes --- .env.backup | 58 ---------- .env.cloud | 11 -- .env.example | 108 ++++++------------ .env.production | 29 ----- netlify.toml | 8 +- next.config.js | 17 +-- src/app/api/auth/test-providers/route.ts | 64 ----------- src/app/api/create-test-payment/route.ts | 46 -------- src/app/api/equipment/test-endpoint/route.ts | 106 ----------------- src/app/api/payments/test-intent/route.ts | 40 ------- src/app/api/redis-test/route.ts | 60 ---------- src/app/api/socket-debug/initialize/route.ts | 28 ----- src/app/api/socket-debug/restart/route.ts | 38 ------ src/app/api/socket-debug/status/route.ts | 17 --- src/app/api/sse/publish/route.ts | 3 + src/app/api/sse/route.ts | 6 + src/app/api/test/update-verification/route.ts | 53 --------- src/app/api/users/verify-id-basic/route.ts | 8 +- src/lib/auth/auth-options.ts | 36 +----- src/lib/db.ts | 40 +------ 20 files changed, 57 insertions(+), 719 deletions(-) delete mode 100644 .env.backup delete mode 100644 .env.cloud delete mode 100644 .env.production delete mode 100644 src/app/api/auth/test-providers/route.ts delete mode 100644 src/app/api/create-test-payment/route.ts delete mode 100644 src/app/api/equipment/test-endpoint/route.ts delete mode 100644 src/app/api/payments/test-intent/route.ts delete mode 100644 src/app/api/redis-test/route.ts delete mode 100644 src/app/api/socket-debug/initialize/route.ts delete mode 100644 src/app/api/socket-debug/restart/route.ts delete mode 100644 src/app/api/socket-debug/status/route.ts delete mode 100644 src/app/api/test/update-verification/route.ts diff --git a/.env.backup b/.env.backup deleted file mode 100644 index 4ffde4b..0000000 --- a/.env.backup +++ /dev/null @@ -1,58 +0,0 @@ -# Database configuration -DATABASE_URL="postgresql://baheemferrell:@localhost:5432/jackerbox?sslmode=prefer" -DIRECT_DATABASE_URL="postgresql://baheemferrell:@localhost:5432/jackerbox?sslmode=prefer" - -# NextAuth.js -NEXTAUTH_URL="http://localhost:3000" -NEXTAUTH_SECRET="b47d57c8e07eb57ef77d7cb9fa8412d6cd40b19a31ce00f2bb763a83ba4c8d1b" - -# Socket.IO server -SOCKET_SERVER_PORT=3002 -NEXT_PUBLIC_SOCKET_SERVER_PORT=3002 -NEXT_PUBLIC_DISABLE_SOCKET=true - -# Google OAuth -GOOGLE_CLIENT_ID="406837945822-18c6sjc7c2eabmicc3kcuk6l1ss6b0se.apps.googleusercontent.com" -GOOGLE_CLIENT_SECRET="GOCSPX-Q2NTVxLHP6rbh78xpHE4hCZRSGq" - -# Email Configuration -RESEND_API_KEY="re_8YEVJDiV_BysahcS65BYkcdXKDpVVEHus" -EMAIL_FROM="noreply@jackerbox.app" - -# Email (for development) -# EMAIL_FROM=noreply@jackerbox.local (commented out to avoid conflicts) -EMAIL_SERVER=smtp://127.0.0.1:1025 - -# Stripe (test keys for development) -STRIPE_SECRET_KEY=sk_test_dummy -STRIPE_PUBLISHABLE_KEY=pk_test_dummy -NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_dummy - -# Cloudinary (for image uploads) -NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="local-dev" -CLOUDINARY_API_KEY="dummy-key" -CLOUDINARY_API_SECRET="dummy-secret" - -# AWS (for development) -AWS_REGION="us-east-1" -AWS_ACCESS_KEY_ID="dummy-key" -AWS_SECRET_ACCESS_KEY="dummy-secret" -AWS_S3_BUCKET_NAME="jackerbox-dev" - -# Upstash Redis (for rate limiting) -# Get these values from your Upstash Redis database dashboard at https://console.upstash.com/ -# After creating a database, go to Details > REST API section -UPSTASH_REDIS_REST_URL="https://your-redis-url.upstash.io" -UPSTASH_REDIS_REST_TOKEN="your-redis-token" - -APPLE_TEAM_ID=2PF2FNX9X6 -APPLE_CLIENT_ID=com.jackerbox -APPLE_KEY_ID=HX8H87KYWG -APPLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgjlLbtFOdb20cmqfL -ESK0IB01iRrNDEZnY2meztsOENugCgYIKoZIzj0DAQehRANCAAQWADQcTbwAEUEi -9u3THkeByaDPIGVq7Nvi9oA1KY9dbn/p64K1R+fdD6CaM5J6m9fJpUQ3zoYKGHYp -c7mRl5ps ------END PRIVATE KEY----- - -# ... existing code ... \ No newline at end of file diff --git a/.env.cloud b/.env.cloud deleted file mode 100644 index 8625ba0..0000000 --- a/.env.cloud +++ /dev/null @@ -1,11 +0,0 @@ -# Database configuration - Neon PostgreSQL -DATABASE_URL="postgres://default:BKQz4JdH2RcC@ep-weathered-cherry-a4bsl28s.us-east-1.aws.neon.tech/neondb?sslmode=require" -DIRECT_DATABASE_URL="postgres://default:BKQz4JdH2RcC@ep-weathered-cherry-a4bsl28s.us-east-1.aws.neon.tech/neondb?sslmode=require" - -# Upstash Redis Configuration -UPSTASH_REDIS_REST_URL="https://prime-ostrich-21240.upstash.io" -UPSTASH_REDIS_REST_TOKEN="AVL4AAIjcDExMjE2ZjY5ZTdmMmQ0NWI5OTg4YzNmYzU3NGEwNTdhYnAxMA" - -# NextAuth.js -NEXTAUTH_URL="http://localhost:3001" -NEXTAUTH_SECRET="b47d57c8e07eb57ef77d7cb9fa8412d6cd40b19a31ce00f2bb763a83ba4c8d1b" diff --git a/.env.example b/.env.example index 1bbe26e..9300285 100644 --- a/.env.example +++ b/.env.example @@ -1,72 +1,38 @@ -# Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema - -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. -# See the documentation for all the connection string options: https://pris.ly/d/connection-strings - -# Database configuration -# For local development, use direct connection -DATABASE_URL="postgresql://username:password@host:port/database?sslmode=require" -DIRECT_DATABASE_URL="postgresql://username:password@host:port/database?sslmode=require" -# For local development, you can keep the SQLite connection as a fallback -# DATABASE_URL="file:./dev.db" - -# NextAuth.js +# JackerBox local configuration TEMPLATE. No real credentials belong in Git. +# Add real values only to your local .env (ignored) or to your hosting provider's secrets. +DATABASE_URL= +DIRECT_DATABASE_URL= NEXTAUTH_URL=http://localhost:3000 -NEXTAUTH_SECRET=your-nextauth-secret - -# OAuth Providers (add your own credentials when setting up) -GOOGLE_CLIENT_ID="your-google-client-id" -GOOGLE_CLIENT_SECRET="your-google-client-secret" -APPLE_CLIENT_ID="" -APPLE_CLIENT_SECRET="" - -# Stripe (Payment Processing) -# Using test keys for development -STRIPE_SECRET_KEY=your-stripe-secret-key -STRIPE_PUBLISHABLE_KEY=your-stripe-publishable-key -NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=your-stripe-publishable-key - -STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret -STRIPE_IDENTITY_WEBHOOK_SECRET=your-stripe-identity-webhook-secret -STRIPE_ACCOUNT_COUNTRY=US - -# Cloudinary (Image Upload) -NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="your-cloudinary-cloud-name" -CLOUDINARY_API_KEY="your-cloudinary-api-key" -CLOUDINARY_API_SECRET="your-cloudinary-api-secret" -CLOUDINARY_URL="cloudinary://your-api-key:your-api-secret@your-cloud-name" - -# AWS (for S3 and Rekognition) -AWS_REGION="your-aws-region" -AWS_ACCESS_KEY_ID="your-aws-access-key-id" -AWS_SECRET_ACCESS_KEY="your-aws-secret-access-key" -AWS_S3_BUCKET_NAME="your-s3-bucket-name" - -# Twilio (SMS Verification) -TWILIO_ACCOUNT_SID="" -TWILIO_AUTH_TOKEN="" -TWILIO_PHONE_NUMBER="" - -# Email (optional) -EMAIL_FROM=noreply@example.com -EMAIL_SERVER=smtp://username:password@smtp.example.com:587 - -# Firebase (for phone verification) -NEXT_PUBLIC_FIREBASE_API_KEY="your-firebase-api-key" -NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN="your-firebase-auth-domain" -NEXT_PUBLIC_FIREBASE_PROJECT_ID="your-firebase-project-id" -NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET="your-firebase-storage-bucket" -NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID="your-firebase-messaging-sender-id" -NEXT_PUBLIC_FIREBASE_APP_ID="your-firebase-app-id" - -APPLE_TEAM_ID=2PF2FNX9X6 -APPLE_CLIENT_ID=com.jackerbox -APPLE_KEY_ID=HX8H87KYWG -APPLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgjlLbtFOdb20cmqfL -ESK0IB01iRrNDEZnY2meztsOENugCgYIKoZIzj0DAQehRANCAAQWADQcTbwAEUEi -9u3THkeByaDPIGVq7Nvi9oA1KY9dbn/p64K1R+fdD6CaM5J6m9fJpUQ3zoYKGHYp -c7mRl5ps ------END PRIVATE KEY----- -# Add other environment variables as needed \ No newline at end of file +NEXTAUTH_SECRET= +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= +APPLE_CLIENT_ID= +APPLE_CLIENT_SECRET= +STRIPE_SECRET_KEY= +STRIPE_PUBLISHABLE_KEY= +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= +STRIPE_WEBHOOK_SECRET= +STRIPE_IDENTITY_WEBHOOK_SECRET= +STRIPE_ACCOUNT_COUNTRY= +NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME= +CLOUDINARY_API_KEY= +CLOUDINARY_API_SECRET= +CLOUDINARY_URL= +AWS_REGION= +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_S3_BUCKET_NAME= +TWILIO_ACCOUNT_SID= +TWILIO_AUTH_TOKEN= +TWILIO_PHONE_NUMBER= +EMAIL_FROM= +EMAIL_SERVER= +NEXT_PUBLIC_FIREBASE_API_KEY= +NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN= +NEXT_PUBLIC_FIREBASE_PROJECT_ID= +NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET= +NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= +NEXT_PUBLIC_FIREBASE_APP_ID= +APPLE_TEAM_ID= +APPLE_KEY_ID= +APPLE_PRIVATE_KEY= diff --git a/.env.production b/.env.production deleted file mode 100644 index d652e50..0000000 --- a/.env.production +++ /dev/null @@ -1,29 +0,0 @@ -# Database Configuration - Neon PostgreSQL -# Replace with your actual Neon database credentials -DATABASE_URL="postgresql://jackerboxDB_owner:npg_vYM7Pg4ERIAk@ep-fancy-wind-a5ymnajb-pooler.us-east-2.aws.neon.tech/jackerboxDB?sslmode=require" -DIRECT_DATABASE_URL="postgresql://jackerboxDB_owner:npg_vYM7Pg4ERIAk@ep-fancy-wind-a5ymnajb-pooler.us-east-2.aws.neon.tech/jackerboxDB?sslmode=require" - -# Upstash Redis Configuration -# Replace with your actual Upstash Redis credentials -KV_URL="rediss://default:AVL4AAIjcDExMjE2ZjY5ZTdmMmQ0NWI5OTg4YzNmYzU3NGEwNTdhYnAxMA@prime-ostrich-21240.upstash.io:6379" -KV_REST_API_READ_ONLY_TOKEN="AlL4AAIgcDG6Ii1i0y-BbpQgbe6Wwr6fZst5dlrMknb4_VXgvw9CGw" -REDIS_URL="rediss://default:AVL4AAIjcDExMjE2ZjY5ZTdmMmQ0NWI5OTg4YzNmYzU3NGEwNTdhYnAxMA@prime-ostrich-21240.upstash.io:6379" -KV_REST_API_TOKEN="AVL4AAIjcDExMjE2ZjY5ZTdmMmQ0NWI5OTg4YzNmYzU3NGEwNTdhYnAxMA" -KV_REST_API_URL="https://prime-ostrich-21240.upstash.io" - -# Authentication -NEXTAUTH_URL="https://jackerbox.vercel.app" -NEXTAUTH_SECRET="cpYC5+BS77SLMK7KMhb+9h6Yjoi95BwE7DpWqx+UP+0=" - -# Other services -NODE_ENV="production" - -APPLE_TEAM_ID=2PF2FNX9X6 -APPLE_CLIENT_ID=com.jackerbox -APPLE_KEY_ID=HX8H87KYWG -APPLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgjlLbtFOdb20cmqfL -ESK0IB01iRrNDEZnY2meztsOENugCgYIKoZIzj0DAQehRANCAAQWADQcTbwAEUEi -9u3THkeByaDPIGVq7Nvi9oA1KY9dbn/p64K1R+fdD6CaM5J6m9fJpUQ3zoYKGHYp -c7mRl5ps ------END PRIVATE KEY----- \ No newline at end of file diff --git a/netlify.toml b/netlify.toml index ff032ad..a82e318 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,13 +5,7 @@ [build.environment] NEXT_TELEMETRY_DISABLED = "1" NODE_VERSION = "20" - SECRETS_SCAN_ENABLED = "false" - [[plugins]] package = "@netlify/plugin-nextjs" -# Handle client-side routing -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 +# Next.js routes are handled by the Netlify Next.js runtime, not an SPA fallback. diff --git a/next.config.js b/next.config.js index e57177e..f063398 100644 --- a/next.config.js +++ b/next.config.js @@ -12,6 +12,7 @@ const config = { // Dangerously allow production builds to successfully complete even if // your project has type errors. // !! WARN !! + // Existing type debt must be fixed before re-enabling blocking type checks. ignoreBuildErrors: true, }, output: 'standalone', @@ -130,21 +131,7 @@ const config = { }, ]; }, - env: { - // Only explicitly list allowed environment variables - NEXT_PUBLIC_DISABLE_SOCKET: 'false', - NEXTAUTH_URL: 'http://localhost:3001', - NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, - GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, - GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, - DATABASE_URL: process.env.DATABASE_URL, - // Upstash Redis configuration - KV_URL: process.env.KV_URL || 'rediss://default:AVL4AAIjcDExMjE2ZjY5ZTdmMmQ0NWI5OTg4YzNmYzU3NGEwNTdhYnAxMA@prime-ostrich-21240.upstash.io:6379', - KV_REST_API_TOKEN: process.env.KV_REST_API_TOKEN || 'AVL4AAIjcDExMjE2ZjY5ZTdmMmQ0NWI5OTg4YzNmYzU3NGEwNTdhYnAxMA', - KV_REST_API_READ_ONLY_TOKEN: process.env.KV_REST_API_READ_ONLY_TOKEN || 'AlL4AAIgcDG6Ii1i0y-BbpQgbe6Wwr6fZst5dlrMknb4_VXgvw9CGw', - KV_REST_API_URL: process.env.KV_REST_API_URL || 'https://prime-ostrich-21240.upstash.io', - REDIS_URL: process.env.REDIS_URL || 'rediss://default:AVL4AAIjcDExMjE2ZjY5ZTdmMmQ0NWI5OTg4YzNmYzU3NGEwNTdhYnAxMA@prime-ostrich-21240.upstash.io:6379', - }, + // Secrets belong only in the hosting provider's server-side environment. }; module.exports = config; \ No newline at end of file diff --git a/src/app/api/auth/test-providers/route.ts b/src/app/api/auth/test-providers/route.ts deleted file mode 100644 index af37760..0000000 --- a/src/app/api/auth/test-providers/route.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { NextResponse } from 'next/server'; - -export async function GET() { - try { - // Test configuration for all providers - const providers = { - apple: { - configured: !!( - process.env.APPLE_CLIENT_ID && - process.env.APPLE_TEAM_ID && - process.env.APPLE_KEY_ID && - process.env.APPLE_PRIVATE_KEY - ), - clientId: process.env.APPLE_CLIENT_ID, - teamId: process.env.APPLE_TEAM_ID, - keyId: process.env.APPLE_KEY_ID, - hasPrivateKey: !!process.env.APPLE_PRIVATE_KEY, - }, - google: { - configured: !!( - process.env.GOOGLE_CLIENT_ID && - process.env.GOOGLE_CLIENT_SECRET - ), - clientId: process.env.GOOGLE_CLIENT_ID, - hasSecret: !!process.env.GOOGLE_CLIENT_SECRET, - }, - nextauth: { - configured: !!( - process.env.NEXTAUTH_URL && - process.env.NEXTAUTH_SECRET - ), - url: process.env.NEXTAUTH_URL, - hasSecret: !!process.env.NEXTAUTH_SECRET, - }, - }; - - // Check database configuration - const dbConfigured = !!process.env.DATABASE_URL; - - // Check Redis configuration for rate limiting - const redisConfigured = !!( - process.env.UPSTASH_REDIS_REST_URL && - process.env.UPSTASH_REDIS_REST_TOKEN - ); - - return NextResponse.json({ - providers, - database: { - configured: dbConfigured, - url: process.env.DATABASE_URL?.split('?')[0], // Remove query params for security - }, - redis: { - configured: redisConfigured, - url: process.env.UPSTASH_REDIS_REST_URL?.split('@')[0], // Remove credentials for security - }, - environment: process.env.NODE_ENV, - }); - } catch (error) { - console.error('Provider test error:', error); - return NextResponse.json({ - error: error instanceof Error ? error.message : 'Unknown error', - }, { status: 500 }); - } -} \ No newline at end of file diff --git a/src/app/api/create-test-payment/route.ts b/src/app/api/create-test-payment/route.ts deleted file mode 100644 index 5d1d0ad..0000000 --- a/src/app/api/create-test-payment/route.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { NextResponse } from 'next/server'; -import Stripe from 'stripe'; - -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { - apiVersion: '2025-02-24.acacia', -}); - -export async function POST(request: Request) { - try { - const body = await request.json().catch(() => ({})); - const { amount = 2000, currency = 'usd' } = body; - - const paymentIntent = await stripe.paymentIntents.create({ - amount, - currency, - metadata: { - userId: 'test-user-123', - rentalId: 'test-rental-456', - type: 'test_payment', - createdAt: new Date().toISOString() - }, - automatic_payment_methods: { - enabled: true, - }, - }); - - return NextResponse.json({ - success: true, - paymentIntentId: paymentIntent.id, - clientSecret: paymentIntent.client_secret, - amount: paymentIntent.amount, - currency: paymentIntent.currency, - status: paymentIntent.status, - }); - - } catch (error) { - console.error('Error creating test payment:', error); - return NextResponse.json( - { - error: 'Failed to create test payment', - details: error instanceof Error ? error.message : 'Unknown error' - }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/src/app/api/equipment/test-endpoint/route.ts b/src/app/api/equipment/test-endpoint/route.ts deleted file mode 100644 index 085d86f..0000000 --- a/src/app/api/equipment/test-endpoint/route.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { NextResponse } from "next/server"; -import { db } from "@/lib/db"; - -// Define the EquipmentItem type to fix type errors -interface EquipmentItem { - id: string; - title: string; - description: string; - category: string; - location: string; - imagesJson: string; - tagsJson: string; - dailyRate: number | null; - ownerId: string; -} - -// This endpoint doesn't require authentication for testing purposes -export async function GET(req: Request) { - try { - console.log("Test endpoint called"); - - // Count equipment first - const equipmentCount = await db.equipment.count(); - - console.log(`Found ${equipmentCount} equipment items in database`); - - // If we have equipment, fetch a sample - let sampleEquipment: EquipmentItem[] = []; - if (equipmentCount > 0) { - sampleEquipment = await db.equipment.findMany({ - take: 5, - select: { - id: true, - title: true, - description: true, - category: true, - location: true, - imagesJson: true, - tagsJson: true, - dailyRate: true, - ownerId: true, - } - }); - } - - // Process equipment to parse JSON fields - const processedEquipment = sampleEquipment.map(item => { - try { - // Parse images JSON if it exists - let images: string[] = []; - if (item.imagesJson) { - try { - images = JSON.parse(item.imagesJson); - } catch (e) { - console.error("Error parsing images JSON:", e); - } - } - - // Parse tags JSON if it exists - let tags: string[] = []; - if (item.tagsJson) { - try { - tags = JSON.parse(item.tagsJson); - } catch (e) { - console.error("Error parsing tags JSON:", e); - } - } - - return { - ...item, - images, - tags, - pricePerDay: item.dailyRate, - }; - } catch (error) { - console.error("Error processing equipment item:", error); - return { - ...item, - images: [], - tags: [], - pricePerDay: item.dailyRate, - }; - } - }); - - return NextResponse.json({ - status: "success", - message: `Database connection successful. Found ${equipmentCount} equipment items.`, - count: equipmentCount, - equipment: processedEquipment, - }); - } catch (error) { - console.error("Error in test endpoint:", error); - return NextResponse.json( - { - status: "error", - message: "Something went wrong connecting to the database", - error: error instanceof Error ? error.message : String(error) - }, - { status: 500 } - ); - } -} - -// Ensure this endpoint is never cached -export const dynamic = 'force-dynamic'; \ No newline at end of file diff --git a/src/app/api/payments/test-intent/route.ts b/src/app/api/payments/test-intent/route.ts deleted file mode 100644 index dad86f7..0000000 --- a/src/app/api/payments/test-intent/route.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { NextResponse } from 'next/server'; -import { stripe, formatAmountForStripe } from '@/lib/stripe'; - -export async function POST(req: Request) { - try { - const body = await req.json(); - const { amount = 2000, securityDeposit = 500, currency = 'USD' } = body; - - // Calculate total amount including security deposit - const totalAmount = amount + (securityDeposit || 0); - const amountInCents = formatAmountForStripe(totalAmount, currency); - - // Create a test payment intent - const paymentIntent = await stripe.paymentIntents.create({ - amount: amountInCents, - currency: currency.toLowerCase(), - metadata: { - type: 'test_payment', - testMode: 'true', - rentalAmount: amount.toString(), - securityDepositAmount: (securityDeposit || 0).toString(), - }, - automatic_payment_methods: { - enabled: true, - }, - }); - - return NextResponse.json({ - clientSecret: paymentIntent.client_secret, - paymentIntentId: paymentIntent.id, - amount: totalAmount, - }); - } catch (error) { - console.error('Error creating test payment intent:', error); - return NextResponse.json( - { error: 'Failed to create payment intent' }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/src/app/api/redis-test/route.ts b/src/app/api/redis-test/route.ts deleted file mode 100644 index b4a0d6d..0000000 --- a/src/app/api/redis-test/route.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { NextResponse } from 'next/server'; -import { redis } from '@/lib/redis'; - -export async function GET() { - try { - // Set a test value - await redis.set('test-key', 'Redis connection working!'); - - // Get the test value - const value = await redis.get('test-key'); - - // Return success response - return NextResponse.json({ - status: 'success', - message: 'Redis connection successful', - value - }, { status: 200 }); - } catch (error) { - console.error('Redis test error:', error); - - // Return error response - return NextResponse.json({ - status: 'error', - message: 'Redis connection failed', - error: error instanceof Error ? error.message : String(error) - }, { status: 500 }); - } -} - -export async function POST(request: Request) { - try { - const body = await request.json(); - const { key, value } = body; - - if (!key || !value) { - return NextResponse.json({ - status: 'error', - message: 'Missing key or value in request body' - }, { status: 400 }); - } - - // Store the value in Redis - await redis.set(key, value); - - // Return success response - return NextResponse.json({ - status: 'success', - message: `Value stored successfully under key: ${key}` - }, { status: 200 }); - } catch (error) { - console.error('Redis store error:', error); - - // Return error response - return NextResponse.json({ - status: 'error', - message: 'Failed to store value in Redis', - error: error instanceof Error ? error.message : String(error) - }, { status: 500 }); - } -} \ No newline at end of file diff --git a/src/app/api/socket-debug/initialize/route.ts b/src/app/api/socket-debug/initialize/route.ts deleted file mode 100644 index c28409e..0000000 --- a/src/app/api/socket-debug/initialize/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { NextResponse } from 'next/server'; -import { initServer, getSocketServerStatus } from '@/lib/socket/server-init'; - -export const dynamic = 'force-dynamic'; - -export async function POST() { - try { - console.log('Attempting to initialize socket server...'); - const io = await initServer(); - const status = getSocketServerStatus(); - - return NextResponse.json({ - success: !!io, - message: io ? 'Socket server initialized successfully' : 'Socket server initialization failed', - status - }); - } catch (error: any) { - console.error('Error initializing socket server:', error); - return NextResponse.json( - { - success: false, - error: error.message || 'Failed to initialize socket server', - status: getSocketServerStatus() - }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/src/app/api/socket-debug/restart/route.ts b/src/app/api/socket-debug/restart/route.ts deleted file mode 100644 index 7d5943a..0000000 --- a/src/app/api/socket-debug/restart/route.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { NextResponse } from 'next/server'; -import { shutdownSocketServer, initServer, getSocketServerStatus } from '@/lib/socket/server-init'; - -export const dynamic = 'force-dynamic'; - -export async function POST() { - try { - console.log('Restarting socket server...'); - - // First, shut down the existing server - shutdownSocketServer(); - console.log('Socket server shut down'); - - // Wait a moment to ensure clean shutdown - await new Promise(resolve => setTimeout(resolve, 500)); - - // Then initialize a new server - console.log('Initializing new socket server...'); - const io = await initServer(); - const status = getSocketServerStatus(); - - return NextResponse.json({ - success: !!io, - message: io ? 'Socket server restarted successfully' : 'Socket server restart failed', - status - }); - } catch (error: any) { - console.error('Error restarting socket server:', error); - return NextResponse.json( - { - success: false, - error: error.message || 'Failed to restart socket server', - status: getSocketServerStatus() - }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/src/app/api/socket-debug/status/route.ts b/src/app/api/socket-debug/status/route.ts deleted file mode 100644 index 8133dce..0000000 --- a/src/app/api/socket-debug/status/route.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NextResponse } from 'next/server'; -import { getSocketServerStatus } from '@/lib/socket/server-init'; - -export const dynamic = 'force-dynamic'; - -export async function GET() { - try { - const status = getSocketServerStatus(); - return NextResponse.json(status); - } catch (error: any) { - console.error('Error getting socket server status:', error); - return NextResponse.json( - { error: error.message || 'Failed to get socket server status' }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/src/app/api/sse/publish/route.ts b/src/app/api/sse/publish/route.ts index b188338..e6fe749 100644 --- a/src/app/api/sse/publish/route.ts +++ b/src/app/api/sse/publish/route.ts @@ -1,5 +1,6 @@ import { NextRequest, NextResponse } from 'next/server'; import { publish } from '@/lib/sse/sse-manager'; +import { getCurrentUser } from '@/lib/auth/auth-utils'; export const dynamic = 'force-dynamic'; export const runtime = 'nodejs'; @@ -9,6 +10,8 @@ export const runtime = 'nodejs'; */ export async function POST(req: NextRequest) { try { + const user = await getCurrentUser(); + if (!user?.isAdmin) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); const body = await req.json().catch(() => ({})); const { topic, data } = body; diff --git a/src/app/api/sse/route.ts b/src/app/api/sse/route.ts index 909e02d..221b72e 100644 --- a/src/app/api/sse/route.ts +++ b/src/app/api/sse/route.ts @@ -16,6 +16,8 @@ export const fetchCache = 'force-no-store'; */ export async function GET(req: NextRequest) { const isDev = process.env.NODE_ENV === 'development'; + const session = await getServerSession(authOptions); + if (!session?.user?.id) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); // Set up SSE headers const responseHeaders = new Headers({ @@ -82,11 +84,14 @@ export async function OPTIONS(req: NextRequest) { */ export async function POST(req: NextRequest) { try { + const user = await getCurrentUser(); + if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const body = await req.json().catch(() => ({})); const { clientId, action, topic, enabled } = body; // Handle debug mode toggle if (action === 'debug') { + if (!user.isAdmin) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); if (typeof enabled === 'boolean') { const result = toggleDebugMode(enabled); return NextResponse.json({ success: true, debugMode: result }); @@ -119,6 +124,7 @@ export async function POST(req: NextRequest) { return NextResponse.json({ success: result, action, topic }); case 'stats': + if (!user.isAdmin) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); result = getStats(); return NextResponse.json(result); diff --git a/src/app/api/test/update-verification/route.ts b/src/app/api/test/update-verification/route.ts deleted file mode 100644 index c47ee11..0000000 --- a/src/app/api/test/update-verification/route.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NextResponse } from "next/server"; -import { db } from "@/lib/db"; - -export async function POST(req: Request) { - try { - const { userId, status } = await req.json(); - - if (!userId) { - return NextResponse.json( - { error: "User ID is required" }, - { status: 400 } - ); - } - - // Validate status - if (!["pending", "approved", "requires_input", "canceled", "reset"].includes(status)) { - return NextResponse.json( - { error: "Invalid status" }, - { status: 400 } - ); - } - - // Update user verification status - if (status === "reset") { - // Reset all verification fields - await db.user.update({ - where: { id: userId }, - data: { - idVerified: false, - idVerificationStatus: null, - idVerificationDate: null - } - }); - } else { - await db.user.update({ - where: { id: userId }, - data: { - idVerified: status === "approved", - idVerificationStatus: status, - ...(status === "approved" ? { idVerificationDate: new Date() } : {}) - } - }); - } - - return NextResponse.json({ success: true, status }); - } catch (error) { - console.error("Error updating verification status:", error); - return NextResponse.json( - { error: "Failed to update verification status" }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/src/app/api/users/verify-id-basic/route.ts b/src/app/api/users/verify-id-basic/route.ts index 8593469..3ebe34b 100644 --- a/src/app/api/users/verify-id-basic/route.ts +++ b/src/app/api/users/verify-id-basic/route.ts @@ -39,14 +39,14 @@ export async function POST(req: Request) { where: { id: user.id }, data: { idDocumentType: documentType, - idVerificationStatus: verificationResult.needsManualReview ? "pending" : (verificationResult.isValid ? "approved" : "rejected"), - idVerified: verificationResult.isValid && !verificationResult.needsManualReview, + idVerificationStatus: verificationResult.isValid || verificationResult.needsManualReview ? "pending" : "rejected", + idVerified: false, // A user-submitted document is never proof of completed verification. idVerificationDate: new Date(), }, }); // If manual review is needed, create a notification for admins - if (verificationResult.needsManualReview) { + if (verificationResult.isValid || verificationResult.needsManualReview) { // Find admin users const admins = await db.user.findMany({ where: { isAdmin: true }, @@ -74,7 +74,7 @@ export async function POST(req: Request) { return NextResponse.json({ success: true, ...verificationResult, - status: verificationResult.needsManualReview ? "pending" : (verificationResult.isValid ? "approved" : "rejected"), + status: verificationResult.isValid || verificationResult.needsManualReview ? "pending" : "rejected", }); } catch (error) { if (error instanceof z.ZodError) { diff --git a/src/lib/auth/auth-options.ts b/src/lib/auth/auth-options.ts index de44511..b2cd725 100644 --- a/src/lib/auth/auth-options.ts +++ b/src/lib/auth/auth-options.ts @@ -159,7 +159,7 @@ export const authOptions: NextAuthOptions = { GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, - allowDangerousEmailAccountLinking: true, + allowDangerousEmailAccountLinking: false, }), // AppleProvider disabled until key issues are resolved // AppleProvider({ @@ -182,39 +182,7 @@ export const authOptions: NextAuthOptions = { type: { label: 'Type', type: 'text' }, // 'email' or 'phone' }, async authorize(credentials) { - // Handle phone authentication - if (credentials?.type === 'phone' && credentials?.phone) { - const user = await prisma.user.findFirst({ - where: { - phone: credentials.phone, - }, - select: { - id: true, - name: true, - email: true, - phone: true, - image: true, - isAdmin: true, - stripeConnectAccountId: true, - userType: true, - }, - }); - - if (!user) { - throw new Error('No account found with this phone number'); - } - - return { - id: user.id, - name: user.name, - email: user.email || `phone_${user.phone}@jackerbox.com`, // Ensure email is not null for NextAuth - image: user.image, - isAdmin: Boolean(user.isAdmin), - stripeConnectAccountId: user.stripeConnectAccountId || undefined, - userType: user.userType || 'both', - }; - } - + // Phone-only sign-in is disabled until a verified one-time code is required. // Handle email/password authentication if (!credentials?.email || !credentials?.password) { throw new Error('Invalid credentials'); diff --git a/src/lib/db.ts b/src/lib/db.ts index f354623..a65df1f 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -55,8 +55,8 @@ function createPrismaClient() { return client; } catch (error) { console.error("Failed to create Prisma client:", error); - // Return a mock client that returns empty data instead of crashing - return createMockPrismaClient(); + // Never fake successful database operations when the real client fails. + throw error; } } @@ -77,41 +77,5 @@ function isRetryableError(error: any): boolean { return false; } -// Create a mock client for when the database is unavailable -function createMockPrismaClient() { - console.warn("Using mock Prisma client due to database connection issues"); - - const handler = { - get: (target: any, prop: string) => { - // Return empty arrays/objects for common methods - if (prop === '$connect' || prop === '$disconnect') { - return async () => {}; - } - - // For all model operations, return an empty result proxy - return new Proxy({}, { - get: (target: any, operation: string) => { - // Handle common Prisma operations - if (['findMany', 'findFirst', 'findUnique', 'findFirstOrThrow', 'findUniqueOrThrow'].includes(operation)) { - return async () => operation.includes('Many') ? [] : null; - } - - if (['create', 'update', 'upsert'].includes(operation)) { - return async () => ({}); - } - - if (['delete', 'deleteMany', 'updateMany', 'count'].includes(operation)) { - return async () => ({ count: 0 }); - } - - return async () => null; - } - }); - } - }; - - return new Proxy({}, handler); -} - // Export only once export default db; From 59197eba66d13a8e25363d0f94c4a02e8b7303b4 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:23:22 -0400 Subject: [PATCH 002/152] fix: validate bookings server-side and enforce paid rental transitions --- src/app/api/payments/create-intent/route.ts | 207 +++++--------------- src/app/api/rentals/[id]/status/route.ts | 155 ++++----------- src/app/api/rentals/route.ts | 182 +++++++++-------- 3 files changed, 174 insertions(+), 370 deletions(-) diff --git a/src/app/api/payments/create-intent/route.ts b/src/app/api/payments/create-intent/route.ts index bb8d094..190dfab 100644 --- a/src/app/api/payments/create-intent/route.ts +++ b/src/app/api/payments/create-intent/route.ts @@ -1,188 +1,69 @@ import { NextResponse } from 'next/server'; import { z } from 'zod'; - import { stripe, formatAmountForStripe } from '@/lib/stripe'; import { db } from '@/lib/db'; import { getCurrentUser } from '@/lib/auth/session'; -// Schema for validating the request body -const paymentIntentSchema = z.object({ - rentalId: z.string(), - paymentId: z.string(), - amount: z.number().positive(), - securityDeposit: z.number().optional(), - currency: z.string().default('USD'), +const schema = z.object({ + rentalId: z.string().min(1), + paymentId: z.string().min(1), }); -// Mock function for development environments -async function createMockPaymentIntent( - rentalId: string, - amount: number, - currency: string -) { - console.log('Creating mock payment intent for development', { - rentalId, - amount, - currency - }); - - // Create a fake client secret that looks like a Stripe one - const timestamp = Date.now(); - const mockClientSecret = `mock_pi_${timestamp}_secret_${Math.random().toString(36).substring(2, 15)}`; - - // In development mode, automatically mark the payment as successful after a delay - setTimeout(async () => { - try { - // Find the payment and update it to successful - const payment = await db.payment.findFirst({ - where: { - rentalId: rentalId, - }, - }); - - if (payment) { - await db.payment.update({ - where: { - id: payment.id, - }, - data: { - status: "COMPLETED", - stripePaymentIntentId: `mock_pi_${timestamp}`, - }, - }); - - // Also update the rental status - await db.rental.update({ - where: { - id: rentalId, - }, - data: { - status: "ACTIVE", - }, - }); - - console.log(`Mock payment for rental ${rentalId} automatically marked as successful.`); - } - } catch (error) { - console.error('Error processing mock payment:', error); - } - }, 5000); // Simulate a 5 second processing time - - return { - clientSecret: mockClientSecret, - paymentIntentId: `mock_pi_${timestamp}`, - }; -} - export async function POST(req: Request) { - try { - // Get the current user - const currentUser = await getCurrentUser(); - if (!currentUser) { - return new NextResponse('Unauthorized', { status: 401 }); - } - - // Parse and validate the request body - const body = await req.json(); - const validationResult = paymentIntentSchema.safeParse(body); - - if (!validationResult.success) { - return new NextResponse('Invalid request data', { status: 400 }); - } - - const { rentalId, paymentId, amount, securityDeposit, currency } = validationResult.data; + const user = await getCurrentUser(); + if (!user) return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); + const parsed = schema.safeParse(await req.json().catch(() => null)); + if (!parsed.success) return NextResponse.json({ message: 'Invalid payment request' }, { status: 400 }); - // Check if the rental exists and belongs to the current user + try { + const { rentalId, paymentId } = parsed.data; const rental = await db.rental.findUnique({ - where: { - id: rentalId, - renterId: currentUser.id, - }, - include: { - equipment: true, - }, + where: { id: rentalId }, + include: { payment: true, equipment: { select: { title: true } } }, }); - - if (!rental) { - return new NextResponse('Rental not found or unauthorized', { status: 404 }); + if (!rental || rental.renterId !== user.id || !rental.payment || rental.payment.id !== paymentId) { + return NextResponse.json({ message: 'Payment not found' }, { status: 404 }); + } + if (rental.status !== 'PENDING' || rental.payment.status !== 'PENDING' || + Date.now() - rental.createdAt.getTime() > 30 * 60 * 1000) { + return NextResponse.json({ message: 'This rental is no longer eligible for payment' }, { status: 409 }); } - // Check if the payment exists and belongs to the rental - const payment = await db.payment.findUnique({ - where: { - id: paymentId, - rentalId: rentalId, - }, - }); - - if (!payment) { - return new NextResponse('Payment not found', { status: 404 }); + // Never accept a price, currency or deposit from the browser. + const amount = Math.round((rental.totalPrice + (rental.securityDeposit ?? 0)) * 100) / 100; + if (!Number.isFinite(amount) || amount <= 0 || amount > 999999) { + return NextResponse.json({ message: 'Invalid rental amount' }, { status: 400 }); } + const cents = formatAmountForStripe(amount, 'USD'); - // Calculate total amount including security deposit if provided - const totalAmount = securityDeposit - ? amount + securityDeposit - : amount; - - // In development mode, use mock payment processing - if (process.env.NODE_ENV === 'development') { - const mockResult = await createMockPaymentIntent( - rentalId, - amount + (securityDeposit || 0), - currency - ); - - // Update the payment record with the mock payment intent ID - await db.payment.update({ - where: { - id: payment.id, - }, - data: { - stripePaymentIntentId: mockResult.paymentIntentId, - }, - }); - - return NextResponse.json({ - clientSecret: mockResult.clientSecret, - paymentId: payment.id, - }); + if (rental.payment.stripePaymentIntentId) { + const existing = await stripe.paymentIntents.retrieve(rental.payment.stripePaymentIntentId); + if (existing.status === 'requires_payment_method' || existing.status === 'requires_confirmation' || + existing.status === 'requires_action') { + if (existing.amount === cents && existing.currency === 'usd' && existing.client_secret) { + return NextResponse.json({ clientSecret: existing.client_secret, paymentId }); + } + } + return NextResponse.json({ message: 'Payment already initiated. Contact support if you cannot complete it.' }, { status: 409 }); } - // Create a real Stripe payment intent - const amountInCents = formatAmountForStripe(totalAmount, currency); - - const paymentIntent = await stripe.paymentIntents.create({ - amount: amountInCents, - currency: currency.toLowerCase(), + const intent = await stripe.paymentIntents.create({ + amount: cents, + currency: 'usd', metadata: { - rentalId, - paymentId, - equipmentId: rental.equipmentId, - equipmentTitle: rental.equipment.title, - hasSecurityDeposit: securityDeposit ? 'true' : 'false', - securityDepositAmount: securityDeposit ? securityDeposit.toString() : '0', - rentalAmount: amount.toString(), + rentalId, paymentId, equipmentId: rental.equipmentId, + rentalAmount: rental.totalPrice.toFixed(2), + securityDepositAmount: (rental.securityDeposit ?? 0).toFixed(2), }, - }); + }, { idempotencyKey: `rental-${rentalId}-payment-${paymentId}-v1` }); - // Update the payment record with the Stripe payment intent ID and security deposit info await db.payment.update({ - where: { - id: payment.id, - }, - data: { - stripePaymentIntentId: paymentIntent.id, - amount: totalAmount, // Update to include security deposit - }, - }); - - // Return the client secret to the client - return NextResponse.json({ - clientSecret: paymentIntent.client_secret, - paymentId: payment.id, + where: { id: paymentId }, + data: { stripePaymentIntentId: intent.id, amount, currency: 'USD' }, }); + return NextResponse.json({ clientSecret: intent.client_secret, paymentId }); } catch (error) { - console.error('Error creating payment intent:', error); - return new NextResponse('Error creating payment intent', { status: 500 }); + console.error('Payment initialization failed', error); + return NextResponse.json({ message: 'Unable to initialize payment' }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/src/app/api/rentals/[id]/status/route.ts b/src/app/api/rentals/[id]/status/route.ts index b9c7d0d..a8cff14 100644 --- a/src/app/api/rentals/[id]/status/route.ts +++ b/src/app/api/rentals/[id]/status/route.ts @@ -1,130 +1,43 @@ -import { NextResponse } from "next/server"; -import { getCurrentUser } from "@/lib/auth/auth-utils"; -import { db } from "@/lib/db"; -import { z } from "zod"; +import { NextResponse } from 'next/server'; +import { z } from 'zod'; +import { db } from '@/lib/db'; +import { getCurrentUser } from '@/lib/auth/auth-utils'; -// Define the status update schema -const statusUpdateSchema = z.object({ - status: z.enum([ - "Pending", - "Approved", - "Rejected", - "Cancelled", - "InProgress", - "Completed", - ]), -}); +const schema = z.object({ status: z.enum(['ACTIVE', 'COMPLETED', 'CANCELLED']) }); + +export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }) { + const user = await getCurrentUser(); + if (!user) return NextResponse.json({ message: 'Unauthorized' }, { status: 401 }); + const result = schema.safeParse(await req.json().catch(() => null)); + if (!result.success) return NextResponse.json({ message: 'Invalid rental status' }, { status: 400 }); + const { id } = await params; -export async function PATCH( - req: Request, - { params }: { params: { id: string } } -) { try { - // Get the current user - const user = await getCurrentUser(); - - if (!user || !user.id) { - return NextResponse.json( - { message: "Unauthorized" }, - { status: 401 } - ); - } - - // Parse the request body - const body = await req.json(); - - // Validate the request body - const validatedData = statusUpdateSchema.parse(body); - - // Extract the rental ID using the newer approach for safety - const rentalId = params.id; - - // Check if the rental exists const rental = await db.rental.findUnique({ - where: { - id: rentalId, - }, - include: { - equipment: true, - }, + where: { id }, + include: { equipment: { select: { ownerId: true } }, payment: { select: { status: true } } }, }); - - if (!rental) { - return NextResponse.json( - { message: "Rental not found" }, - { status: 404 } - ); - } - - // Check if the user is the renter or the owner - const isRenter = rental.renterId === user.id; + if (!rental) return NextResponse.json({ message: 'Rental not found' }, { status: 404 }); + const isOwner = rental.equipment.ownerId === user.id; - - if (!isRenter && !isOwner) { - return NextResponse.json( - { message: "You are not authorized to update this rental" }, - { status: 403 } - ); - } - - // Validate status transitions - const currentStatus = rental.status; - const newStatus = validatedData.status; - - // Owner-only status changes - if (newStatus === "Approved" && !isOwner) { - return NextResponse.json( - { message: "Only the owner can approve a rental" }, - { status: 403 } - ); - } - - if (newStatus === "Rejected" && !isOwner) { - return NextResponse.json( - { message: "Only the owner can reject a rental" }, - { status: 403 } - ); - } - - // Invalid transitions - if (currentStatus === "Completed" || currentStatus === "Cancelled") { - return NextResponse.json( - { message: `Cannot change status from ${currentStatus}` }, - { status: 400 } - ); - } - - if (currentStatus === "Rejected" && newStatus !== "Cancelled") { - return NextResponse.json( - { message: "Rejected rentals can only be cancelled" }, - { status: 400 } - ); - } - - // Update the rental status - const updatedRental = await db.rental.update({ - where: { - id: rentalId, - }, - data: { - status: validatedData.status, - }, + const isRenter = rental.renterId === user.id; + if (!isOwner && !isRenter) return NextResponse.json({ message: 'Forbidden' }, { status: 403 }); + + const target = result.data.status; + const valid = (target === 'CANCELLED' && rental.status === 'PENDING' && (isOwner || isRenter)) || + (target === 'ACTIVE' && isOwner && rental.status === 'PAID' && rental.payment?.status === 'COMPLETED') || + (target === 'COMPLETED' && isOwner && rental.status === 'ACTIVE' && rental.payment?.status === 'COMPLETED'); + + if (!valid) return NextResponse.json({ message: 'Invalid status transition. Paid cancellations require refund review.' }, { status: 409 }); + + const changed = await db.rental.updateMany({ + where: { id, status: rental.status }, + data: { status: target }, }); - - return NextResponse.json(updatedRental); + if (changed.count !== 1) return NextResponse.json({ message: 'Rental was updated elsewhere. Refresh and retry.' }, { status: 409 }); + return NextResponse.json({ success: true, status: target }); } catch (error) { - console.error("Error updating rental status:", error); - - if (error instanceof z.ZodError) { - return NextResponse.json( - { message: "Invalid data", errors: error.errors }, - { status: 400 } - ); - } - - return NextResponse.json( - { message: "Failed to update rental status" }, - { status: 500 } - ); + console.error('Rental status update failed', error); + return NextResponse.json({ message: 'Unable to update rental' }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/src/app/api/rentals/route.ts b/src/app/api/rentals/route.ts index da37122..72217e9 100644 --- a/src/app/api/rentals/route.ts +++ b/src/app/api/rentals/route.ts @@ -1,107 +1,117 @@ import { NextRequest, NextResponse } from 'next/server'; -import { getServerSession } from 'next-auth'; -import { authOptions } from '../../../lib/auth/auth-options'; -import { PrismaClient } from '../../../../prisma/generated/client'; +import { z } from 'zod'; +import { Prisma } from '../../../../prisma/generated/client'; +import { db } from '@/lib/db'; +import { getCurrentUser } from '@/lib/auth/session'; -const prisma = new PrismaClient(); +const DAY = 24 * 60 * 60 * 1000; +const PENDING_HOLD_MS = 30 * 60 * 1000; +const requestSchema = z.object({ + equipmentId: z.string().min(1), + startDate: z.string(), + endDate: z.string(), + rentalType: z.enum(['hourly', 'daily', 'weekly']), +}); -export async function GET(request: NextRequest) { - try { - const session = await getServerSession(authOptions); - - if (!session?.user?.email) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } - - // Get user rentals - const user = await prisma.user.findUnique({ - where: { email: session.user.email } - }); +class ConflictError extends Error {} - if (!user) { - return NextResponse.json({ error: 'User not found' }, { status: 404 }); - } - - const rentals = await prisma.rental.findMany({ - where: { - OR: [ - { renterId: user.id }, - { equipment: { ownerId: user.id } } - ] - }, +export async function GET(_request: NextRequest) { + const user = await getCurrentUser(); + if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); + try { + const rentals = await db.rental.findMany({ + where: { OR: [{ renterId: user.id }, { equipment: { ownerId: user.id } }] }, include: { - equipment: { - select: { - title: true, - category: true, - hourlyRate: true, - dailyRate: true, - imagesJson: true - } - }, - renter: { - select: { - name: true, - email: true - } - } + equipment: { select: { title: true, category: true, hourlyRate: true, dailyRate: true, imagesJson: true } }, + renter: { select: { name: true, email: true } }, }, - orderBy: { createdAt: 'desc' } + orderBy: { createdAt: 'desc' }, }); - return NextResponse.json(rentals); } catch (error) { - console.error('Rentals API error:', error); - return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); + console.error('Rentals list failed', error); + return NextResponse.json({ error: 'Unable to load rentals' }, { status: 500 }); } } export async function POST(request: NextRequest) { - try { - const session = await getServerSession(authOptions); - - if (!session?.user?.email) { - return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - } + const user = await getCurrentUser(); + if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const body = await request.json(); - const { equipmentId, startDate, endDate, totalPrice } = body; + const parsed = requestSchema.safeParse(await request.json().catch(() => null)); + if (!parsed.success) return NextResponse.json({ message: 'Invalid rental request' }, { status: 400 }); - if (!equipmentId || !startDate || !endDate || !totalPrice) { - return NextResponse.json({ error: 'Missing required fields' }, { status: 400 }); - } - - const user = await prisma.user.findUnique({ - where: { email: session.user.email } - }); + const { equipmentId, startDate, endDate, rentalType } = parsed.data; + const start = new Date(startDate); + const end = new Date(endDate); + const todayUtc = new Date(); + todayUtc.setUTCHours(0, 0, 0, 0); + if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime()) || + start < todayUtc || end <= start || end.getTime() - start.getTime() > 90 * DAY) { + return NextResponse.json({ message: 'Choose valid rental dates within the next 90-day rental period' }, { status: 400 }); + } - if (!user) { - return NextResponse.json({ error: 'User not found' }, { status: 404 }); - } + try { + // Serializable isolation prevents concurrent requests from both accepting an overlapping interval. + const rental = await db.$transaction(async (tx) => { + const equipment = await tx.equipment.findUnique({ where: { id: equipmentId } }); + if (!equipment || !equipment.isAvailable || equipment.moderationStatus !== 'APPROVED') { + throw new ConflictError('This equipment is not available for booking'); + } + if (equipment.ownerId === user.id) throw new ConflictError('You cannot rent your own equipment'); - // Create rental - const rental = await prisma.rental.create({ - data: { - equipmentId, - renterId: user.id, - startDate: new Date(startDate), - endDate: new Date(endDate), - totalPrice: parseFloat(totalPrice), - status: 'PENDING' - }, - include: { - equipment: { - select: { - title: true, - category: true - } - } + const rate = rentalType === 'hourly' ? equipment.hourlyRate + : rentalType === 'weekly' ? equipment.weeklyRate : equipment.dailyRate; + if (rate == null || !Number.isFinite(rate) || rate <= 0) { + throw new ConflictError('The selected rental rate is unavailable'); } - }); + const duration = end.getTime() - start.getTime(); + const units = rentalType === 'hourly' ? Math.ceil(duration / (60 * 60 * 1000)) + : rentalType === 'weekly' ? Math.ceil(duration / (7 * DAY)) : Math.ceil(duration / DAY); + const totalPrice = Math.round(rate * units * 100) / 100; + if (!Number.isFinite(totalPrice) || totalPrice <= 0) throw new ConflictError('Invalid rental price'); - return NextResponse.json(rental); + // Block date-level blackout days, including any part of the requested rental window. + if (equipment.blackoutDates.some((d) => { + const blackout = new Date(d); + const dateOnly = new Date(Date.UTC(blackout.getUTCFullYear(), blackout.getUTCMonth(), blackout.getUTCDate())); + return dateOnly < end && new Date(dateOnly.getTime() + DAY) > start; + })) throw new ConflictError('These dates include unavailable equipment days'); + + const overlap = await tx.rental.findFirst({ + where: { + equipmentId, + startDate: { lt: end }, + endDate: { gt: start }, + OR: [ + { status: { in: ['PAID', 'ACTIVE'] } }, + { status: 'PENDING', createdAt: { gte: new Date(Date.now() - PENDING_HOLD_MS) } }, + ], + }, + select: { id: true }, + }); + if (overlap) throw new ConflictError('These dates are already reserved'); + + return tx.rental.create({ + data: { + equipmentId, + renterId: user.id, + startDate: start, + endDate: end, + totalPrice, + securityDeposit: Math.max(0, equipment.securityDeposit ?? 0), + status: 'PENDING', + }, + include: { equipment: { select: { title: true, category: true } } }, + }); + }, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable }); + + return NextResponse.json({ rental }, { status: 201 }); } catch (error) { - console.error('Rental creation error:', error); - return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); + if (error instanceof ConflictError || (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2034')) { + return NextResponse.json({ message: error instanceof ConflictError ? error.message : 'Booking conflicted with another request. Please retry.' }, { status: 409 }); + } + console.error('Rental creation failed', error); + return NextResponse.json({ message: 'Unable to create rental' }, { status: 500 }); } -} \ No newline at end of file +} From 1d543ee1e680faffd9a055bb4ed3b405ae8e41f0 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:24:41 -0400 Subject: [PATCH 003/152] fix: connect checkout UI, rental status actions and verified Stripe webhooks --- src/app/api/webhooks/stripe/route.ts | 236 ++++++------------ src/app/routes/rentals/[id]/page.tsx | 17 +- src/app/routes/rentals/[id]/payment/page.tsx | 134 +++------- src/components/payments/payment-form.tsx | 51 +--- .../profile/basic-id-verification-form.tsx | 2 +- src/components/rentals/booking-form.tsx | 10 +- src/components/rentals/rental-actions.tsx | 236 ++++-------------- 7 files changed, 169 insertions(+), 517 deletions(-) diff --git a/src/app/api/webhooks/stripe/route.ts b/src/app/api/webhooks/stripe/route.ts index 77979fd..b99edc4 100644 --- a/src/app/api/webhooks/stripe/route.ts +++ b/src/app/api/webhooks/stripe/route.ts @@ -1,176 +1,80 @@ import { NextResponse } from 'next/server'; -import { headers } from 'next/headers'; -import Stripe from 'stripe'; -import prisma from '@/lib/db'; - -const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { - apiVersion: '2025-02-24.acacia', -}); - -async function verifyStripeSignature(request: Request): Promise { - const body = await request.text(); - const headersList = await headers(); - const signature = headersList.get('stripe-signature'); - - if (!signature) { - throw new Error('No Stripe signature found'); - } - - return stripe.webhooks.constructEvent( - body, - signature, - process.env.STRIPE_WEBHOOK_SECRET! - ); -} +import { stripe } from '@/lib/stripe'; +import { db } from '@/lib/db'; export async function POST(request: Request) { + const signature = request.headers.get('stripe-signature'); + if (!signature || !process.env.STRIPE_WEBHOOK_SECRET) { + return NextResponse.json({ error: 'Webhook signature is required' }, { status: 400 }); + } + let event; try { - const event = await verifyStripeSignature(request); - - console.log(`📦 Received Stripe webhook: ${event.type} (${event.id})`); - - switch (event.type) { - case 'payment_intent.succeeded': - const paymentIntent = event.data.object as Stripe.PaymentIntent; - try { - await prisma.payment.update({ - where: { stripePaymentIntentId: paymentIntent.id }, - data: { - status: 'COMPLETED', - paidAt: new Date(), - metadata: paymentIntent.metadata as any, - }, - }); - console.log(`✅ Payment ${paymentIntent.id} marked as completed`); - } catch (updateError: any) { - if (updateError.code === 'P2025') { - // Payment record not found - this is normal for test webhooks - console.log(`⚠️ Payment record not found for ${paymentIntent.id} (test webhook)`); - } else { - console.error(`❌ Error updating payment ${paymentIntent.id}:`, updateError); - } - } - break; + event = stripe.webhooks.constructEvent(await request.text(), signature, process.env.STRIPE_WEBHOOK_SECRET); + } catch { + return NextResponse.json({ error: 'Invalid webhook signature' }, { status: 400 }); + } - case 'payment_intent.payment_failed': - const failedPayment = event.data.object as Stripe.PaymentIntent; - try { - await prisma.payment.update({ - where: { stripePaymentIntentId: failedPayment.id }, - data: { - status: 'FAILED', - failedAt: new Date(), - blockReason: failedPayment.last_payment_error?.message, - }, - }); - console.log(`❌ Payment ${failedPayment.id} marked as failed`); - } catch (updateError: any) { - if (updateError.code === 'P2025') { - console.log(`⚠️ Payment record not found for ${failedPayment.id} (test webhook)`); - } else { - console.error(`❌ Error updating failed payment ${failedPayment.id}:`, updateError); - } - } - break; + try { + if (event.type === 'payment_intent.succeeded') { + const intent = event.data.object; + const payment = await db.payment.findUnique({ where: { stripePaymentIntentId: intent.id } }); + if (!payment || !payment.rentalId || payment.id !== intent.metadata.paymentId) { + // An unknown payment should not be falsely marked as completed. + throw new Error('Payment record missing or metadata mismatch'); + } + if (intent.amount !== Math.round(payment.amount * 100) || intent.currency !== 'usd') { + throw new Error('Stripe payment amount does not match the stored charge'); + } - case 'charge.refunded': - const charge = event.data.object as Stripe.Charge; - const paymentIntentId = (charge.payment_intent as string); - try { - await prisma.payment.update({ - where: { stripePaymentIntentId: paymentIntentId }, - data: { - status: 'REFUNDED', - refundedAt: new Date(), - }, + await db.$transaction(async (tx) => { + await tx.payment.update({ + where: { id: payment.id }, + data: { status: 'COMPLETED', paidAt: new Date(), metadata: intent.metadata }, + }); + await tx.rental.updateMany({ + where: { id: payment.rentalId!, status: 'PENDING' }, + data: { status: 'PAID' }, + }); + }); + } else if (event.type === 'payment_intent.payment_failed') { + const intent = event.data.object; + const payment = await db.payment.findUnique({ where: { stripePaymentIntentId: intent.id } }); + if (payment && payment.status !== 'COMPLETED') { + await db.$transaction(async (tx) => { + await tx.payment.update({ where: { id: payment.id }, data: { + status: 'FAILED', failedAt: new Date(), blockReason: intent.last_payment_error?.message, + } }); + if (payment.rentalId) await tx.rental.updateMany({ + where: { id: payment.rentalId, status: 'PENDING' }, + data: { status: 'PAYMENT_FAILED' }, }); - console.log(`🔄 Payment ${paymentIntentId} marked as refunded`); - } catch (updateError: any) { - if (updateError.code === 'P2025') { - console.log(`⚠️ Payment record not found for refund ${paymentIntentId}`); - } else { - console.error(`❌ Error processing refund for ${paymentIntentId}:`, updateError); - } - } - break; - - // Identity verification events - TEMPORARILY DISABLED FOR SIMPLIFIED ONBOARDING - case 'identity.verification_session.verified': - const verificationSession = event.data.object as Stripe.Identity.VerificationSession; - if (verificationSession.metadata?.userId) { - try { - await prisma.user.update({ - where: { id: verificationSession.metadata.userId }, - data: { - idVerified: true, - idVerificationStatus: 'VERIFIED', - idVerificationDate: new Date(), - }, - }); - console.log(`✅ User ${verificationSession.metadata.userId} ID verified`); - } catch (updateError: any) { - if (updateError.code === 'P2025') { - console.log(`⚠️ User not found for ID verification: ${verificationSession.metadata.userId}`); - } else { - console.error(`❌ Error updating user verification:`, updateError); - } - } - } - break; - - case 'identity.verification_session.requires_input': - const pendingSession = event.data.object as Stripe.Identity.VerificationSession; - if (pendingSession.metadata?.userId) { - try { - await prisma.user.update({ - where: { id: pendingSession.metadata.userId }, - data: { - idVerificationStatus: 'PENDING_INPUT', - }, - }); - console.log(`⏳ User ${pendingSession.metadata.userId} verification pending input`); - } catch (updateError: any) { - if (updateError.code === 'P2025') { - console.log(`⚠️ User not found for verification update: ${pendingSession.metadata.userId}`); - } else { - console.error(`❌ Error updating user verification status:`, updateError); - } - } - } - break; - - default: - console.log(`🤷 Unhandled Stripe event type: ${event.type}`); - // Don't treat unknown events as errors - just log them + }); + } + } else if (event.type === 'charge.refunded') { + const charge = event.data.object; + const intentId = typeof charge.payment_intent === 'string' ? charge.payment_intent : charge.payment_intent?.id; + if (intentId) { + const fullyRefunded = charge.amount_refunded >= charge.amount; + await db.payment.updateMany({ + where: { stripePaymentIntentId: intentId }, + data: { refundedAt: new Date(), ...(fullyRefunded ? { status: 'REFUNDED' as const } : {}) }, + }); + } + } else if (event.type === 'identity.verification_session.verified') { + const userId = event.data.object.metadata?.userId; + if (userId) await db.user.updateMany({ where: { id: userId }, data: { + idVerified: true, idVerificationStatus: 'VERIFIED', idVerificationDate: new Date(), + } }); + } else if (event.type === 'identity.verification_session.requires_input') { + const userId = event.data.object.metadata?.userId; + if (userId) await db.user.updateMany({ where: { id: userId }, data: { + idVerified: false, idVerificationStatus: 'PENDING_INPUT', + } }); } - - return NextResponse.json({ - received: true, - eventType: event.type, - eventId: event.id, - timestamp: new Date().toISOString() - }); - + return NextResponse.json({ received: true }); } catch (error) { - console.error('❌ Stripe webhook error:', error); - - // Don't return error status for signature verification issues during development - if (process.env.NODE_ENV === 'development' && error instanceof Error && error.message.includes('signature')) { - console.log('🚧 Development mode: Allowing webhook despite signature issues'); - return NextResponse.json({ - received: true, - error: 'Signature verification failed (development mode)', - timestamp: new Date().toISOString() - }); - } - - return NextResponse.json( - { - error: 'Webhook handler failed', - message: error instanceof Error ? error.message : 'Unknown error', - timestamp: new Date().toISOString() - }, - { status: 400 } - ); + console.error('Stripe webhook processing failed', error); + // Stripe can retry a transient processing error. + return NextResponse.json({ error: 'Webhook processing failed' }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/src/app/routes/rentals/[id]/page.tsx b/src/app/routes/rentals/[id]/page.tsx index 16e099c..f586e33 100644 --- a/src/app/routes/rentals/[id]/page.tsx +++ b/src/app/routes/rentals/[id]/page.tsx @@ -6,19 +6,18 @@ import { formatCurrency, formatDateRange } from "@/lib/utils/format"; import { RentalActions } from "@/components/rentals/rental-actions"; interface RentalDetailPageProps { - params: { - id: string; - }; + params: Promise<{ id: string }>; } export default async function RentalDetailPage({ params }: RentalDetailPageProps) { // Ensure user is authenticated const user = await requireAuth(); + const { id } = await params; // Fetch the rental const rental = await db.rental.findUnique({ where: { - id: params.id, + id, }, include: { equipment: { @@ -81,11 +80,11 @@ export default async function RentalDetailPage({ params }: RentalDetailPageProps

Rental Details

Payment Status

- {rental.payment ? ( + {rental.payment?.status === "COMPLETED" ? ( Paid ) : ( Unpaid @@ -181,7 +180,7 @@ export default async function RentalDetailPage({ params }: RentalDetailPageProps {/* Review Section */} - {rental.status === "Completed" && !rental.review && !isOwner && ( + {rental.status === "COMPLETED" && !rental.review && !isOwner && (

Leave a Review

} export default async function PaymentPage({ params }: PaymentPageProps) { - const currentUser = await getCurrentUser(); - - if (!currentUser) { - redirect("/auth/login?callbackUrl=/rentals"); - } + const user = await getCurrentUser(); + if (!user) redirect("/auth/login?callbackUrl=/routes/rentals"); + const { id } = await params; const rental = await db.rental.findUnique({ - where: { - id: params.id, - renterId: currentUser.id, - }, - include: { - equipment: { - include: { - owner: true, - }, - }, - payment: true, - }, + where: { id }, + include: { equipment: { select: { title: true, owner: { select: { name: true } } } }, payment: true }, }); - - if (!rental) { - redirect("/rentals?error=rental-not-found"); - } - - if (rental.status !== "Pending") { - redirect(`/rentals?error=invalid-status&status=${rental.status}`); + if (!rental || rental.renterId !== user.id) redirect("/routes/rentals"); + if (rental.status !== 'PENDING' || Date.now() - rental.createdAt.getTime() > 30 * 60 * 1000) { + redirect("/routes/rentals?error=expired"); } - // Calculate total amount including security deposit - const totalAmount = rental.totalPrice; - const securityDeposit = rental.securityDeposit || 0; - const totalWithDeposit = totalAmount + securityDeposit; - - if (!rental.payment) { - // Create a payment record if it doesn't exist - const payment = await db.payment.create({ - data: { - amount: totalAmount, // Just the rental amount initially - currency: "USD", - status: "Pending", - userId: currentUser.id, - rentalId: rental.id, - }, - }); - - // Refresh the page to get the payment - redirect(`/routes/rentals/${rental.id}/payment`); - } + const payment = await db.payment.upsert({ + where: { rentalId: rental.id }, + update: {}, + create: { + amount: Math.round((rental.totalPrice + (rental.securityDeposit ?? 0)) * 100) / 100, + currency: 'USD', + status: 'PENDING', + userId: user.id, + rentalId: rental.id, + }, + }); return (

Complete Your Payment

-
-
-
-

Rental Details

-
-

Equipment: {rental.equipment.title}

-

Owner: {rental.equipment.owner.name}

-

Start Date: {new Date(rental.startDate).toLocaleDateString()}

-

End Date: {new Date(rental.endDate).toLocaleDateString()}

-

Rental Price: ${rental.totalPrice.toFixed(2)}

- {rental.securityDeposit && rental.securityDeposit > 0 && ( - <> -

Security Deposit: ${rental.securityDeposit.toFixed(2)}

-

Total Amount: ${totalWithDeposit.toFixed(2)}

- - )} -
-
- -
-

Payment Information

-

- Your payment is processed securely through Stripe. We do not store your card details. -

- {rental.securityDeposit && rental.securityDeposit > 0 && ( -
-

About Your Security Deposit

-

The security deposit of ${rental.securityDeposit.toFixed(2)} will be held and returned to you after the rental period, assuming the equipment is returned in the same condition.

-
- )} -

- You will only be charged once the owner approves your rental request. -

-
-
- -
- redirect("/rentals")} - /> +
+

Rental Details

+

Equipment: {rental.equipment.title}

+

Owner: {rental.equipment.owner.name}

+

Start: {rental.startDate.toLocaleDateString()}

+

End: {rental.endDate.toLocaleDateString()}

+

Rental amount: ${rental.totalPrice.toFixed(2)}

+

Refundable deposit: ${(rental.securityDeposit ?? 0).toFixed(2)}

+

Pay today: ${(rental.totalPrice + (rental.securityDeposit ?? 0)).toFixed(2)}

+

Payment is charged when you complete checkout. The owner can then start your rental.

+
); -} \ No newline at end of file +} diff --git a/src/components/payments/payment-form.tsx b/src/components/payments/payment-form.tsx index 25184db..aad57db 100644 --- a/src/components/payments/payment-form.tsx +++ b/src/components/payments/payment-form.tsx @@ -10,7 +10,6 @@ import { } from "@stripe/react-stripe-js"; import { Elements } from "@stripe/react-stripe-js"; import { getStripe } from "@/lib/stripe-client"; -import { formatAmountFromStripe } from "@/lib/stripe"; import { Loader2 } from "lucide-react"; interface PaymentFormProps { @@ -50,9 +49,6 @@ export function PaymentFormWrapper({ body: JSON.stringify({ rentalId, paymentId, - amount, - securityDeposit, - currency, }), }); @@ -94,7 +90,7 @@ export function PaymentFormWrapper({

{error}

- - {isDevelopmentMode && ( -
-

Development Mode

-

- This payment will be automatically processed after 5 seconds. No real payment will be made. -

-
- )}
- {/* If in development mode, show simplified form */} - {isDevelopmentMode ? ( -
-

Development Mode: Mock Payment Form

-
-
- -
- 4242 4242 4242 4242 (Simulated) -
-
-
-
- -
- 12/30 -
-
-
- -
- 123 -
-
-
-
-
- ) : ( - - )} + {errorMessage && (
@@ -290,7 +247,7 @@ function PaymentForm({ - -
-
- ); - } - - if (rental.status === "Approved") { - return ( -
-

Actions

- - {error && ( -
- {error} -
- )} - -
- - -
-
- ); - } + if (isOwner && rental.status === 'PAID' && rental.payment?.status === 'COMPLETED') { + actions.push({ label: 'Start rental / hand over equipment', status: 'ACTIVE' }); } - - // Actions for renter - else { - if (rental.status === "Pending") { - const hasPayment = rental.payment && rental.payment.status === "COMPLETED"; - - return ( -
-

Actions

- - {error && ( -
- {error} -
- )} - -
- {!hasPayment && ( - - )} - -
-

- {hasPayment - ? "Payment completed. Waiting for owner approval." - : "Please complete payment to proceed with your rental request."} -

-
- ); - } - - if (rental.status === "Approved") { - return ( -
-

Actions

- - {error && ( -
- {error} -
- )} - -
- - -
-
- ); - } - - if (rental.status === "Rejected") { - return ( -
-

Rental Rejected

-

- Your rental request has been rejected by the owner. -

-
- - Browse Other Equipment - -
-
- ); - } + if (isOwner && rental.status === 'ACTIVE') { + actions.push({ label: 'Mark rental completed', status: 'COMPLETED' }); } - - return null; -} \ No newline at end of file + + return ( +
+

Rental actions

+ {error &&

{error}

} + {rental.status === 'PENDING' && !isOwner && ( + + )} + {actions.map((action) => ( + + ))} + {rental.status === 'PAID' && !isOwner &&

Payment confirmed. Waiting for the owner to start the rental.

} + {rental.status === 'ACTIVE' && !isOwner &&

Rental active. Contact the owner if you need assistance.

} +
+ ); +} From 874d61154cf85ee6d21a12883f3b601c5939349d Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:26:31 -0400 Subject: [PATCH 004/152] fix: correct checkout totals and add idempotent owner transfers and deposit refunds --- src/app/api/payments/process-payout/route.ts | 205 ++++-------------- .../payments/refund-security-deposit/route.ts | 127 +++-------- src/app/api/rentals/[id]/status/route.ts | 4 +- src/app/api/webhooks/stripe/route.ts | 45 +++- src/components/payments/payment-form.tsx | 13 +- 5 files changed, 124 insertions(+), 270 deletions(-) diff --git a/src/app/api/payments/process-payout/route.ts b/src/app/api/payments/process-payout/route.ts index e49ca17..c8bda89 100644 --- a/src/app/api/payments/process-payout/route.ts +++ b/src/app/api/payments/process-payout/route.ts @@ -1,178 +1,59 @@ import { NextResponse } from 'next/server'; import { z } from 'zod'; - -import { stripe, formatAmountForStripe } from '@/lib/stripe'; +import { stripe } from '@/lib/stripe'; import { db } from '@/lib/db'; import { getCurrentUser } from '@/lib/auth/session'; -import { sendNotification, NotificationType } from '@/lib/notifications/notification-service'; -// Schema for validating the request body -const payoutSchema = z.object({ - rentalId: z.string(), -}); +const schema = z.object({ rentalId: z.string().min(1) }); export async function POST(req: Request) { - try { - // Get the current user (must be an admin) - const currentUser = await getCurrentUser(); - if (!currentUser || !currentUser.isAdmin) { - return new NextResponse('Unauthorized', { status: 401 }); - } + const admin = await getCurrentUser(); + if (!admin?.isAdmin) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); + const parsed = schema.safeParse(await req.json().catch(() => null)); + if (!parsed.success) return NextResponse.json({ error: 'Invalid request' }, { status: 400 }); - // Parse and validate the request body - const body = await req.json(); - const validationResult = payoutSchema.safeParse(body); - - if (!validationResult.success) { - return new NextResponse('Invalid request data', { status: 400 }); - } - - const { rentalId } = validationResult.data; - - // Get the rental with related data + try { const rental = await db.rental.findUnique({ - where: { - id: rentalId, - status: 'COMPLETED', // Only process payouts for completed rentals - }, - include: { - equipment: { - include: { - owner: true, - }, - }, - payment: true, - }, + where: { id: parsed.data.rentalId }, + include: { payment: true, equipment: { include: { owner: true } } }, }); - - if (!rental) { - return new NextResponse('Rental not found or not completed', { status: 404 }); - } - - if (!rental.payment || rental.payment.status !== 'COMPLETED') { - return new NextResponse('Payment not completed', { status: 400 }); + if (!rental || rental.status !== 'COMPLETED' || rental.payment?.status !== 'COMPLETED') { + return NextResponse.json({ error: 'Rental and payment must both be completed' }, { status: 409 }); } + const ownerAccount = rental.equipment.owner.stripeConnectAccountId; + if (!ownerAccount) return NextResponse.json({ error: 'Owner needs a Stripe Connect account' }, { status: 409 }); - // Check if payout has already been processed - if (rental.payment.ownerPaidOut) { - return new NextResponse('Payout already processed', { status: 400 }); + const previous = rental.payment.metadata && typeof rental.payment.metadata === 'object' && !Array.isArray(rental.payment.metadata) + ? rental.payment.metadata : {}; + if ('ownerPayoutTransferId' in previous) { + return NextResponse.json({ error: 'Owner payout already recorded' }, { status: 409 }); } - // ---- TEMPORARILY DISABLED FOR SIMPLIFIED ONBOARDING ---- - // Check if the owner has a Stripe Connect account - // if (!rental.equipment.owner.stripeConnectAccountId) { - // return new NextResponse('Equipment owner does not have a Stripe Connect account', { status: 400 }); - // } - - // Calculate platform fee (e.g., 10% of rental amount) - const platformFeePercentage = 0.10; // 10% - const rentalAmount = rental.payment.rentalAmount || rental.totalPrice; - const platformFee = rentalAmount * platformFeePercentage; - const ownerAmount = rentalAmount - platformFee; - - // ---- SIMPLIFIED DEVELOPMENT MODE - MOCK PAYOUT ---- - if (process.env.NODE_ENV === 'development') { - console.log('🚀 MOCK PAYOUT PROCESSED:', { - rentalId: rental.id, - ownerAmount, - platformFee, - ownerId: rental.equipment.owner.id - }); - - // Update the payment record (mock payout) - await db.payment.update({ - where: { - id: rental.payment.id, - }, - data: { - ownerPaidOut: true, - ownerPaidOutAmount: ownerAmount, - platformFee: platformFee, - stripeTransferId: 'mock_transfer_dev_' + Date.now(), // Mock transfer ID - }, - }); - - // Send notification to the owner - if (rental.equipment.owner.id) { - await sendNotification({ - userId: rental.equipment.owner.id, - type: NotificationType.PAYOUT_PROCESSED, - data: { - amount: ownerAmount, - propertyName: rental.equipment.name, - checkIn: rental.startDate, - checkOut: rental.endDate, - transferId: 'mock_transfer_dev' - }, - }); - } - - // Return success response - return NextResponse.json({ - success: true, - rentalId: rental.id, - ownerAmount, - platformFee, - transferId: 'mock_transfer_dev_' + Date.now(), - mode: 'development_mock' - }); - } - - // ---- PRODUCTION STRIPE CONNECT PAYOUT (COMMENTED OUT) ---- - // Process the payout using Stripe Connect - // const transfer = await stripe.transfers.create({ - // amount: formatAmountForStripe(ownerAmount, 'USD'), - // currency: 'usd', - // destination: rental.equipment.owner.stripeConnectAccountId, - // transfer_group: rental.id, - // metadata: { - // rentalId: rental.id, - // paymentId: rental.payment.id, - // equipmentId: rental.equipment.id, - // ownerId: rental.equipment.owner.id - // }, - // description: `Payout for rental of ${rental.equipment.name} from ${new Date(rental.startDate).toLocaleDateString()} to ${new Date(rental.endDate).toLocaleDateString()}` - // }); - - // // Update the payment record - // await db.payment.update({ - // where: { - // id: rental.payment.id, - // }, - // data: { - // ownerPaidOut: true, - // ownerPaidOutAmount: ownerAmount, - // platformFee: platformFee, - // stripeTransferId: transfer.id, // Store the transfer ID for reference - // }, - // }); - - // // Send notification to the owner - // if (rental.equipment.owner.id) { - // await sendNotification({ - // userId: rental.equipment.owner.id, - // type: NotificationType.PAYOUT_PROCESSED, - // data: { - // amount: ownerAmount, - // propertyName: rental.equipment.name, - // checkIn: rental.startDate, - // checkOut: rental.endDate, - // transferId: transfer.id - // }, - // }); - // } - - // // Return success response - // return NextResponse.json({ - // success: true, - // rentalId: rental.id, - // ownerAmount, - // platformFee, - // transferId: transfer.id - // }); - + // Exclude the refundable security deposit from the owner payout. + const feeCents = Math.round(rental.totalPrice * 100 * 0.10); + const ownerCents = Math.round(rental.totalPrice * 100) - feeCents; + if (ownerCents <= 0) return NextResponse.json({ error: 'Invalid payout amount' }, { status: 400 }); + + const transfer = await stripe.transfers.create({ + amount: ownerCents, + currency: 'usd', + destination: ownerAccount, + transfer_group: `RENTAL_${rental.id}`, + metadata: { rentalId: rental.id, paymentId: rental.payment.id }, + }, { idempotencyKey: `jackerbox-owner-transfer-${rental.id}-v1` }); + + await db.payment.update({ + where: { id: rental.payment.id }, + data: { metadata: { + ...previous, + ownerPayoutTransferId: transfer.id, + ownerPayoutCents: ownerCents, + platformFeeCents: feeCents, + } }, + }); + return NextResponse.json({ success: true, transferId: transfer.id }); } catch (error) { - console.error('Error processing payout:', error); - return new NextResponse('Error processing payout', { status: 500 }); + console.error('Owner payout failed', error); + return NextResponse.json({ error: 'Payout failed. Review Stripe before retrying.' }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/src/app/api/payments/refund-security-deposit/route.ts b/src/app/api/payments/refund-security-deposit/route.ts index d285386..9aa101b 100644 --- a/src/app/api/payments/refund-security-deposit/route.ts +++ b/src/app/api/payments/refund-security-deposit/route.ts @@ -1,117 +1,48 @@ import { NextResponse } from 'next/server'; import { z } from 'zod'; - -import { stripe, processSecurityDepositRefund } from '@/lib/stripe'; +import { stripe } from '@/lib/stripe'; import { db } from '@/lib/db'; import { getCurrentUser } from '@/lib/auth/session'; -import { sendNotification, NotificationType } from '@/lib/notifications/notification-service'; -// Schema for validating the request body -const refundSchema = z.object({ - rentalId: z.string(), - amount: z.number().optional(), // Optional: if not provided, refund the full amount - reason: z.string().optional(), -}); +const schema = z.object({ rentalId: z.string().min(1) }); export async function POST(req: Request) { - try { - // Get the current user (must be an admin) - const currentUser = await getCurrentUser(); - if (!currentUser || !currentUser.isAdmin) { - return new NextResponse('Unauthorized', { status: 401 }); - } - - // Parse and validate the request body - const body = await req.json(); - const validationResult = refundSchema.safeParse(body); - - if (!validationResult.success) { - return new NextResponse('Invalid request data', { status: 400 }); - } - - const { rentalId, amount, reason } = validationResult.data; + const admin = await getCurrentUser(); + if (!admin?.isAdmin) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); + const parsed = schema.safeParse(await req.json().catch(() => null)); + if (!parsed.success) return NextResponse.json({ error: 'Invalid request' }, { status: 400 }); - // Get the rental with related data + try { const rental = await db.rental.findUnique({ - where: { - id: rentalId, - status: 'COMPLETED', // Only process refunds for completed rentals - }, - include: { - user: true, - payment: true, - }, + where: { id: parsed.data.rentalId }, + include: { payment: true }, }); - - if (!rental) { - return new NextResponse('Rental not found or not completed', { status: 404 }); - } - - if (!rental.payment || rental.payment.status !== 'COMPLETED') { - return new NextResponse('Payment not completed', { status: 400 }); + if (!rental || rental.status !== 'COMPLETED' || + !rental.payment || rental.payment.status !== 'COMPLETED' || + !rental.payment.stripePaymentIntentId) { + return NextResponse.json({ error: 'Rental must be completed and paid before deposit return' }, { status: 409 }); } + const depositCents = Math.round((rental.securityDeposit ?? 0) * 100); + if (depositCents <= 0) return NextResponse.json({ error: 'No security deposit' }, { status: 409 }); - // Check if security deposit exists - if (!rental.payment.securityDepositAmount || rental.payment.securityDepositAmount <= 0) { - return new NextResponse('No security deposit to refund', { status: 400 }); + const previous = rental.payment.metadata && typeof rental.payment.metadata === 'object' && !Array.isArray(rental.payment.metadata) + ? rental.payment.metadata : {}; + if ('securityDepositRefundId' in previous) { + return NextResponse.json({ error: 'Deposit refund already recorded' }, { status: 409 }); } - // Check if security deposit has already been returned - if (rental.payment.securityDepositReturned) { - return new NextResponse('Security deposit already returned', { status: 400 }); - } - - // Get the payment intent ID - const paymentIntentId = rental.payment.stripePaymentIntentId; - if (!paymentIntentId) { - return new NextResponse('No payment intent ID found', { status: 400 }); - } - - // Calculate the refund amount in cents - const refundAmount = amount || rental.payment.securityDepositAmount; - const refundAmountInCents = Math.round(refundAmount * 100); - - // Process the refund - const refund = await processSecurityDepositRefund( - paymentIntentId, - refundAmountInCents, - reason - ); + const refund = await stripe.refunds.create({ + payment_intent: rental.payment.stripePaymentIntentId, + amount: depositCents, + }, { idempotencyKey: `jackerbox-security-deposit-${rental.id}-v1` }); - // Update the payment record await db.payment.update({ - where: { - id: rental.payment.id, - }, - data: { - securityDepositReturned: true, - updatedAt: new Date(), - }, - }); - - // Send notification to the user - if (rental.user.id) { - await sendNotification({ - userId: rental.user.id, - type: NotificationType.SECURITY_DEPOSIT_RETURNED, - data: { - amount: refundAmount, - propertyName: rental.equipmentId, // Use equipment name if available - checkIn: rental.startDate, - checkOut: rental.endDate, - rentalId: rental.id, - }, - }); - } - - // Return success response - return NextResponse.json({ - success: true, - refundId: refund.id, - amount: refundAmount, + where: { id: rental.payment.id }, + data: { metadata: { ...previous, securityDepositRefundId: refund.id, securityDepositRefundCents: depositCents } }, }); + return NextResponse.json({ success: true, refundId: refund.id, amount: depositCents / 100 }); } catch (error) { - console.error('Error processing security deposit refund:', error); - return new NextResponse('Error processing security deposit refund', { status: 500 }); + console.error('Security deposit refund failed', error); + return NextResponse.json({ error: 'Refund failed. Review Stripe before retrying.' }, { status: 500 }); } -} \ No newline at end of file +} diff --git a/src/app/api/rentals/[id]/status/route.ts b/src/app/api/rentals/[id]/status/route.ts index a8cff14..3d1f7fb 100644 --- a/src/app/api/rentals/[id]/status/route.ts +++ b/src/app/api/rentals/[id]/status/route.ts @@ -15,7 +15,7 @@ export async function PATCH(req: Request, { params }: { params: Promise<{ id: st try { const rental = await db.rental.findUnique({ where: { id }, - include: { equipment: { select: { ownerId: true } }, payment: { select: { status: true } } }, + include: { equipment: { select: { ownerId: true } }, payment: { select: { status: true, stripePaymentIntentId: true } } }, }); if (!rental) return NextResponse.json({ message: 'Rental not found' }, { status: 404 }); @@ -24,7 +24,7 @@ export async function PATCH(req: Request, { params }: { params: Promise<{ id: st if (!isOwner && !isRenter) return NextResponse.json({ message: 'Forbidden' }, { status: 403 }); const target = result.data.status; - const valid = (target === 'CANCELLED' && rental.status === 'PENDING' && (isOwner || isRenter)) || + const valid = (target === 'CANCELLED' && rental.status === 'PENDING' && !rental.payment?.stripePaymentIntentId && (isOwner || isRenter)) || (target === 'ACTIVE' && isOwner && rental.status === 'PAID' && rental.payment?.status === 'COMPLETED') || (target === 'COMPLETED' && isOwner && rental.status === 'ACTIVE' && rental.payment?.status === 'COMPLETED'); diff --git a/src/app/api/webhooks/stripe/route.ts b/src/app/api/webhooks/stripe/route.ts index b99edc4..ed5ef05 100644 --- a/src/app/api/webhooks/stripe/route.ts +++ b/src/app/api/webhooks/stripe/route.ts @@ -26,15 +26,54 @@ export async function POST(request: Request) { throw new Error('Stripe payment amount does not match the stored charge'); } + if (payment.status === 'COMPLETED') return NextResponse.json({ received: true }); + + // A payment confirmed after a reservation expired or after another rental + // took the same dates must be returned, not activated as a double booking. + const rental = await db.rental.findUnique({ where: { id: payment.rentalId } }); + if (!rental) throw new Error('Rental missing for paid intent'); + const confirmedAt = new Date(event.created * 1000); + const expired = confirmedAt.getTime() - rental.createdAt.getTime() > 30 * 60 * 1000; + const conflicting = await db.rental.findFirst({ + where: { + id: { not: rental.id }, + equipmentId: rental.equipmentId, + startDate: { lt: rental.endDate }, + endDate: { gt: rental.startDate }, + status: { in: ['PAID', 'ACTIVE'] }, + }, + select: { id: true }, + }); + if (rental.status !== 'PENDING' || expired || conflicting) { + await stripe.refunds.create({ payment_intent: intent.id }, { + idempotencyKey: `jackerbox-invalid-booking-${intent.id}`, + }); + await db.payment.update({ where: { id: payment.id }, data: { status: 'REFUNDED', refundedAt: new Date() } }); + await db.rental.updateMany({ where: { id: rental.id, status: 'PENDING' }, data: { status: 'REFUNDED' } }); + return NextResponse.json({ received: true }); + } + await db.$transaction(async (tx) => { + const conflict = await tx.rental.findFirst({ + where: { + id: { not: rental.id }, + equipmentId: rental.equipmentId, + startDate: { lt: rental.endDate }, + endDate: { gt: rental.startDate }, + status: { in: ['PAID', 'ACTIVE'] }, + }, + select: { id: true }, + }); + if (conflict) throw new Error('Booking conflict during payment confirmation'); await tx.payment.update({ where: { id: payment.id }, - data: { status: 'COMPLETED', paidAt: new Date(), metadata: intent.metadata }, + data: { status: 'COMPLETED', paidAt: confirmedAt, metadata: intent.metadata }, }); - await tx.rental.updateMany({ - where: { id: payment.rentalId!, status: 'PENDING' }, + const result = await tx.rental.updateMany({ + where: { id: rental.id, status: 'PENDING' }, data: { status: 'PAID' }, }); + if (result.count !== 1) throw new Error('Rental state changed during payment confirmation'); }); } else if (event.type === 'payment_intent.payment_failed') { const intent = event.data.object; diff --git a/src/components/payments/payment-form.tsx b/src/components/payments/payment-form.tsx index aad57db..7a6e3c7 100644 --- a/src/components/payments/payment-form.tsx +++ b/src/components/payments/payment-form.tsx @@ -54,7 +54,7 @@ export function PaymentFormWrapper({ if (!response.ok) { const errorData = await response.json(); - throw new Error(errorData.message || "Failed to create payment intent"); + throw new Error(errorData.message || errorData.error || "Failed to create payment intent"); } const data = await response.json(); @@ -106,7 +106,7 @@ export function PaymentFormWrapper({ Unable to initialize payment. Please try again later.

- - - )} - - {rental.status === "Approved" && ( - - )} - - {rental.status === "Completed" && viewType === "renter" && !rental.review && ( + {/* Rental state changes are handled on the detail page with access checks. */} + {rental.status === "COMPLETED" && viewType === "renter" && !rental.review && ( Date: Sat, 10 Oct 2026 09:40:24 -0400 Subject: [PATCH 018/152] test: share pricing logic with production and cover booking overlap cases --- src/app/api/rentals/route.ts | 6 ++---- src/lib/rentals/pricing.ts | 19 +++++++++++++++++++ tests/unit/rental-pricing.test.ts | 25 +++++++++++++++++++++++++ tests/unit/security-guardrails.test.ts | 2 +- 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 src/lib/rentals/pricing.ts create mode 100644 tests/unit/rental-pricing.test.ts diff --git a/src/app/api/rentals/route.ts b/src/app/api/rentals/route.ts index 72217e9..fc994c4 100644 --- a/src/app/api/rentals/route.ts +++ b/src/app/api/rentals/route.ts @@ -3,6 +3,7 @@ import { z } from 'zod'; import { Prisma } from '../../../../prisma/generated/client'; import { db } from '@/lib/db'; import { getCurrentUser } from '@/lib/auth/session'; +import { calculateRentalPrice } from '@/lib/rentals/pricing'; const DAY = 24 * 60 * 60 * 1000; const PENDING_HOLD_MS = 30 * 60 * 1000; @@ -65,10 +66,7 @@ export async function POST(request: NextRequest) { if (rate == null || !Number.isFinite(rate) || rate <= 0) { throw new ConflictError('The selected rental rate is unavailable'); } - const duration = end.getTime() - start.getTime(); - const units = rentalType === 'hourly' ? Math.ceil(duration / (60 * 60 * 1000)) - : rentalType === 'weekly' ? Math.ceil(duration / (7 * DAY)) : Math.ceil(duration / DAY); - const totalPrice = Math.round(rate * units * 100) / 100; + const totalPrice = calculateRentalPrice(rate, start, end, rentalType); if (!Number.isFinite(totalPrice) || totalPrice <= 0) throw new ConflictError('Invalid rental price'); // Block date-level blackout days, including any part of the requested rental window. diff --git a/src/lib/rentals/pricing.ts b/src/lib/rentals/pricing.ts new file mode 100644 index 0000000..9f4f740 --- /dev/null +++ b/src/lib/rentals/pricing.ts @@ -0,0 +1,19 @@ +export type RentalRateUnit = 'hourly' | 'daily' | 'weekly'; + +const HOUR = 60 * 60 * 1000; +const DAY = 24 * HOUR; + +export function calculateRentalPrice(rate: number, start: Date, end: Date, type: RentalRateUnit): number { + const duration = end.getTime() - start.getTime(); + if (!Number.isFinite(rate) || rate <= 0 || !Number.isFinite(duration) || duration <= 0) { + throw new Error('Invalid rental price or duration'); + } + const unit = type === 'hourly' ? HOUR : type === 'weekly' ? 7 * DAY : DAY; + const total = Math.round(rate * Math.ceil(duration / unit) * 100) / 100; + if (!Number.isFinite(total) || total <= 0) throw new Error('Invalid rental total'); + return total; +} + +export function rentalDatesOverlap(startA: Date, endA: Date, startB: Date, endB: Date) { + return startA < endB && endA > startB; +} diff --git a/tests/unit/rental-pricing.test.ts b/tests/unit/rental-pricing.test.ts new file mode 100644 index 0000000..ae744a9 --- /dev/null +++ b/tests/unit/rental-pricing.test.ts @@ -0,0 +1,25 @@ +import { calculateRentalPrice, rentalDatesOverlap } from '../../src/lib/rentals/pricing'; + +const t = (iso: string) => new Date(iso); + +describe('JackerBox actual rental pricing', () => { + test('hourly pricing rounds partial hours up', () => { + expect(calculateRentalPrice(25, t('2026-10-11T10:00:00Z'), t('2026-10-11T12:30:00Z'), 'hourly')).toBe(75); + }); + test('daily pricing respects exact full days', () => { + expect(calculateRentalPrice(150, t('2026-10-11T00:00:00Z'), t('2026-10-14T00:00:00Z'), 'daily')).toBe(450); + }); + test('weekly pricing rounds partial weeks up', () => { + expect(calculateRentalPrice(800, t('2026-10-11T00:00:00Z'), t('2026-10-26T00:00:00Z'), 'weekly')).toBe(2400); + }); + test('rejects negative or zero rates and reversed date range', () => { + expect(() => calculateRentalPrice(-1, t('2026-10-11'), t('2026-10-12'), 'daily')).toThrow(); + expect(() => calculateRentalPrice(50, t('2026-10-12'), t('2026-10-11'), 'daily')).toThrow(); + }); + test('two rental windows overlapping are rejected', () => { + expect(rentalDatesOverlap(t('2026-10-11'), t('2026-10-13'), t('2026-10-12'), t('2026-10-14'))).toBe(true); + }); + test('back-to-back rentals do not overlap', () => { + expect(rentalDatesOverlap(t('2026-10-11'), t('2026-10-13'), t('2026-10-13'), t('2026-10-15'))).toBe(false); + }); +}); diff --git a/tests/unit/security-guardrails.test.ts b/tests/unit/security-guardrails.test.ts index 4017250..bdb9941 100644 --- a/tests/unit/security-guardrails.test.ts +++ b/tests/unit/security-guardrails.test.ts @@ -24,7 +24,7 @@ describe('JackerBox security regression checks', () => { test('browser-supplied rental pricing is not trusted', () => { const route = content('src/app/api/rentals/route.ts'); - expect(route).toContain('Math.round(rate * units * 100)'); + expect(route).toContain('calculateRentalPrice(rate, start, end, rentalType)'); expect(route).toContain('TransactionIsolationLevel.Serializable'); expect(route).not.toContain('parseFloat(totalPrice)'); }); From 96622ead0c3f03e6c07341ba8a96e667dbe0413d Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:40:46 -0400 Subject: [PATCH 019/152] ci: run booking tests and fail release checks on type and dependency errors --- .github/workflows/jackerbox-repair.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/jackerbox-repair.yml b/.github/workflows/jackerbox-repair.yml index 36f94ea..5ab466a 100644 --- a/.github/workflows/jackerbox-repair.yml +++ b/.github/workflows/jackerbox-repair.yml @@ -21,17 +21,16 @@ jobs: persist-credentials: false - uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: npm - name: Install dependencies run: npm ci --legacy-peer-deps - name: Generate Prisma client run: npx prisma generate - name: Verify security repair regression tests - run: npx jest tests/unit/security-guardrails.test.ts --runInBand - - name: TypeScript diagnostics + run: npx jest tests/unit/security-guardrails.test.ts tests/unit/rental-pricing.test.ts --runInBand + - name: TypeScript diagnostics (release gate) run: npx tsc --noEmit - continue-on-error: true - - name: Dependency audit + - name: Dependency audit (release gate) + if: always() run: npm audit --omit=dev --audit-level=high - continue-on-error: true From ba10978301185a88d628f71f646cac36e442ccf2 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:41:42 -0400 Subject: [PATCH 020/152] ci: safely rebase dependency lockfile fixes before updating repair branch --- .github/workflows/jackerbox-safe-audit-fix.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/jackerbox-safe-audit-fix.yml b/.github/workflows/jackerbox-safe-audit-fix.yml index 50e933c..419f71a 100644 --- a/.github/workflows/jackerbox-safe-audit-fix.yml +++ b/.github/workflows/jackerbox-safe-audit-fix.yml @@ -32,4 +32,6 @@ jobs: git add -- package.json package-lock.json if git diff --cached --quiet; then exit 0; fi git commit -m "security: apply non-breaking npm advisory fixes [skip ci]" + git fetch --no-tags origin audit/security-and-rental-hardening-2026-10 + git rebase FETCH_HEAD git push origin HEAD:audit/security-and-rental-hardening-2026-10 From f18613c076c2521d782fd2092cd488865a0ad935 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 10 Oct 2026 13:44:23 +0000 Subject: [PATCH 021/152] security: apply non-breaking npm advisory fixes [skip ci] --- package-lock.json | 4454 ++++++++++++++++----------------------------- 1 file changed, 1607 insertions(+), 2847 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f0a137..3364f5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -150,173 +150,187 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "node_modules/@arcjet/analyze": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/analyze/-/analyze-1.14.1.tgz", + "integrity": "sha512-/ifvV/anlvb0XjHP+P5FKm5XS1MQXFH3VWTe73wbOGh+lzD9CGGEiHCIMhCvlEnJmRwoRKpeT3OYh6pJMLn5BA==", "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@arcjet/analyze-wasm": "1.14.1", + "@arcjet/protocol": "1.14.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=22.21.0 <23 || >=24.5.0" } }, - "node_modules/@arcjet/analyze": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/analyze/-/analyze-1.0.0-beta.6.tgz", - "integrity": "sha512-oWvxdNdrR4qMNsrr4y9TdYsuXlx/M8sdN6iENqBwFjUBCfksYrQAzHUr6maDr1ey/g38DXdxXNhGL3PWs0XFJA==", + "node_modules/@arcjet/analyze-wasm": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/analyze-wasm/-/analyze-wasm-1.14.1.tgz", + "integrity": "sha512-7HcQOaNlWty5iXR1aM18/afG8by8L7mt5BFe47liZPf9sIsAmQFiUsDyRVbkKzYca1TXHLm4QGGn1Ko+8G9cyQ==", "license": "Apache-2.0", - "dependencies": { - "@arcjet/analyze-wasm": "1.0.0-beta.6", - "@arcjet/protocol": "1.0.0-beta.6" - }, "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, - "node_modules/@arcjet/analyze-wasm": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/analyze-wasm/-/analyze-wasm-1.0.0-beta.6.tgz", - "integrity": "sha512-xi4qnr0li8jGks1SN9aTqe9JFjGzwVoxcAOQm5+zFE08S3Ly5hK5Nm4dyZG5FQQY4D74XWaG/YEl1i0F+RrSvA==", + "node_modules/@arcjet/body": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/body/-/body-1.14.1.tgz", + "integrity": "sha512-GocI9RCucdfsuDfoGvqVbIM1NVxj0w97zJLpWlxbgFcPFIrapQKhM3JF/nioy8IJrhlay0fbNOSnPff5TcQh0Q==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" + } + }, + "node_modules/@arcjet/cache": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/cache/-/cache-1.14.1.tgz", + "integrity": "sha512-lncLtwhRrH9LmXX/yRFa1TjJPN6MQKNW5JQPlr8Po7xwMojNmizOmp3SUYwRDTrXTxzxavB/L3S5jz381huQeQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/duration": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/duration/-/duration-1.0.0-beta.6.tgz", - "integrity": "sha512-r0AVHz7papWvbEPybYadzaGsSrA+UYYkNG0YzTbXGELCBpDDwKrN1mGtMNPdyxUKuzt6bYYW18OPwzNuY41osw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/duration/-/duration-1.14.1.tgz", + "integrity": "sha512-HbJMDjwY7vDdgFTiuPmI1LD/pst5IegCAbMtNqLTiAFpgJmtutt8gMUvfsoCdSad00eEfTfO4qIufp4M2zEhqw==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/env": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/env/-/env-1.0.0-beta.6.tgz", - "integrity": "sha512-WFehWJShBLt9JiniW4Jc+lLSe9c7M7ThvnCj3sOn5pudZ1Kvlxwic39QzYl+7GEp5QVFqNyfci0daMSTeYyIAw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/env/-/env-1.14.1.tgz", + "integrity": "sha512-v8uvPl/FUNrtzQ+uhMomZIHhgsOVY4Bpn9xNgJ+/1Dhc9YaX+RrgAhtA/hbvEehWX21JrPkg3OYYNg5OyHxQbg==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/headers": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/headers/-/headers-1.0.0-beta.6.tgz", - "integrity": "sha512-u8x3SS4tw6FZOq8md/yA6iqFX9UQpSr+66iL2J8vaegLxocgTBzsij9JKcENs/W8B/qH1D4Y6Q8OnN5xjtrNwg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/headers/-/headers-1.14.1.tgz", + "integrity": "sha512-FdOnZQwI061i7iaALqc0G1dPIL40vy7PSFy1vh39KULOjQIGGlyRUFxsjTsEHEiSSE5/18aZ3FHTNa21TtvI0g==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/ip": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/ip/-/ip-1.0.0-beta.6.tgz", - "integrity": "sha512-ugMOBkpZ6pKBL9uF/KOYBU9blVhi6AwpkQydeiVAmip9Cg0mA1H1cBh2DEItRpuMUKXg24rTwTrd2l68qxq7Yw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/ip/-/ip-1.14.1.tgz", + "integrity": "sha512-I9CsQHIpP1j/obDW4DLcNucJ+WKpqvlBIOjUxSgUVGq0G9wgP1qsO8ByPdCR3vWQtnQMJpGv4l6qhP3woOU9lQ==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/logger": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/logger/-/logger-1.0.0-beta.6.tgz", - "integrity": "sha512-v/0WT5VRgyOkDbjn9GWEL3O1zh8LCuT+r4MEiZ/ECq5rEH3ssN54F5FfN48AotvJ3r7CFQFb2MUPmagYz5w6JQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/logger/-/logger-1.14.1.tgz", + "integrity": "sha512-9xCRIkb+Ve/lqLThYl3LGhCHpz/W5L0OTRKvFgmecDscPD6r0XrqXyK4WwU+pCDVMJnIhsOQKUWulBQpHOsHDw==", "license": "Apache-2.0", "dependencies": { - "@arcjet/sprintf": "1.0.0-beta.6" + "@arcjet/sprintf": "1.14.1" }, "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/next": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/next/-/next-1.0.0-beta.6.tgz", - "integrity": "sha512-+0JQISkjiRdvRlZ7uVVgPzT0w5s7CbNsArfhoIxRR7pepXBPv+PT4amRJR3JJjqGG4RHui5QrZOXWzX1WtyxjA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/next/-/next-1.14.1.tgz", + "integrity": "sha512-KoDGqAnzsgZRoIcAYuO8+ytRK3rEGiJo+0n4e1bJsM8ZJdlMOnuwEj5nmkmx3pMwg64qIkjhKcomsavcOuYHZg==", "license": "Apache-2.0", "dependencies": { - "@arcjet/env": "1.0.0-beta.6", - "@arcjet/headers": "1.0.0-beta.6", - "@arcjet/ip": "1.0.0-beta.6", - "@arcjet/logger": "1.0.0-beta.6", - "@arcjet/protocol": "1.0.0-beta.6", - "@arcjet/transport": "1.0.0-beta.6", - "arcjet": "1.0.0-beta.6" + "@arcjet/body": "1.14.1", + "@arcjet/env": "1.14.1", + "@arcjet/headers": "1.14.1", + "@arcjet/ip": "1.14.1", + "@arcjet/logger": "1.14.1", + "@arcjet/protocol": "1.14.1", + "@arcjet/transport": "1.14.1", + "arcjet": "1.14.1" }, "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" }, "peerDependencies": { "next": ">=13" } }, "node_modules/@arcjet/protocol": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/protocol/-/protocol-1.0.0-beta.6.tgz", - "integrity": "sha512-pD2JldnObwguoArvk/F3OOJYbRsiPnzTWJ9Y/EhedszYS3vf02K3lb+KHwdTof60EmOh00iLrtE2NxRT+cSEyA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/protocol/-/protocol-1.14.1.tgz", + "integrity": "sha512-SvP37kfeXaSHIFkVU94tUstw5BcgIiQJXLu3QPFnc8e1yxfB1cvyMeTNNdO6ToAyxE4j+ecgg+0y/rTJqkrvkA==", "license": "Apache-2.0", "dependencies": { - "@bufbuild/protobuf": "1.10.0", - "@connectrpc/connect": "1.6.1", - "typeid-js": "1.2.0" + "@arcjet/cache": "1.14.1", + "@bufbuild/protobuf": "2.15.0", + "@connectrpc/connect": "2.2.0" }, "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/runtime": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/runtime/-/runtime-1.0.0-beta.6.tgz", - "integrity": "sha512-Zst6CtlUXjWIdYfG9Ny9YjqxewyGVszKhtcCaMnDL8i/lbEIh/vY+kRLjf09cYH/v+bcwbwXN8ZzVfdu3nzfIg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/runtime/-/runtime-1.14.1.tgz", + "integrity": "sha512-G2hAfpPI68nzZQ/m1MWwiwE9cubgVGlgaIGNYvsaM3B9Bil/6SiSaovDlC9gYH4lspSX3v96mvBuNywC2/96rw==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" + } + }, + "node_modules/@arcjet/skills": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/skills/-/skills-1.14.1.tgz", + "integrity": "sha512-tQgFwH1mfkyyIilch0h1kUn3l4oHb2OFbTQnD7qqx0lTYuEWPW8P9/TsKHr/f5bxeRodqNIQS1eM3bLhULNj4A==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/@arcjet/sprintf": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/sprintf/-/sprintf-1.0.0-beta.6.tgz", - "integrity": "sha512-3ejdH/oTKtAYSQCafi+0pF56otz0crCE/Sx3pA2OPMzG0pPnLAY3/IaN45L528dYp5XYGn0/oxSS6hKJnauYcA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/sprintf/-/sprintf-1.14.1.tgz", + "integrity": "sha512-XKRvFwQfOny3XfQVHTiBf1ttMhMFYPIQAOHQsMtGLSub8npmhqrA6/w0Wq9NNbgXz9686YMJ7edvdhNXNgzhTg==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, - "node_modules/@arcjet/transport": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@arcjet/transport/-/transport-1.0.0-beta.6.tgz", - "integrity": "sha512-9VCgk9nT9Gawmpw8zPfE4fG07soBcvZJvPc18yiE12PirxesDdZaenkUftMR0Ks8vczd7uyLSfdOtHYQA/l8hA==", + "node_modules/@arcjet/stable-hash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/stable-hash/-/stable-hash-1.14.1.tgz", + "integrity": "sha512-2TGK361o6JizaAKb60wu3FsXxdhYFeI4yoQX0xkz4Ux7rnUxGBLmeM8oL90WjOr0r9injmHCQOPndBO8LHhASQ==", "license": "Apache-2.0", - "dependencies": { - "@bufbuild/protobuf": "1.10.0", - "@connectrpc/connect": "1.6.1", - "@connectrpc/connect-node": "1.6.1", - "@connectrpc/connect-web": "1.6.1" - }, "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, - "node_modules/@auth/prisma-adapter": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-2.9.1.tgz", - "integrity": "sha512-0ZfjOPt3Ci8yx8SMCydAuBAjR/exI/8SAr6JDVYtqDFhm0JaV1XuHYgEzgzXZZfW2+WKC29LowCWxdCjoAz9kQ==", - "license": "ISC", + "node_modules/@arcjet/transport": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@arcjet/transport/-/transport-1.14.1.tgz", + "integrity": "sha512-yLit6yx3TyX/9veislVYDZbxhI/1MahIH3Xc6ofDJHLDFgIAsHqdWOQaF+M8O5+wwbjWOZrHr2h8boxVptfafg==", + "license": "Apache-2.0", "dependencies": { - "@auth/core": "0.39.1" + "@arcjet/env": "1.14.1", + "@arcjet/logger": "1.14.1", + "@bufbuild/protobuf": "2.15.0", + "@connectrpc/connect": "2.2.0", + "@connectrpc/connect-node": "2.2.0", + "@connectrpc/connect-web": "2.2.0" }, - "peerDependencies": { - "@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5 || >=6" + "engines": { + "node": ">=22.21.0 <23 || >=24.5.0" } }, - "node_modules/@auth/prisma-adapter/node_modules/@auth/core": { - "version": "0.39.1", - "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.39.1.tgz", - "integrity": "sha512-McD8slui0oOA1pjR5sPjLPl5Zm//nLP/8T3kr8hxIsvNLvsiudYvPHhDFPjh1KcZ2nFxCkZmP6bRxaaPd/AnLA==", + "node_modules/@auth/core": { + "version": "0.41.3", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.3.tgz", + "integrity": "sha512-sJ3JMHHkXMD3aOjopv7mOBTO1Ocw4b0fAEXJBz6k7YHLpYQI6C40jCUPc5fNvUKxXRXNE1/sRISA15UrwWJBTw==", "license": "ISC", "dependencies": { "@panva/hkdf": "^1.2.1", @@ -328,7 +342,7 @@ "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.2", - "nodemailer": "^6.8.0" + "nodemailer": "^7.0.7 || ^8.0.5" }, "peerDependenciesMeta": { "@simplewebauthn/browser": { @@ -342,25 +356,16 @@ } } }, - "node_modules/@auth/prisma-adapter/node_modules/jose": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.0.11.tgz", - "integrity": "sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/@auth/prisma-adapter/node_modules/oauth4webapi": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.1.tgz", - "integrity": "sha512-txg/jZQwcbaF7PMJgY7aoxc9QuCxHVFMiEkDIJ60DwDz3PbtXPQnrzo+3X4IRYGChIwWLabRBRpf1k9hO9+xrQ==", + "node_modules/@auth/core/node_modules/jose": { + "version": "6.2.12", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", + "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } }, - "node_modules/@auth/prisma-adapter/node_modules/preact-render-to-string": { + "node_modules/@auth/core/node_modules/preact-render-to-string": { "version": "6.5.11", "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz", "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==", @@ -369,1162 +374,509 @@ "preact": ">=10" } }, - "node_modules/@aws-crypto/crc32": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", - "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", - "license": "Apache-2.0", + "node_modules/@auth/prisma-adapter": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-2.11.3.tgz", + "integrity": "sha512-jZbpVAO6PTc9zNtdTWc0RLWG8qap4iMc54/3oWaWbuKdj92wHxzPrs3HivWB2mB9975GPW0l3YM/wFUWiUlTlg==", + "license": "ISC", "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" + "@auth/core": "0.41.3" }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/crc32c": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", - "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha1-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", - "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" + "peerDependencies": { + "@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5 || >=6" } }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "node_modules/@aws-sdk/checksums": { + "version": "3.1001.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1001.2.tgz", + "integrity": "sha512-gKRj5IXZ/O0ehk2rwfb55YygdNKNhK5N1l/Ztg/w06tk21AJtCPuyErETk2RS/6XOmpBkcZY6CN3GlQ2fWTh1g==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "node_modules/@aws-sdk/client-rekognition": { + "version": "3.1149.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-rekognition/-/client-rekognition-3.1149.0.tgz", + "integrity": "sha512-Mr0AtymXsWIX+85mbt95Z9Nh917YEvl5JkF+TlgI8vGi4+uKFDuRf3sS5o5Us/eoY/5fvludduScXOcMJqAiGw==", "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/credential-provider-node": "^3.972.85", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "node_modules/@aws-sdk/client-s3": { + "version": "3.1149.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1149.0.tgz", + "integrity": "sha512-wEccG+3/ap7iIBO4DbWwqNHh2u5Qm5OCQJzJaAvtVFIoZbp0qia8HIXv4rpnNmJJEX8205mlq67F9QJ0nKlcxg==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", + "@aws-sdk/checksums": "^3.1001.2", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/credential-provider-node": "^3.972.85", + "@aws-sdk/middleware-sdk-s3": "^3.972.78", + "@aws-sdk/signature-v4-multi-region": "^3.996.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "license": "Apache-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.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "node_modules/@aws-sdk/core": { + "version": "3.978.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.2.tgz", + "integrity": "sha512-ViOBLuGSSyPAmkKGJ6KJXtVN7MOEp3rnI7uH+kWxnHccvo8C9cvunEAnN5/oaZH1laQfsTBw7IOnmNkWlFZl2A==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/types": "^3.974.6", + "@aws-sdk/xml-builder": "^3.972.41", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.35.2", + "@smithy/signature-v4": "^5.7.4", + "@smithy/types": "^4.19.0", + "bowser": "^2.11.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.72.tgz", + "integrity": "sha512-UlY1+6rV1K7bFeMivM6qfQuVSBrkm/3fXBDzQO+3izAMZ64JAm0QQquCV+Ib/fGJgMNe02koq/Bgs1SBZTwfZw==", "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", + "@aws-sdk/nested-clients": "^3.997.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.73", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.73.tgz", + "integrity": "sha512-PxlFZiF5IPUsPnuVSqjM9jlmRwZhL0xx40ccWfZiLQS8TRnHQpegpK1uAidatWuEqbJtbbY97A2Sezikz2AMUw==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.75", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.75.tgz", + "integrity": "sha512-Q/uIDy8eAVN7JgSKDg16F/f+hmNJj/ZyLJN8AkW2ofVdDgJVh8fO/A26iZ7YsvM2/k76hsf/u2lLAtyXsK8Ziw==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.18", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.18.tgz", + "integrity": "sha512-KoyjZ9vdjuxEQ8obAH06xKP8H0WKqGhwUZLMqAOiS7G0xgUAht4X8f0ASLC/vhNLCWGblZOD3VQHWyTROGJHLg==", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/credential-provider-env": "^3.972.73", + "@aws-sdk/credential-provider-http": "^3.972.75", + "@aws-sdk/credential-provider-login": "^3.972.80", + "@aws-sdk/credential-provider-process": "^3.972.73", + "@aws-sdk/credential-provider-sso": "^3.973.17", + "@aws-sdk/credential-provider-web-identity": "^3.972.79", + "@aws-sdk/nested-clients": "^3.997.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.80", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.80.tgz", + "integrity": "sha512-xF9A0gaO7k+1dYPFoo69OQatA9Ov0QuDZfqE8H0FLyIoOph+mlEC+I1Qo9UULupGuDfSYh+kVpfcDSxSYf/2fg==", "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/nested-clients": "^3.997.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.85", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.85.tgz", + "integrity": "sha512-CrFcML/xImiSlquH4W3V6Npz3aSkPXHDVciAU1JOBN0vqjmkcz9H9up2sCHQqN76J/WrT+TJ580L8h2joksQrg==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", + "@aws-sdk/credential-provider-env": "^3.972.73", + "@aws-sdk/credential-provider-http": "^3.972.75", + "@aws-sdk/credential-provider-ini": "^3.973.18", + "@aws-sdk/credential-provider-process": "^3.972.73", + "@aws-sdk/credential-provider-sso": "^3.973.17", + "@aws-sdk/credential-provider-web-identity": "^3.972.79", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.787.0.tgz", - "integrity": "sha512-7v6nywZ5wcQxX7qdZ5M1ld15QdkzLU6fAKiEqbvJKu4dM8cFW6As+DbS990Mg46pp1xM/yvme+51xZDTfTfJZA==", + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.73", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.73.tgz", + "integrity": "sha512-tyNnT4aVuOEXmKKKZPExBi828vRd9heshobBsKF0bov5EORHSJc1AGsHOMRP57sDt+dIuVASUOywaixiX26t4g==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-node": "3.787.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-rekognition": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-rekognition/-/client-rekognition-3.787.0.tgz", - "integrity": "sha512-0HUudIPlOTyOFtlMhLvJM8kcU56hetko4xqBiKhvp9qNcNc8MnLbiANXOWYfLoAZDG5OxQYXIeWEpvXiRDUinQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-node": "3.787.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.3", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-rekognition/node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "license": "MIT" - }, - "node_modules/@aws-sdk/client-rekognition/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.787.0.tgz", - "integrity": "sha512-eGLCWkN0NlntJ9yPU6OKUggVS4cFvuZJog+cFg1KD5hniLqz7Y0YRtB4uBxW212fK3XCfddgyscEOEeHaTQQTw==", + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.17", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.17.tgz", + "integrity": "sha512-gxKTWaUk2gSbBOH4m3NPRfEKcGXeDAOgHr7nNG5JktR1xZLo0R+DpMjbcleoHbB0uJREOG7hjIRE635IuBWsRQ==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha1-browser": "5.2.0", - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-node": "3.787.0", - "@aws-sdk/middleware-bucket-endpoint": "3.775.0", - "@aws-sdk/middleware-expect-continue": "3.775.0", - "@aws-sdk/middleware-flexible-checksums": "3.787.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-location-constraint": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-sdk-s3": "3.775.0", - "@aws-sdk/middleware-ssec": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/signature-v4-multi-region": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@aws-sdk/xml-builder": "3.775.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/eventstream-serde-browser": "^4.0.2", - "@smithy/eventstream-serde-config-resolver": "^4.1.0", - "@smithy/eventstream-serde-node": "^4.0.2", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-blob-browser": "^4.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/hash-stream-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/md5-js": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-stream": "^4.2.0", - "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.3", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/nested-clients": "^3.997.47", + "@aws-sdk/token-providers": "3.1149.0", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.787.0.tgz", - "integrity": "sha512-L8R+Mh258G0DC73ktpSVrG4TT9i2vmDLecARTDR/4q5sRivdDQSL5bUp3LKcK80Bx+FRw3UETIlX6mYMLL9PJQ==", + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.79", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.79.tgz", + "integrity": "sha512-/jn0Gs/qm6fs6nTIA5yncHayybz42SATZ3rNxCEBYPJ9v69PLrDRgk07E9xTT2gpRcNmDXXbi27ZbuU06N0Z6Q==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/nested-clients": "^3.997.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/core": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", - "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", + "node_modules/@aws-sdk/credential-providers": { + "version": "3.1149.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1149.0.tgz", + "integrity": "sha512-OiABL+ZjZJ9yBjyCG07wKzN81axkVokZOpS+VZeDZx8AiYPgqu1MNDbmtX0c4z+SYxcSOtrxH6rU+Lwqz2Sjaw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/core": "^3.2.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/signature-v4": "^5.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", - "fast-xml-parser": "4.4.1", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/credential-provider-cognito-identity": "^3.972.72", + "@aws-sdk/credential-provider-env": "^3.972.73", + "@aws-sdk/credential-provider-http": "^3.972.75", + "@aws-sdk/credential-provider-ini": "^3.973.18", + "@aws-sdk/credential-provider-login": "^3.972.80", + "@aws-sdk/credential-provider-node": "^3.972.85", + "@aws-sdk/credential-provider-process": "^3.972.73", + "@aws-sdk/credential-provider-sso": "^3.973.17", + "@aws-sdk/credential-provider-web-identity": "^3.972.79", + "@aws-sdk/nested-clients": "^3.997.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/credential-provider-imds": "^4.5.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.787.0.tgz", - "integrity": "sha512-nF5XjgvZHFuyttOeTjMgfEsg6slZPQ6uI34yzq12Kq4icFgcD4bQsijnQClMN7A0u5qR8Ad8kume4b7+I2++Ig==", + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.972.78", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.78.tgz", + "integrity": "sha512-W1kXIqMBkfrpVTbOOUSt63D2mEM4882TLqGWXjkZ1OcJ2ggSEWzgyjlyVDIHu/goGJSREd5s/KQ9wAgVZ0djeQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-cognito-identity": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/signature-v4-multi-region": "^3.996.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", - "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.47", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.47.tgz", + "integrity": "sha512-bovCKvDsLocNTzaj6VrrMVJ2BGROqO0JlwcGseO67a+I9Bo+08nUJhSQfZUIx4+A4a7I4101GEJd/AYm7dQ68w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/signature-v4-multi-region": "^3.996.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", - "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", + "node_modules/@aws-sdk/s3-request-presigner": { + "version": "3.1149.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.1149.0.tgz", + "integrity": "sha512-baBynYmUAeUkcgY/PZJJsEFzVYLhbvQo9e0kVm5NA4zmNQornvoN5FID4gaDvxZVnZjXsBEcEygjtbYg1l2gMQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/signature-v4-multi-region": "^3.996.48", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.787.0.tgz", - "integrity": "sha512-hc2taRoDlXn2uuNuHWDJljVWYrp3r9JF1a/8XmOAZhVUNY+ImeeStylHXhXXKEA4JOjW+5PdJj0f1UDkVCHJiQ==", + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.48", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.48.tgz", + "integrity": "sha512-cFDXfEbXaGwbnpvR/DyqfxfjxpjXVRVthQLgkwvcfDS5u3+8G9WSj1X1Ag/pTRg/QOeOno1Tq3ycEdrKsCUcOA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.787.0", - "@aws-sdk/credential-provider-web-identity": "3.787.0", - "@aws-sdk/nested-clients": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "^3.974.6", + "@smithy/signature-v4": "^5.7.4", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.787.0.tgz", - "integrity": "sha512-JioVi44B1vDMaK2CdzqimwvJD3uzvzbQhaEWXsGMBcMcNHajXAXf08EF50JG3ZhLrhhUsT1ObXpbTaPINOhh+g==", + "node_modules/@aws-sdk/token-providers": { + "version": "3.1149.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1149.0.tgz", + "integrity": "sha512-CAwYyA8eVk1w6h8YgLvkjIOakWPwURaUFrP7BRVgkxTFUM+O87thyKsGKJ6rVPbP8eoEV10cBWQ5YfaYl3qSVQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-ini": "3.787.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.787.0", - "@aws-sdk/credential-provider-web-identity": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "^3.978.2", + "@aws-sdk/nested-clients": "^3.997.47", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.2", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", - "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", + "node_modules/@aws-sdk/types": { + "version": "3.974.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.6.tgz", + "integrity": "sha512-v/clNZzZnDxGyvpHMOGpJKVXFAExJzUNAAjaWGdcx8QAcXLGwTaOkw33p5SHAi0YAioK32xB3hWwOekRVfmfKg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.787.0.tgz", - "integrity": "sha512-fHc08bsvwm4+dEMEQKnQ7c1irEQmmxbgS+Fq41y09pPvPh31nAhoMcjBSTWAaPHvvsRbTYvmP4Mf12ZGr8/nfg==", + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.41.tgz", + "integrity": "sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso": "3.787.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/token-providers": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.787.0.tgz", - "integrity": "sha512-SobmCwNbk6TfEsF283mZPQEI5vV2j6eY5tOCj8Er4Lzraxu9fBPADV+Bib2A8F6jlB1lMPJzOuDCbEasSt/RIw==", + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/nested-clients": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.787.0.tgz", - "integrity": "sha512-kR3RtI7drOc9pho13vWbUC2Bvrx9A0G4iizBDGmTs08NOdg4w3c1I4kdLG9tyPiIMeVnH+wYrsli5CM7xIfqiA==", - "license": "Apache-2.0", + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", "dependencies": { - "@aws-sdk/client-cognito-identity": "3.787.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-cognito-identity": "3.787.0", - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-ini": "3.787.0", - "@aws-sdk/credential-provider-node": "3.787.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.787.0", - "@aws-sdk/credential-provider-web-identity": "3.787.0", - "@aws-sdk/nested-clients": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.775.0.tgz", - "integrity": "sha512-qogMIpVChDYr4xiUNC19/RDSw/sKoHkAhouS6Skxiy6s27HBhow1L3Z1qVYXuBmOZGSWPU0xiyZCvOyWrv9s+Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-arn-parser": "3.723.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-config-provider": "^4.0.0", - "tslib": "^2.6.2" - }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.775.0.tgz", - "integrity": "sha512-Apd3owkIeUW5dnk3au9np2IdW2N0zc9NjTjHiH+Mx3zqwSrc+m+ANgJVgk9mnQjMzU/vb7VuxJ0eqdEbp5gYsg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.787.0.tgz", - "integrity": "sha512-X71qEwWoixFmwowWzlPoZUR3u1CWJ7iAzU0EzIxqmPhQpQJLFmdL1+SRjqATynDPZQzLs1a5HBtPT++EnZ+Quw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@aws-crypto/crc32c": "5.2.0", - "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/is-array-buffer": "^4.0.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-stream": "^4.2.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" + "node": ">=6.9.0" }, - "engines": { - "node": ">=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", - "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.775.0.tgz", - "integrity": "sha512-8TMXEHZXZTFTckQLyBT5aEI8fX11HZcwZseRifvBKKpj0RZDk4F0EEYGxeNSPpUQ7n+PRWyfAEnnZNRdAj/1NQ==", - "license": "Apache-2.0", + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", - "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", - "license": "Apache-2.0", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" + "@babel/types": "^7.25.9" }, "engines": { - "node": ">=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", - "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", - "license": "Apache-2.0", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.775.0.tgz", - "integrity": "sha512-zsvcu7cWB28JJ60gVvjxPCI7ZU7jWGcpNACPiZGyVtjYXwcxyhXbYEVDSWKsSA6ERpz9XrpLYod8INQWfW3ECg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-arn-parser": "3.723.0", - "@smithy/core": "^3.2.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/signature-v4": "^5.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-stream": "^4.2.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.775.0.tgz", - "integrity": "sha512-Iw1RHD8vfAWWPzBBIKaojO4GAvQkHOYIpKdAfis/EUSUmSa79QsnXnRqsdcE0mCB0Ylj23yi+ah4/0wh9FsekA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.787.0.tgz", - "integrity": "sha512-Lnfj8SmPLYtrDFthNIaNj66zZsBCam+E4XiUDr55DIHTGstH6qZ/q6vg0GfbukxwSmUcGMwSR4Qbn8rb8yd77g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@smithy/core": "^3.2.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.787.0.tgz", - "integrity": "sha512-xk03q1xpKNHgbuo+trEf1dFrI239kuMmjKKsqLEsHlAZbuFq4yRGMlHBrVMnKYOPBhVFDS/VineM991XI52fKg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.775.0.tgz", - "integrity": "sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/s3-request-presigner": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.787.0.tgz", - "integrity": "sha512-WBm0AS3RRURNN0yjYXHaiI692boVwWXGt3RLdI7tYBX58E1Zb5nzC8rlk81O9Xe7ZTgTC1KCr8y4+jcBD+zwJg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/signature-v4-multi-region": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-format-url": "3.775.0", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.775.0.tgz", - "integrity": "sha512-cnGk8GDfTMJ8p7+qSk92QlIk2bmTmFJqhYxcXZ9PysjZtx0xmfCMxnG3Hjy1oU2mt5boPCVSOptqtWixayM17g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/signature-v4": "^5.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.787.0.tgz", - "integrity": "sha512-d7/NIqxq308Zg0RPMNrmn0QvzniL4Hx8Qdwzr6YZWLYAbUSvZYS2ppLR3BFWSkV6SsTJUx8BuDaj3P8vttkrog==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/nested-clients": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", - "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.723.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.723.0.tgz", - "integrity": "sha512-ZhEfvUwNliOQROcAk34WJWVYTlTa4694kSVhDSjW6lE1bMataPnIN8A0ycukEzBXmd8ZSoBcQLn6lKGl7XIJ5w==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.787.0.tgz", - "integrity": "sha512-fd3zkiOkwnbdbN0Xp9TsP5SWrmv0SpT70YEdbb8wAj2DWQwiCmFszaSs+YCvhoCdmlR3Wl9Spu0pGpSAGKeYvQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "@smithy/util-endpoints": "^3.0.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-format-url": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.775.0.tgz", - "integrity": "sha512-Nw4nBeyCbWixoGh8NcVpa/i8McMA6RXJIjQFyloJLaPr7CPquz7ZbSl0MUWMFVwP/VHaJ7B+lNN3Qz1iFCEP/Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/querystring-builder": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.723.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.723.0.tgz", - "integrity": "sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", - "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.787.0.tgz", - "integrity": "sha512-mG7Lz8ydfG4SF9e8WSXiPQ/Lsn3n8A5B5jtPROidafi06I3ckV2WxyMLdwG14m919NoS6IOfWHyRGSqWIwbVKA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.775.0.tgz", - "integrity": "sha512-b9NGO6FKJeLGYnV7Z1yvcP1TNU4dkD5jNsLWOF1/sygZoASaQhNOlaiJ/1OH331YQ1R1oWk38nBb0frsYkDsOQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", - "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" + "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { @@ -1608,6 +960,15 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", @@ -1622,27 +983,27 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1664,9 +1025,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1720,27 +1081,27 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1761,25 +1122,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", - "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.10.tgz", + "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -2537,15 +1898,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.8.tgz", + "integrity": "sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.8" }, "engines": { "node": ">=6.9.0" @@ -3063,54 +2424,45 @@ } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.10.tgz", + "integrity": "sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.9", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -3124,44 +2476,41 @@ "license": "MIT" }, "node_modules/@bufbuild/protobuf": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.0.tgz", - "integrity": "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.15.0.tgz", + "integrity": "sha512-DAheWUkVr/SJTWCc+lg9dhY0eN4SaWlf4+bG1KzHeXbnqt0AfB/NX0Z+VunGlM1ki1B4zVvye27MpKh/svySUA==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@connectrpc/connect": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-1.6.1.tgz", - "integrity": "sha512-KchMDNtU4CDTdkyf0qG7ugJ6qHTOR/aI7XebYn3OTCNagaDYWiZUVKgRgwH79yeMkpNgvEUaXSK7wKjaBK9b/Q==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.2.0.tgz", + "integrity": "sha512-M63OQ1ZFcPUm85CuewJ9G9CMV8LjzGR9935xOnXNQGSazAbwMb3x2W7vXBYM1zqrP7XFD8uxp/dUAhirclgwnQ==", "license": "Apache-2.0", "peerDependencies": { - "@bufbuild/protobuf": "^1.10.0" + "@bufbuild/protobuf": "^2.7.0" } }, "node_modules/@connectrpc/connect-node": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@connectrpc/connect-node/-/connect-node-1.6.1.tgz", - "integrity": "sha512-DxcD1wsF/aX9GegjAtl7VbpiZNjVJozy87VbaFoN6AF0Ln1Q757r5dgV59Gz0wmlk5f17txUsrEr1f2inlnnAg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect-node/-/connect-node-2.2.0.tgz", + "integrity": "sha512-E6uUO6e11WdynAuBjuN+0WpHjqxEM9BNDdfDIJHcn49Esg/WxSIbn2y1KFt9XL96IJi01qdBbvubcdpBz1X3Zw==", "license": "Apache-2.0", - "dependencies": { - "undici": "^5.28.4" - }, "engines": { - "node": ">=16.0.0" + "node": ">=22" }, "peerDependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "1.6.1" + "@bufbuild/protobuf": "^2.7.0", + "@connectrpc/connect": "2.2.0" } }, "node_modules/@connectrpc/connect-web": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-1.6.1.tgz", - "integrity": "sha512-GVfxQOmt3TtgTaKeXLS/EA2IHa3nHxwe2BCHT7X0Q/0hohM+nP5DDnIItGEjGrGdt3LTTqWqE4s70N4h+qIMlQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-2.2.0.tgz", + "integrity": "sha512-uuBUcBTYfb/r1o98LzCCZk1H90yx0vmZ5m21dpw/q4EUwsKwkCDGI8H0aEdjcZld+Q2jJ5A5ADvPqfb6lzQ/sg==", "license": "Apache-2.0", "peerDependencies": { - "@bufbuild/protobuf": "^1.10.0", - "@connectrpc/connect": "1.6.1" + "@bufbuild/protobuf": "^2.7.0", + "@connectrpc/connect": "2.2.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -3228,9 +2577,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz", - "integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", "dev": true, "license": "MIT", "dependencies": { @@ -3260,9 +2609,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -3270,34 +2619,37 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^3.1.5" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", - "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3308,20 +2660,20 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.7.tgz", + "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", + "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", + "js-yaml": "^4.3.2", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { @@ -3332,19 +2684,22 @@ } }, "node_modules/@eslint/js": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz", - "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==", + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3352,41 +2707,19 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.13.0", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, "node_modules/@firebase/analytics": { "version": "0.10.8", "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.8.tgz", @@ -3540,15 +2873,6 @@ "@firebase/app-compat": "0.x" } }, - "node_modules/@firebase/auth-compat/node_modules/undici": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz", - "integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/@firebase/auth-interop-types": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.3.tgz", @@ -3565,15 +2889,6 @@ "@firebase/util": "1.x" } }, - "node_modules/@firebase/auth/node_modules/undici": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz", - "integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/@firebase/component": { "version": "0.6.9", "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.9.tgz", @@ -3687,15 +3002,6 @@ "@firebase/util": "1.x" } }, - "node_modules/@firebase/firestore/node_modules/undici": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz", - "integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/@firebase/functions": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.8.tgz", @@ -3736,15 +3042,6 @@ "integrity": "sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w==", "license": "Apache-2.0" }, - "node_modules/@firebase/functions/node_modules/undici": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz", - "integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/@firebase/installations": { "version": "0.6.9", "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.9.tgz", @@ -3951,15 +3248,6 @@ "@firebase/util": "1.x" } }, - "node_modules/@firebase/storage/node_modules/undici": { - "version": "6.19.7", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz", - "integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/@firebase/util": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.10.0.tgz", @@ -4049,9 +3337,9 @@ "license": "MIT" }, "node_modules/@grpc/grpc-js": { - "version": "1.9.15", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", - "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "version": "1.9.16", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.16.tgz", + "integrity": "sha512-wE4Ut/olIzfKqp631XrG+wbF0v1vWFN4YL9FyXC2LJiG33DsV7PLzURjrCvY/6je2ntdRkeLpPDluzSRGaVltQ==", "license": "Apache-2.0", "dependencies": { "@grpc/proto-loader": "^0.7.8", @@ -4121,41 +3409,41 @@ } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=18.18.0" } }, "node_modules/@humanwhocodes/module-importer": { @@ -4819,9 +4107,9 @@ } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", "dev": true, "license": "MIT", "dependencies": { @@ -5238,17 +4526,23 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -5260,15 +4554,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", @@ -5286,9 +4571,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -5578,19 +4863,19 @@ } }, "node_modules/@playwright/test": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", - "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.0.tgz", + "integrity": "sha512-oTN9FNYuN6bqQMwiho6jJKLCG2/QOYCixGXuCjRmzOq23eODeukuY2XiAVoVpAECbuezMt1MHQjAiQxK8F+Y+g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.52.0" + "playwright": "1.64.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/@popperjs/core": { @@ -5719,25 +5004,24 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", "license": "BSD-3-Clause", "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "@protobufjs/aspromise": "^1.1.1" } }, "node_modules/@protobufjs/float": { @@ -5746,12 +5030,6 @@ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "license": "BSD-3-Clause" }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", @@ -5765,9 +5043,9 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", "license": "BSD-3-Clause" }, "node_modules/@radix-ui/number": { @@ -7051,906 +6329,257 @@ } }, "node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "license": "MIT", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "license": "MIT" - }, - "node_modules/@rrweb/types": { - "version": "2.0.0-alpha.18", - "resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.18.tgz", - "integrity": "sha512-iMH3amHthJZ9x3gGmBPmdfim7wLGygC2GciIkw2A6SO8giSn8PHYtRT8OKNH4V+k3SZ6RSnYHcTQxBA7pSWZ3Q==", - "license": "MIT" - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz", - "integrity": "sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@selderee/plugin-htmlparser2": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", - "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", - "license": "MIT", - "dependencies": { - "domhandler": "^5.0.3", - "selderee": "^0.11.0" - }, - "funding": { - "url": "https://ko-fi.com/killymxi" - } - }, - "node_modules/@sendgrid/client": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.5.tgz", - "integrity": "sha512-Jqt8aAuGIpWGa15ZorTWI46q9gbaIdQFA21HIPQQl60rCjzAko75l3D1z7EyjFrNr4MfQ0StusivWh8Rjh10Cg==", - "license": "MIT", - "dependencies": { - "@sendgrid/helpers": "^8.0.0", - "axios": "^1.8.2" - }, - "engines": { - "node": ">=12.*" - } - }, - "node_modules/@sendgrid/helpers": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-8.0.0.tgz", - "integrity": "sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==", - "license": "MIT", - "dependencies": { - "deepmerge": "^4.2.2" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/@sendgrid/mail": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.5.tgz", - "integrity": "sha512-W+YuMnkVs4+HA/bgfto4VHKcPKLc7NiZ50/NH2pzO6UHCCFuq8/GNB98YJlLEr/ESDyzAaDr7lVE7hoBwFTT3Q==", - "license": "MIT", - "dependencies": { - "@sendgrid/client": "^8.1.5", - "@sendgrid/helpers": "^8.0.0" - }, - "engines": { - "node": ">=12.*" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@smithy/abort-controller": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.2.tgz", - "integrity": "sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/chunked-blob-reader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.0.0.tgz", - "integrity": "sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/chunked-blob-reader-native": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.0.0.tgz", - "integrity": "sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-base64": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz", - "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.2.0.tgz", - "integrity": "sha512-k17bgQhVZ7YmUvA8at4af1TDpl0NDMBuBKJl8Yg0nrefwmValU+CnA5l/AriVdQNthU/33H3nK71HrLgqOPr1Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/middleware-serde": "^4.0.3", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-stream": "^4.2.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz", - "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-codec": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.2.tgz", - "integrity": "sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-hex-encoding": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.2.tgz", - "integrity": "sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.0.tgz", - "integrity": "sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.2.tgz", - "integrity": "sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.2.tgz", - "integrity": "sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-codec": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.2.tgz", - "integrity": "sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.1.0", - "@smithy/querystring-builder": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/util-base64": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-blob-browser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.2.tgz", - "integrity": "sha512-3g188Z3DyhtzfBRxpZjU8R9PpOQuYsbNnyStc/ZVS+9nVX1f6XeNOa9IrAh35HwwIZg+XWk8bFVtNINVscBP+g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/chunked-blob-reader": "^5.0.0", - "@smithy/chunked-blob-reader-native": "^4.0.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.2.tgz", - "integrity": "sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-stream-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.0.2.tgz", - "integrity": "sha512-POWDuTznzbIwlEXEvvXoPMS10y0WKXK790soe57tFRfvf4zBHyzE529HpZMqmDdwG9MfFflnyzndUQ8j78ZdSg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.2.tgz", - "integrity": "sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", - "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/md5-js": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.2.tgz", - "integrity": "sha512-Hc0R8EiuVunUewCse2syVgA2AfSRco3LyAv07B/zCOMa+jpXI9ll+Q21Nc6FAlYPcpNcAXqBzMhNs1CD/pP2bA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.2.tgz", - "integrity": "sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.0.tgz", - "integrity": "sha512-xhLimgNCbCzsUppRTGXWkZywksuTThxaIB0HwbpsVLY5sceac4e1TZ/WKYqufQLaUy+gUSJGNdwD2jo3cXL0iA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.2.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-middleware": "^4.0.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.0.tgz", - "integrity": "sha512-2zAagd1s6hAaI/ap6SXi5T3dDwBOczOMCSkkYzktqN1+tzbk1GAsHNAdo/1uzxz3Ky02jvZQwbi/vmDA6z4Oyg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/service-error-classification": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-retry/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz", - "integrity": "sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.2.tgz", - "integrity": "sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz", - "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.4.tgz", - "integrity": "sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/querystring-builder": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.2.tgz", - "integrity": "sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.0.tgz", - "integrity": "sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.2.tgz", - "integrity": "sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "@smithy/util-uri-escape": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.2.tgz", - "integrity": "sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz", - "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.2.tgz", - "integrity": "sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.2.tgz", - "integrity": "sha512-Mz+mc7okA73Lyz8zQKJNyr7lIcHLiPYp0+oiqiMNc/t7/Kf2BENs5d63pEj7oPqdjaum6g0Fc8wC78dY1TgtXw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-uri-escape": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.0.tgz", - "integrity": "sha512-Qs65/w30pWV7LSFAez9DKy0Koaoh3iHhpcpCCJ4waj/iqwsuSzJna2+vYwq46yBaqO5ZbP9TjUsATUNxrKeBdw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.2.0", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", - "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.2.tgz", - "integrity": "sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==", - "license": "Apache-2.0", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "license": "MIT", "dependencies": { - "@smithy/querystring-parser": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" }, "engines": { - "node": ">=18.0.0" + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } } }, - "node_modules/@smithy/util-base64": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", - "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", - "license": "Apache-2.0", + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "license": "MIT", "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" }, "engines": { - "node": ">=18.0.0" + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@smithy/util-body-length-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", - "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", - "license": "Apache-2.0", + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" }, - "engines": { - "node": ">=18.0.0" + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" } }, - "node_modules/@smithy/util-body-length-node": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", - "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", - "license": "Apache-2.0", + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" }, "engines": { - "node": ">=18.0.0" + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@smithy/util-buffer-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", - "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", - "license": "Apache-2.0", + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "license": "MIT" + }, + "node_modules/@rrweb/types": { + "version": "2.0.0-alpha.18", + "resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.18.tgz", + "integrity": "sha512-iMH3amHthJZ9x3gGmBPmdfim7wLGygC2GciIkw2A6SO8giSn8PHYtRT8OKNH4V+k3SZ6RSnYHcTQxBA7pSWZ3Q==", + "license": "MIT" + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz", + "integrity": "sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", + "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "license": "MIT", "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", - "tslib": "^2.6.2" + "domhandler": "^5.0.3", + "selderee": "^0.11.0" }, - "engines": { - "node": ">=18.0.0" + "funding": { + "url": "https://ko-fi.com/killymxi" } }, - "node_modules/@smithy/util-config-provider": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", - "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", - "license": "Apache-2.0", + "node_modules/@sendgrid/client": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.5.tgz", + "integrity": "sha512-Jqt8aAuGIpWGa15ZorTWI46q9gbaIdQFA21HIPQQl60rCjzAko75l3D1z7EyjFrNr4MfQ0StusivWh8Rjh10Cg==", + "license": "MIT", "dependencies": { - "tslib": "^2.6.2" + "@sendgrid/helpers": "^8.0.0", + "axios": "^1.8.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=12.*" } }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.8.tgz", - "integrity": "sha512-ZTypzBra+lI/LfTYZeop9UjoJhhGRTg3pxrNpfSTQLd3AJ37r2z4AXTKpq1rFXiiUIJsYyFgNJdjWRGP/cbBaQ==", - "license": "Apache-2.0", + "node_modules/@sendgrid/helpers": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-8.0.0.tgz", + "integrity": "sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==", + "license": "MIT", "dependencies": { - "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" + "deepmerge": "^4.2.2" }, "engines": { - "node": ">=18.0.0" + "node": ">= 12.0.0" } }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.8.tgz", - "integrity": "sha512-Rgk0Jc/UDfRTzVthye/k2dDsz5Xxs9LZaKCNPgJTRyoyBoeiNCnHsYGOyu1PKN+sDyPnJzMOz22JbwxzBp9NNA==", - "license": "Apache-2.0", + "node_modules/@sendgrid/mail": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.5.tgz", + "integrity": "sha512-W+YuMnkVs4+HA/bgfto4VHKcPKLc7NiZ50/NH2pzO6UHCCFuq8/GNB98YJlLEr/ESDyzAaDr7lVE7hoBwFTT3Q==", + "license": "MIT", "dependencies": { - "@smithy/config-resolver": "^4.1.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" + "@sendgrid/client": "^8.1.5", + "@sendgrid/helpers": "^8.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=12.*" } }, - "node_modules/@smithy/util-endpoints": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz", - "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==", - "license": "Apache-2.0", + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "type-detect": "4.0.8" } }, - "node_modules/@smithy/util-hex-encoding": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", - "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", - "license": "Apache-2.0", + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@smithy/util-middleware": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.2.tgz", - "integrity": "sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==", + "node_modules/@smithy/core": { + "version": "3.35.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.35.2.tgz", + "integrity": "sha512-ejTukBuP/Pg3t9N8Ux+0zKsXeHWm7p6W3HbXFOyltKasSxZwCFmvTut7kBdZSCF3m9y1bXXyVu6p2xuMFcsTyQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/util-retry": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz", - "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==", + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/util-stream": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.0.tgz", - "integrity": "sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==", + "node_modules/@smithy/fetch-http-handler": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.8.0.tgz", + "integrity": "sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/types": "^4.2.0", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.18.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/util-uri-escape": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", - "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "node_modules/@smithy/node-http-handler": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.1.tgz", + "integrity": "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==", "license": "Apache-2.0", "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.18.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/util-utf8": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", - "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "node_modules/@smithy/signature-v4": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.4.tgz", + "integrity": "sha512-tHy0K0VtqNd5Y7Y41h0a0Lhh0L1GzC08dTWg0F7vRJWFtTENg7IZikf3wQkanYIRdb7ngoIPMTmqgUi401fEeQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/util-waiter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.3.tgz", - "integrity": "sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==", + "node_modules/@smithy/types": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.19.0.tgz", + "integrity": "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.0.2", - "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8226,25 +6855,15 @@ } }, "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 10" } }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -8690,6 +7309,15 @@ "@types/node": "*" } }, + "node_modules/@types/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", @@ -8708,21 +7336,20 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.30.1.tgz", - "integrity": "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.1.tgz", + "integrity": "sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/type-utils": "8.30.1", - "@typescript-eslint/utils": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/type-utils": "8.71.1", + "@typescript-eslint/utils": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8732,23 +7359,33 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "@typescript-eslint/parser": "^8.71.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.12.tgz", + "integrity": "sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.30.1.tgz", - "integrity": "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.1.tgz", + "integrity": "sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/typescript-estree": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8758,19 +7395,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.30.1.tgz", - "integrity": "sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz", + "integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1" + "@typescript-eslint/tsconfig-utils": "^8.71.1", + "@typescript-eslint/types": "^8.71.1", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8778,19 +7416,20 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.30.1.tgz", - "integrity": "sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.1.tgz", + "integrity": "sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.30.1", - "@typescript-eslint/utils": "8.30.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8798,16 +7437,12 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.30.1.tgz", - "integrity": "sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz", + "integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==", "dev": true, "license": "MIT", "engines": { @@ -8816,23 +7451,23 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.30.1.tgz", - "integrity": "sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.1.tgz", + "integrity": "sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/utils": "8.71.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8842,76 +7477,102 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@typescript-eslint/types": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.1.tgz", + "integrity": "sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz", + "integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" + "@typescript-eslint/project-service": "8.71.1", + "@typescript-eslint/tsconfig-utils": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8.6.0" + "node": "18 || 20 || >=22" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">= 6" + "node": "20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.8" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.30.1.tgz", - "integrity": "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.1.tgz", + "integrity": "sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/typescript-estree": "8.30.1" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8921,19 +7582,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.30.1.tgz", - "integrity": "sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.1.tgz", + "integrity": "sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.30.1", - "eslint-visitor-keys": "^4.2.0" + "@typescript-eslint/types": "8.71.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8943,6 +7604,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@unrs/resolver-binding-darwin-arm64": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.5.0.tgz", @@ -9304,9 +7978,9 @@ } }, "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -9359,9 +8033,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -9392,9 +8066,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -9495,19 +8169,22 @@ } }, "node_modules/arcjet": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/arcjet/-/arcjet-1.0.0-beta.6.tgz", - "integrity": "sha512-1v2jfqG4O2zXNfjlT3HHEefeoVigqX3Lzb1nak4ibw83y8aQihvVk9pDkp0WKYztq20A+5w3oZHsx+EYzbUB6A==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/arcjet/-/arcjet-1.14.1.tgz", + "integrity": "sha512-MDwQobCG93yp1AcSrcaeDPTVrPLcliQbeYMTKB3v8qMfIC9jjJkzf9ZTZClYLyS+h7NagAfCu1hbhwFxzxEaVA==", "license": "Apache-2.0", "dependencies": { - "@arcjet/analyze": "1.0.0-beta.6", - "@arcjet/duration": "1.0.0-beta.6", - "@arcjet/headers": "1.0.0-beta.6", - "@arcjet/protocol": "1.0.0-beta.6", - "@arcjet/runtime": "1.0.0-beta.6" + "@arcjet/analyze": "1.14.1", + "@arcjet/cache": "1.14.1", + "@arcjet/duration": "1.14.1", + "@arcjet/headers": "1.14.1", + "@arcjet/protocol": "1.14.1", + "@arcjet/runtime": "1.14.1", + "@arcjet/skills": "1.14.1", + "@arcjet/stable-hash": "1.14.1" }, "engines": { - "node": ">=18" + "node": ">=22.21.0 <23 || >=24.5.0" } }, "node_modules/arg": { @@ -9854,14 +8531,40 @@ } }, "node_modules/axios": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", - "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, "node_modules/axobject-query": { @@ -10111,6 +8814,18 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.28", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.28.tgz", + "integrity": "sha512-br0LOmjJqr6Rt4AEkadbcNf67Zpo7EPwKsWbjnRrJIa1QYFHQBqM4C7F2WTbV8ahTEcg1Eo+Y0aWjjORInYFyA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/bcryptjs": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", @@ -10157,29 +8872,29 @@ "license": "MIT" }, "node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.8", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.8.tgz", + "integrity": "sha512-JNcyFQ64OiijEkPzUBTCe+hyPXUD/3LEldGQ6iF5LR1w00mx9o7xtDWHXBY2iItjdCFGoilOLNQbH943ut7pHA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.16.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -10195,12 +8910,41 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, + "node_modules/body-parser/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -10208,9 +8952,9 @@ "license": "ISC" }, "node_modules/bowser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", "license": "MIT" }, "node_modules/brace-expansion": { @@ -10293,36 +9037,35 @@ } }, "node_modules/browserify-rsa/node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz", + "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==", "license": "MIT" }, "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.6.tgz", + "integrity": "sha512-sd+Q65fjlWCYWtZKXiKfrUc8d+4jtp/8f0W2NkwzLtoW4bI6UDnWusLWIurHnmurW0XShIRxpwiOX4EoPtXUAg==", "license": "ISC", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", + "bn.js": "^5.2.3", + "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", + "elliptic": "^6.6.1", "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", + "parse-asn1": "^5.1.9", "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.12" + "node": ">= 0.10" } }, "node_modules/browserify-sign/node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz", + "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==", "license": "MIT" }, "node_modules/browserify-zlib": { @@ -10335,9 +9078,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", + "integrity": "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==", "funding": [ { "type": "opencollective", @@ -10354,10 +9097,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.11.26", + "caniuse-lite": "^1.0.30001813", + "electron-to-chromium": "^1.5.439", + "node-releases": "^2.0.57", + "update-browserslist-db": "^1.3.3" }, "bin": { "browserslist": "cli.js" @@ -10548,9 +9292,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001714", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001714.tgz", - "integrity": "sha512-mtgapdwDLSSBnCI3JokHM7oEQBLxiJKVRtg10AxM1AyeiKcM96f0Mkbqeq+1AbiCtvMcHRulAAEMu693JrSWqg==", + "version": "1.0.30001815", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001815.tgz", + "integrity": "sha512-uDybUEyfgbyJJ93J1vikTylBX31AkdVYeVPeffMQpf8XN7hSfr0oZOn4VFOIMNvtU5+rHvC5Udg2TgtJKHm23Q==", "funding": [ { "type": "opencollective", @@ -10725,13 +9469,12 @@ } }, "node_modules/cloudinary": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.6.0.tgz", - "integrity": "sha512-FIlny9RR5LPgkMioG4V7yUpC6ASyIFQMWfx4TgOi/xBeLxJTegbyQc3itiXL0b0lDlSaL0KyT2THEw6osrKqpQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.11.0.tgz", + "integrity": "sha512-o2pAkDDqrzPFE/mn9GCfFjBIGQmPs++Ts6rtkFl4vY528DNHiMovKWjH16HBjeGa9iwI7eAad24aWN2emT0aww==", "license": "MIT", "dependencies": { - "lodash": "^4.17.21", - "q": "^1.5.1" + "lodash": "^4.17.23" }, "engines": { "node": ">=9" @@ -10792,9 +9535,9 @@ "license": "MIT" }, "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.10.0.tgz", + "integrity": "sha512-AidJptpBJmjTclAp9BkLwJi0T93fo5epJnbaZslpg6QVzpHjAiveF55mE9AcUJiGMqRHgMDY8soMsQtuNYMHfw==", "dev": true, "license": "MIT" }, @@ -11252,9 +9995,9 @@ } }, "node_modules/cssnano-preset-default/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", + "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", "dev": true, "license": "MIT", "dependencies": { @@ -11607,9 +10350,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -11847,9 +10590,9 @@ "license": "Apache-2.0" }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -12067,9 +10810,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.138", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.138.tgz", - "integrity": "sha512-FWlQc52z1dXqm+9cCJ2uyFgJkESd+16j6dBEjsgDNuHjBpuIzL8/lRc0uvh1k8RNI6waGo6tcy2DvwkTBJOLDg==", + "version": "1.5.452", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.452.tgz", + "integrity": "sha512-cVvk1YBSj6571VmV6hdJTqj94Y79xSu8cj6Y9t6ae4Y4431z8/7EJFvu3rVp90xhfuv9BpPKUmaLfTo4+FOGBg==", "license": "ISC" }, "node_modules/elliptic": { @@ -12125,55 +10868,38 @@ } }, "node_modules/engine.io": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", - "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "version": "6.6.11", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.11.tgz", + "integrity": "sha512-z34mGpLoY/82ZbkX1LqGMIaf3wjVMPL6gVC681QDqnmzJ26synI8qAE32P+a7UazmpJZ8UGrFIeAavgRfXzYrg==", "license": "MIT", "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", + "@types/ws": "^8.5.12", "accepts": "~1.3.4", - "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", - "debug": "~4.3.1", + "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" + "ws": "~8.21.0" }, "engines": { "node": ">=10.2.0" } }, "node_modules/engine.io-client": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", - "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.7.tgz", + "integrity": "sha512-GyAvmPA7gnRCpDQbYACAy79Lg4ewevrmaPzySZz0OVvgyZc3gEfLLqPTYk8wVBScjOEpM9ZO4KryyFpVItjGEA==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", + "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.17.1", + "ws": "~8.21.0", "xmlhttprequest-ssl": "~2.1.1" } }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/engine.io-parser": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", @@ -12192,23 +10918,6 @@ "node": ">= 0.6" } }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -12457,33 +11166,33 @@ } }, "node_modules/eslint": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", - "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.0", - "@eslint/core": "^0.12.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.24.0", - "@eslint/plugin-kit": "^0.2.7", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -12495,7 +11204,7 @@ "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -12789,9 +11498,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -12806,9 +11515,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -12819,15 +11528,15 @@ } }, "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.14.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -12984,39 +11693,39 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.3.tgz", + "integrity": "sha512-Bdcs4+3qlpVlx2NRn6fgX2Ue2/gGRaPeawebgclM0ERSCqDpA+owF1fdPwjJUTAJWMTuAaxjDf+hzb0/4eKvvw==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.13", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.16.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -13129,9 +11838,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "funding": [ { "type": "github", @@ -13144,28 +11853,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - } - ], - "license": "MIT", - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -13197,10 +11884,28 @@ "bser": "2.1.1" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fflate": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", - "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.9.tgz", + "integrity": "sha512-zdxgIEddhfsyCaWpJ2SdXEP8ZMrKJ6+5jl4OupODcywU0IhRk6gdXuVGcPICyfx2H97hVK7xmJtRLPjkxAX8Vw==", "license": "MIT" }, "node_modules/file-entry-cache": { @@ -13238,18 +11943,18 @@ } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -13388,16 +12093,16 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.1.tgz", + "integrity": "sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==", "funding": [ { "type": "individual", @@ -13446,15 +12151,16 @@ } }, "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -13920,13 +12626,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/gtoken": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", @@ -14039,9 +12738,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -16020,10 +14719,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -16252,23 +14961,23 @@ } }, "node_modules/jsonwebtoken/node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "node_modules/jsonwebtoken/node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, @@ -16289,23 +14998,23 @@ } }, "node_modules/jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { - "jwa": "^2.0.0", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -16430,15 +15139,15 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, "node_modules/lodash.camelcase": { @@ -16784,9 +15493,9 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -16820,9 +15529,9 @@ "license": "MIT" }, "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.31.0.tgz", + "integrity": "sha512-0acOTfMiWOheYS4eoWb80yYMb/JLvVv9SHbs2PehaDzfUG0Bw855SKyk0IKTnPGa5+U2bmi3W68l1+sGLX/pvw==", "license": "MIT", "engines": { "node": "*" @@ -16858,9 +15567,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "funding": [ { "type": "github", @@ -16944,9 +15653,9 @@ } }, "node_modules/next-auth": { - "version": "4.24.11", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.11.tgz", - "integrity": "sha512-pCFXzIDQX7xmHFs4KVH4luCjaCbuPRtZ9oBUjUhOk84mZ9WVPf94n87TxYI4rSRf9HmfHEF8Yep3JrYDVOo3Cw==", + "version": "4.24.15", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.15.tgz", + "integrity": "sha512-NnjYtjrSOAx/TIVFGTX4IfI/9yHnNpi4B7FuLUwuV20v2Zxgr2OGP/YN0ynJuI7y8QOnTBPitfOdEXZrVvhIuA==", "license": "ISC", "dependencies": { "@babel/runtime": "^7.20.13", @@ -16957,12 +15666,12 @@ "openid-client": "^5.4.0", "preact": "^10.6.3", "preact-render-to-string": "^5.1.19", - "uuid": "^8.3.2" + "uuid": "^11.1.1" }, "peerDependencies": { - "@auth/core": "0.34.2", - "next": "^12.2.5 || ^13 || ^14 || ^15", - "nodemailer": "^6.6.5", + "@auth/core": "0.34.3", + "next": "^12.2.5 || ^13 || ^14 || ^15 || ^16", + "nodemailer": "^7.0.7", "react": "^17.0.2 || ^18 || ^19", "react-dom": "^17.0.2 || ^18 || ^19" }, @@ -16975,6 +15684,19 @@ } } }, + "node_modules/next-auth/node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/next-pwa": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/next-pwa/-/next-pwa-5.6.0.tgz", @@ -17082,10 +15804,13 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "license": "MIT" + "version": "2.0.58", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.58.tgz", + "integrity": "sha512-BdiKAgbfRlvfMq/XzO/AF9NPmaA8a+YpLAyAFTVFBj3gARrAIfWvNq7Q7NE4se3KgFu0KkrvQMxTS0XVnsGzHg==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/normalize-path": { "version": "3.0.0", @@ -17189,6 +15914,15 @@ "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==", "license": "MIT" }, + "node_modules/oauth4webapi": { + "version": "3.8.8", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.8.tgz", + "integrity": "sha512-8N28E+a/oxfXWBgOMt+ZP/JUf/XR+IFbvkAEPP3gznXOMv9BpAAwiIj0TFNz3tGTPc0ZQ8zmWBNgN1nAys0gng==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -17522,16 +16256,15 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "license": "ISC", "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.5", "safe-buffer": "^5.2.1" }, "engines": { @@ -17678,9 +16411,9 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "license": "MIT" }, "node_modules/path-type": { @@ -17693,19 +16426,20 @@ } }, "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.7.tgz", + "integrity": "sha512-nS4mvFgVwUrecPTRdpdseM2fwpdfnX0/HibA8DgBRQtihUAzHQYJFU2l+OlEtiXtpqkrMvCPDwyXMUnASDt6Qw==", "license": "MIT", "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.2" }, "engines": { - "node": ">=0.12" + "node": ">= 0.10" } }, "node_modules/peberminta": { @@ -17766,9 +16500,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -17881,50 +16615,32 @@ } }, "node_modules/playwright": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", - "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.0.tgz", + "integrity": "sha512-kVzTnYFYEyQ9RGzBjNCd2+yEqWmVbxl3AHPynv3qQ6JTjv4a+kwRcnqQwIpuP3NnrnIrE/Q6wWAIAvMfIE2/Yg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.52.0" + "playwright-core": "1.64.0" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" + "node": ">=20" } }, "node_modules/playwright-core": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", - "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.0.tgz", + "integrity": "sha512-T9r+MZkTECl2+oUcZ26YgZzTrYidTsIhYYkJix+6iDOymOb1FB2RLLSOxRGnZGv5DStt+aduIVbt+E8WygXYpg==", "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=18" - } - }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=20" } }, "node_modules/possible-typed-array-names": { @@ -17937,9 +16653,9 @@ } }, "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "funding": [ { "type": "opencollective", @@ -17956,9 +16672,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -18332,9 +17048,9 @@ } }, "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", + "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", "dev": true, "license": "MIT", "dependencies": { @@ -18538,9 +17254,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -18766,33 +17482,32 @@ } }, "node_modules/protobufjs": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.0.tgz", - "integrity": "sha512-Z2E/kOY1QjoMlCytmexzYfDm/w5fKAiRwpSzGtdnXW1zC88Z2yXazHHrOtwCzn+7wSxyE8PYM4rvVcMphF9sOA==", + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", + "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", - "long": "^5.0.0" + "long": "^5.3.2" }, "engines": { "node": ">=12.0.0" } }, "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz", + "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==", "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -18800,13 +17515,20 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/psl": { "version": "1.15.0", @@ -18861,24 +17583,14 @@ ], "license": "MIT" }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -18951,16 +17663,45 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -19611,19 +18352,37 @@ } }, "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" } }, "node_modules/rollup": { - "version": "2.79.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", - "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "version": "2.80.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz", + "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", "license": "MIT", "bin": { "rollup": "dist/bin/rollup" @@ -19665,15 +18424,6 @@ "node": ">= 10.13.0" } }, - "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/rollup-plugin-terser/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -19840,6 +18590,16 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -19956,9 +18716,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -20032,16 +18792,23 @@ "license": "ISC" }, "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", "license": "(MIT AND BSD-3-Clause)", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/sharp": { @@ -20116,9 +18883,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.12.0.tgz", + "integrity": "sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==", "dev": true, "license": "MIT", "engines": { @@ -20129,14 +18896,14 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -20148,13 +18915,13 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -20247,30 +19014,13 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", - "license": "MIT", - "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" - } - }, - "node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz", + "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "debug": "~4.4.1", + "ws": "~8.21.0" } }, "node_modules/socket.io-client": { @@ -20306,35 +19056,18 @@ } }, "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz", + "integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==", "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" + "debug": "~4.4.1" }, "engines": { "node": ">=10.0.0" } }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/socket.io/node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -20378,9 +19111,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -20441,15 +19174,31 @@ } }, "node_modules/statsig-node": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/statsig-node/-/statsig-node-6.3.2.tgz", - "integrity": "sha512-oDwGZc7+zCKdYI5BRFbytEYtwrxpqOt4CmEVgWpTFFqox77iNBLIE45u2x86RxnwvlI5n3fDq/nsMwxLPsE6Aw==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/statsig-node/-/statsig-node-6.5.2.tgz", + "integrity": "sha512-frYju9kWvHc61SkjisIe7/d6GCZd0a3zrL1P88rJl1fD6JB73AnoAd9cd1GUNcECzDth7l4UzPGvlJykI9fBvg==", "license": "ISC", "dependencies": { "ip3country": "^5.0.0", - "node-fetch": "^2.6.13", + "node-fetch": "^2.7.0", "ua-parser-js": "^1.0.2", - "uuid": "^8.3.2" + "uuid": "^11.1.1" + }, + "engines": { + "pnpm": "never" + } + }, + "node_modules/statsig-node/node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" } }, "node_modules/statuses": { @@ -20797,18 +19546,6 @@ "node": ">=12.*" } }, - "node_modules/strnum": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", - "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" - }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -20872,9 +19609,9 @@ } }, "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -20890,9 +19627,10 @@ } }, "node_modules/sucrase/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -20910,12 +19648,12 @@ } }, "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -21002,19 +19740,19 @@ } }, "node_modules/svgo": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", - "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.5.tgz", + "integrity": "sha512-8SQMzdrvWaD8deUmrnYB+ASyxBVgWUOilg+A75nE/76WdLpj6LopCwiAVvkzkcqy/9b7t2Mg7faFLjg0ZRcZ3w==", "dev": true, "license": "MIT", "dependencies": { - "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^5.1.0", "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", - "picocolors": "^1.0.0" + "picocolors": "^1.0.0", + "sax": "^1.5.0" }, "bin": { "svgo": "bin/svgo" @@ -21064,33 +19802,33 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", - "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.3.0", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.19.1", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", @@ -21106,13 +19844,32 @@ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "license": "MIT" }, - "node_modules/tailwindcss/node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "node_modules/tailwindcss/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, "engines": { - "node": ">=10" + "node": ">=8.6.0" + } + }, + "node_modules/tailwindcss/node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/tailwindcss/node_modules/object-hash": { @@ -21195,15 +19952,14 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -21217,21 +19973,48 @@ "webpack": "^5.1.0" }, "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, "@swc/core": { "optional": true }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, "esbuild": { "optional": true }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, "uglify-js": { "optional": true } } }, "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -21360,14 +20143,14 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", - "picomatch": "^4.0.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -21376,25 +20159,10 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, "license": "MIT", "engines": { @@ -21411,6 +20179,20 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -21475,9 +20257,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -21797,28 +20579,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typeid-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/typeid-js/-/typeid-js-1.2.0.tgz", - "integrity": "sha512-t76ZucAnvGC60ea/HjVsB0TSoB0cw9yjnfurUgtInXQWUI/VcrlZGpO23KN3iSe8yOGUgb1zr7W7uEzJ3hSljA==", - "license": "Apache-2.0", - "dependencies": { - "uuid": "^10.0.0" - } - }, - "node_modules/typeid-js/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -21902,15 +20662,12 @@ } }, "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "version": "6.19.7", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz", + "integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==", "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, "engines": { - "node": ">=14.0" + "node": ">=18.17" } }, "node_modules/undici-types": { @@ -22028,9 +20785,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", + "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", "funding": [ { "type": "opencollective", @@ -22308,9 +21065,9 @@ "license": "BSD-2-Clause" }, "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", + "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", @@ -22571,9 +21328,9 @@ } }, "node_modules/workbox-build/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -22848,9 +21605,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -22927,15 +21684,18 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { From 1a2b83207e7ed474f0309f88e0896be6fa85764d Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:44:49 -0400 Subject: [PATCH 022/152] ci: retire one-time dependency update workflow after successful lockfile patch --- .../workflows/jackerbox-safe-audit-fix.yml | 37 ------------------- 1 file changed, 37 deletions(-) delete mode 100644 .github/workflows/jackerbox-safe-audit-fix.yml diff --git a/.github/workflows/jackerbox-safe-audit-fix.yml b/.github/workflows/jackerbox-safe-audit-fix.yml deleted file mode 100644 index 419f71a..0000000 --- a/.github/workflows/jackerbox-safe-audit-fix.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: JackerBox one-time safe dependency patch - -on: - push: - branches: - - audit/security-and-rental-hardening-2026-10 - paths: - - .github/workflows/jackerbox-safe-audit-fix.yml - -permissions: - contents: write - -jobs: - safe-update: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '22' - - name: Apply non-breaking npm advisory fixes to lockfile - run: npm audit fix --package-lock-only --ignore-scripts --legacy-peer-deps --no-fund || true - - name: Validate updated lockfile - run: | - git diff --check - node -e "const p=require('./package.json'); const l=require('./package-lock.json'); if(p.name!==l.name)process.exit(1)" - - name: Commit safe lockfile updates only - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -- package.json package-lock.json - if git diff --cached --quiet; then exit 0; fi - git commit -m "security: apply non-breaking npm advisory fixes [skip ci]" - git fetch --no-tags origin audit/security-and-rental-hardening-2026-10 - git rebase FETCH_HEAD - git push origin HEAD:audit/security-and-rental-hardening-2026-10 From 2da8bdd76b16e35770aea4db644148d5ea586212 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:27:21 -0400 Subject: [PATCH 023/152] fix: reconcile Prisma model types, availability routes and equipment management --- src/app/api/admin/equipment/[id]/route.ts | 10 ++++---- .../[id]/availability/recurring/route.ts | 20 +++++----------- .../api/equipment/[id]/availability/route.ts | 24 ++++++++++--------- src/app/api/equipment/[id]/route.ts | 10 ++++---- src/app/api/profile/route.ts | 2 +- src/app/routes/admin/equipment/page.tsx | 4 ++-- src/app/routes/admin/users/page.tsx | 2 +- .../equipment/availability-calendar.tsx | 4 ++-- src/components/equipment/equipment-card.tsx | 2 +- src/components/equipment/equipment-form.tsx | 2 +- src/lib/prisma-client.ts | 3 +++ 11 files changed, 39 insertions(+), 44 deletions(-) create mode 100644 src/lib/prisma-client.ts diff --git a/src/app/api/admin/equipment/[id]/route.ts b/src/app/api/admin/equipment/[id]/route.ts index bf11905..633b658 100644 --- a/src/app/api/admin/equipment/[id]/route.ts +++ b/src/app/api/admin/equipment/[id]/route.ts @@ -4,18 +4,16 @@ import { db } from "@/lib/db"; // Use the correct Next.js App Router parameter type type RouteParams = { - params: { - id: string; - }; + params: Promise<{ id: string }>; }; export async function DELETE( - req: Request, + _req: Request, context: RouteParams ) { try { const user = await getCurrentUser(); - const { id } = context.params; + const { id } = await context.params; if (!user?.isAdmin) { return NextResponse.json( @@ -41,7 +39,7 @@ export async function DELETE( where: { equipmentId: id, status: { - in: ["PENDING", "CONFIRMED", "ACTIVE"], + in: ["PENDING", "PAID", "ACTIVE"], }, }, }); diff --git a/src/app/api/equipment/[id]/availability/recurring/route.ts b/src/app/api/equipment/[id]/availability/recurring/route.ts index 20bd14b..c3a3767 100644 --- a/src/app/api/equipment/[id]/availability/recurring/route.ts +++ b/src/app/api/equipment/[id]/availability/recurring/route.ts @@ -2,14 +2,6 @@ import { NextResponse } from "next/server"; import { z } from "zod"; import { db } from "@/lib/db"; import { getCurrentUser } from "@/lib/auth/auth-utils"; -import { PaperclipIcon } from 'lucide-react'; - -// Define a type for date ranges -interface DateRange { - startDate: Date; - endDate: Date; -} - // Define a type for date ranges interface DateRange { @@ -20,9 +12,9 @@ interface DateRange { // Schema for creating recurring availability const recurringAvailabilitySchema = z.object({ dates: z.array(z.object({ - startDate: z.date(), - endDate: z.date(), - })), + startDate: z.coerce.date(), + endDate: z.coerce.date(), + })).min(1).max(90), recurrenceType: z.enum(["daily", "weekly", "monthly"]), recurrenceInterval: z.number().min(1), recurrenceEndDate: z.string().refine((val) => { @@ -35,7 +27,7 @@ const recurringAvailabilitySchema = z.object({ // POST endpoint to add recurring availability periods export async function POST( req: Request, - { params }: { params: { id: string } } + { params }: { params: Promise<{ id: string }> } ) { try { const user = await getCurrentUser(); @@ -61,7 +53,7 @@ export async function POST( ); } - const equipmentId = await Promise.resolve(params.id); + const equipmentId = (await params).id; // Check if equipment exists and user is the owner const equipment = await db.equipment.findUnique({ @@ -104,7 +96,7 @@ export async function POST( where: { equipmentId, status: { - in: ["Pending", "Approved"], + in: ["PENDING", "PAID", "ACTIVE"], }, OR: [ { diff --git a/src/app/api/equipment/[id]/availability/route.ts b/src/app/api/equipment/[id]/availability/route.ts index 569c5c2..fd6dd28 100644 --- a/src/app/api/equipment/[id]/availability/route.ts +++ b/src/app/api/equipment/[id]/availability/route.ts @@ -25,18 +25,18 @@ const availabilitySchema = z.object({ // GET endpoint to fetch availability for an equipment export async function GET( - request: Request, - { params }: { params: { id: string } } + _request: Request, + { params }: { params: Promise<{ id: string }> } ) { try { - const equipmentId = params.id; + const equipmentId = (await params).id; // Get all bookings for this equipment - const bookings = await prisma.booking.findMany({ + const bookings = await prisma.rental.findMany({ where: { equipmentId, status: { - in: ['PENDING', 'CONFIRMED'] + in: ['PAID', 'ACTIVE'] } }, select: { @@ -60,7 +60,9 @@ export async function GET( } // Combine bookings with blackout dates and availability schedule + const ranges = await prisma.availability.findMany({ where: { equipmentId }, orderBy: { startDate: 'asc' } }); const availability = { + availability: ranges, bookings, blackoutDates: equipment.blackoutDates || [], availabilitySchedule: equipment.availabilitySchedule || {} @@ -76,7 +78,7 @@ export async function GET( // POST endpoint to add new availability period export async function POST( req: Request, - { params }: { params: { id: string } } + { params }: { params: Promise<{ id: string }> } ) { try { const user = await getCurrentUser(); @@ -102,7 +104,7 @@ export async function POST( ); } - const equipmentId = await Promise.resolve(params.id); + const equipmentId = (await params).id; // Check if equipment exists and user is the owner const equipment = await db.equipment.findUnique({ @@ -135,16 +137,16 @@ export async function POST( where: { equipmentId, status: { - in: ["Pending", "Approved"], + in: ["PENDING", "PAID", "ACTIVE"], }, OR: [ { // New availability period overlaps with existing booking startDate: { - lte: endDate, + lt: endDate, }, endDate: { - gte: startDate, + gt: startDate, }, }, ], @@ -215,7 +217,7 @@ export async function POST( // DELETE endpoint to remove an availability period export async function DELETE( req: Request, - { params }: { params: { id: string } } + { params }: { params: Promise<{ id: string }> } ) { try { const user = await getCurrentUser(); diff --git a/src/app/api/equipment/[id]/route.ts b/src/app/api/equipment/[id]/route.ts index 9fce7d2..19790fe 100644 --- a/src/app/api/equipment/[id]/route.ts +++ b/src/app/api/equipment/[id]/route.ts @@ -21,7 +21,7 @@ const updateEquipmentSchema = z.object({ }); export async function GET( - req: Request, + _req: Request, { params }: { params: Promise<{ id: string }> } ) { try { @@ -84,7 +84,7 @@ export async function GET( } export async function DELETE( - req: Request, + _req: Request, { params }: { params: Promise<{ id: string }> } ) { try { @@ -98,7 +98,7 @@ export async function DELETE( } // Properly await params before using - const equipmentId = await Promise.resolve(params.id); + const equipmentId = (await params).id; // Check if user is a renter (has rental history) const userRentals = await db.rental.count({ @@ -173,7 +173,7 @@ export async function DELETE( } export async function PATCH( - req: Request, + _req: Request, { params }: { params: Promise<{ id: string }> } ) { try { @@ -187,7 +187,7 @@ export async function PATCH( } // Properly await params before using - const equipmentId = await Promise.resolve(params.id); + const equipmentId = (await params).id; // Check if user is a renter (has rental history) const userRentals = await db.rental.count({ diff --git a/src/app/api/profile/route.ts b/src/app/api/profile/route.ts index 8de7b8e..6db9e56 100644 --- a/src/app/api/profile/route.ts +++ b/src/app/api/profile/route.ts @@ -58,7 +58,7 @@ export async function PUT(req: Request) { }, status: { not: { - in: ["Completed", "Cancelled"] + in: ["COMPLETED", "CANCELLED"] }, }, }, diff --git a/src/app/routes/admin/equipment/page.tsx b/src/app/routes/admin/equipment/page.tsx index 0ccfb59..2e14c63 100644 --- a/src/app/routes/admin/equipment/page.tsx +++ b/src/app/routes/admin/equipment/page.tsx @@ -6,7 +6,7 @@ import { EQUIPMENT_CATEGORIES } from "@/lib/constants"; import Link from "next/link"; import { EquipmentBulkActions } from "@/components/admin/equipment-bulk-actions"; import { ContentModerationPanel } from "@/components/admin/content-moderation-panel"; -import { Prisma, ModerationStatus } from "@prisma/client"; +import { Prisma, ModerationStatus } from "@/lib/prisma-client"; import { EquipmentFilters } from "@/components/admin/equipment-filters"; interface AdminEquipmentPageProps { @@ -82,7 +82,7 @@ export default async function AdminEquipmentPage({ searchParams }: AdminEquipmen // Convert to serializable format const serializedStats = moderationStats.map(stat => ({ moderationStatus: stat.moderationStatus, - count: stat._count, + count: stat._count._all, })); // Convert equipment to serializable format diff --git a/src/app/routes/admin/users/page.tsx b/src/app/routes/admin/users/page.tsx index 9c65678..07ff5a7 100644 --- a/src/app/routes/admin/users/page.tsx +++ b/src/app/routes/admin/users/page.tsx @@ -3,7 +3,7 @@ export const dynamic = 'force-dynamic'; import { getCurrentUser } from "@/lib/auth/auth-utils"; import { db } from "@/lib/db"; import Link from "next/link"; -import { Prisma } from "@prisma/client"; +import { Prisma } from "@/lib/prisma-client"; import { UserFilters } from "@/components/admin/user-filters"; interface AdminUsersPageProps { diff --git a/src/components/equipment/availability-calendar.tsx b/src/components/equipment/availability-calendar.tsx index 9e8b67c..1eafcc5 100644 --- a/src/components/equipment/availability-calendar.tsx +++ b/src/components/equipment/availability-calendar.tsx @@ -110,14 +110,14 @@ export function AvailabilityCalendar({ })); // Convert existing bookings to calendar events - const bookingEvents = existingBookings.map((booking) => ({ + const bookingEvents = (data.bookings?.length ? data.bookings.map((r: any) => ({ id: r.id, title: "Reserved", start: r.startDate, end: r.endDate, status: r.status })) : existingBookings).map((booking: any) => ({ id: booking.id, title: `Booked: ${booking.title}`, start: new Date(booking.start), end: new Date(booking.end), status: booking.status, allDay: true, - className: booking.status === "Approved" ? "bg-red-200" : "bg-yellow-200", + className: ["PAID", "ACTIVE"].includes(booking.status) ? "bg-red-200" : "bg-yellow-200", })); // Combine both types of events diff --git a/src/components/equipment/equipment-card.tsx b/src/components/equipment/equipment-card.tsx index d630015..863e820 100644 --- a/src/components/equipment/equipment-card.tsx +++ b/src/components/equipment/equipment-card.tsx @@ -1,6 +1,6 @@ "use client"; -import { Equipment, User } from "@prisma/client"; +import type { Equipment } from "@/lib/prisma-client"; import Image from "next/image"; import Link from "next/link"; import { formatCurrency } from "@/lib/utils/format"; diff --git a/src/components/equipment/equipment-form.tsx b/src/components/equipment/equipment-form.tsx index 2b49108..eaaa476 100644 --- a/src/components/equipment/equipment-form.tsx +++ b/src/components/equipment/equipment-form.tsx @@ -5,7 +5,7 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { useRouter } from "next/navigation"; -import { Equipment } from "@prisma/client"; +import type { Equipment } from "@/lib/prisma-client"; import { EQUIPMENT_CATEGORIES, EQUIPMENT_CONDITIONS } from "@/lib/constants"; import { useCloudinaryUpload } from "@/hooks/use-cloudinary-upload"; diff --git a/src/lib/prisma-client.ts b/src/lib/prisma-client.ts new file mode 100644 index 0000000..4cc57db --- /dev/null +++ b/src/lib/prisma-client.ts @@ -0,0 +1,3 @@ +// Canonical Prisma types and enums generated from prisma/schema.prisma. +// Do not import from @prisma/client: this app uses a custom generated output. +export * from '../../prisma/generated/client'; From e843a1345bff53bfe71e6eb0595528a1907c2183 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:27:50 -0400 Subject: [PATCH 024/152] fix: add missing notification preferences data model and migration --- .../migration.sql | 19 +++++++++++++++++++ prisma/schema.prisma | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 prisma/migrations/20261010103000_notification_preferences/migration.sql diff --git a/prisma/migrations/20261010103000_notification_preferences/migration.sql b/prisma/migrations/20261010103000_notification_preferences/migration.sql new file mode 100644 index 0000000..fe37270 --- /dev/null +++ b/prisma/migrations/20261010103000_notification_preferences/migration.sql @@ -0,0 +1,19 @@ +-- Persist notification preferences; the existing API previously referenced a missing Prisma model. +CREATE TABLE "NotificationPreference" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "notificationType" TEXT NOT NULL, + "emailEnabled" BOOLEAN NOT NULL DEFAULT true, + "pushEnabled" BOOLEAN NOT NULL DEFAULT true, + "inAppEnabled" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + CONSTRAINT "NotificationPreference_pkey" PRIMARY KEY ("id") +); +CREATE UNIQUE INDEX "NotificationPreference_userId_notificationType_key" + ON "NotificationPreference"("userId", "notificationType"); +CREATE INDEX "NotificationPreference_userId_idx" ON "NotificationPreference"("userId"); +ALTER TABLE "NotificationPreference" + ADD CONSTRAINT "NotificationPreference_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "User"("id") + ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4be6d9f..1221b5a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -40,6 +40,7 @@ model User { receivedMessages Message[] @relation("ReceivedMessages") sentMessages Message[] @relation("SentMessages") notifications Notification[] + notificationPreferences NotificationPreference[] payments Payment[] pushSubscriptions PushSubscription[] rentals Rental[] @relation("RenterRentals") @@ -366,3 +367,18 @@ enum RentalStatus { CANCELLED REFUNDED } + +model NotificationPreference { + id String @id @default(cuid()) + userId String + notificationType String + emailEnabled Boolean @default(true) + pushEnabled Boolean @default(true) + inAppEnabled Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([userId, notificationType]) + @@index([userId]) +} From 4755d3ba1fcf1ec06624ec0f4b294eea1f687d78 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:29:37 -0400 Subject: [PATCH 025/152] fix: protect rented equipment from bulk deletion --- src/app/api/admin/equipment/bulk/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/admin/equipment/bulk/route.ts b/src/app/api/admin/equipment/bulk/route.ts index 98d344c..c38e68e 100644 --- a/src/app/api/admin/equipment/bulk/route.ts +++ b/src/app/api/admin/equipment/bulk/route.ts @@ -56,7 +56,7 @@ export async function POST(req: Request) { rentals: { some: { status: { - in: ["PENDING", "APPROVED"], + in: ["PENDING", "PAID", "ACTIVE"], }, }, }, From 208d27719e6b12b9b1bd8ffeb9526cb2500b495a Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:29:55 -0400 Subject: [PATCH 026/152] fix: require paid rental states for admin transitions --- .../admin/rentals/[id]/update-status/route.ts | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/app/api/admin/rentals/[id]/update-status/route.ts b/src/app/api/admin/rentals/[id]/update-status/route.ts index 78d399d..d36a9aa 100644 --- a/src/app/api/admin/rentals/[id]/update-status/route.ts +++ b/src/app/api/admin/rentals/[id]/update-status/route.ts @@ -5,22 +5,13 @@ import { z } from "zod"; // Schema for updating rental status const updateRentalStatusSchema = z.object({ - status: z.enum([ - "PENDING", - "CONFIRMED", - "ACTIVE", - "COMPLETED", - "CANCELLED", - "DISPUTED", - ]), + status: z.enum(["ACTIVE", "COMPLETED", "CANCELLED"]), notes: z.string().optional(), }); // Use the correct Next.js App Router parameter type type RouteParams = { - params: { - id: string; - }; + params: Promise<{ id: string }>; }; export async function POST( @@ -29,7 +20,7 @@ export async function POST( ) { try { const user = await getCurrentUser(); - const { id } = context.params; + const { id } = await context.params; if (!user?.isAdmin) { return NextResponse.json( @@ -39,12 +30,13 @@ export async function POST( } const body = await req.json(); - const { status, notes } = updateRentalStatusSchema.parse(body); + const { status } = updateRentalStatusSchema.parse(body); // Check if rental exists const rental = await db.rental.findUnique({ where: { id }, include: { + payment: true, renter: true, equipment: { include: { @@ -61,14 +53,27 @@ export async function POST( ); } - // Update rental status - const updatedRental = await db.rental.update({ - where: { id }, - data: { - status, - }, + const paymentOk = rental.payment?.status === "COMPLETED"; + const allowed = + (status === "ACTIVE" && rental.status === "PAID" && paymentOk) || + (status === "COMPLETED" && rental.status === "ACTIVE" && paymentOk) || + (status === "CANCELLED" && rental.status === "PENDING" && !rental.payment?.stripePaymentIntentId); + + if (!allowed) return NextResponse.json( + { message: "Invalid transition or unresolved payment. Paid cancellations need refund processing." }, + { status: 409 } + ); + + const changed = await db.rental.updateMany({ + where: { id, status: rental.status }, + data: { status }, }); - + if (changed.count !== 1) return NextResponse.json( + { message: "The rental changed during this request. Refresh and retry." }, + { status: 409 } + ); + const updatedRental = await db.rental.findUnique({ where: { id } }); + // Create notifications for both renter and owner await db.notification.create({ data: { From 7ca0fe5b45a231052361db77b3f1550f2b65c362 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:30:14 -0400 Subject: [PATCH 027/152] fix: align seed scripts to Prisma client and prevent production reseeding --- prisma/seed.ts | 3 ++- scripts/create-admin.ts | 2 +- scripts/seed-test-data.ts | 15 +++------------ scripts/setup-stripe-connect.ts | 2 +- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/prisma/seed.ts b/prisma/seed.ts index 027a8c6..6f84489 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,9 +1,10 @@ -import { PrismaClient } from '@prisma/client'; +import { PrismaClient } from './generated/client'; import { hash } from 'bcryptjs'; const prisma = new PrismaClient(); async function main() { + if (process.env.NODE_ENV === 'production') throw new Error('Demo data seeding is disabled in production'); // Clear existing data await prisma.equipment.deleteMany(); await prisma.user.deleteMany(); diff --git a/scripts/create-admin.ts b/scripts/create-admin.ts index aa1ceab..978259f 100644 --- a/scripts/create-admin.ts +++ b/scripts/create-admin.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from '@prisma/client'; +import { PrismaClient } from '../prisma/generated/client'; const prisma = new PrismaClient(); diff --git a/scripts/seed-test-data.ts b/scripts/seed-test-data.ts index bf26283..6cf43a9 100644 --- a/scripts/seed-test-data.ts +++ b/scripts/seed-test-data.ts @@ -1,19 +1,10 @@ -import { PrismaClient, ModerationStatus } from '@prisma/client'; +import { PrismaClient, ModerationStatus, RentalStatus } from '../prisma/generated/client'; import { hash } from 'bcryptjs'; const prisma = new PrismaClient(); -// Define RentalStatus constants instead of enum -const RentalStatus = { - PENDING: 'PENDING', - APPROVED: 'APPROVED', - ACTIVE: 'ACTIVE', - COMPLETED: 'COMPLETED', - CANCELED: 'CANCELED', - DISPUTED: 'DISPUTED' -} as const; - async function main() { + if (process.env.NODE_ENV === 'production') throw new Error('Demo data seeding is disabled in production'); console.log('🌱 Starting to seed test data...'); // Clean up existing data (optional - comment out if you want to keep existing data) @@ -406,7 +397,7 @@ async function main() { data: { startDate: new Date(Date.now() - 20 * 24 * 60 * 60 * 1000), // 20 days ago endDate: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000), // 15 days ago - status: RentalStatus.CANCELED, + status: RentalStatus.CANCELLED, totalPrice: 95, // Added required field securityDeposit: 1200, equipmentId: videoCamera.id, diff --git a/scripts/setup-stripe-connect.ts b/scripts/setup-stripe-connect.ts index 97f1267..4d46ff0 100644 --- a/scripts/setup-stripe-connect.ts +++ b/scripts/setup-stripe-connect.ts @@ -1,4 +1,4 @@ -import { PrismaClient } from '@prisma/client'; +import { PrismaClient } from '../prisma/generated/client'; import Stripe from 'stripe'; const prisma = new PrismaClient(); From 21715eeb7c1f507bb8e78489530f645fd6dfa54d Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:30:27 -0400 Subject: [PATCH 028/152] fix: fail closed on nonfunctional dispute resolution route --- src/app/api/admin/disputes/resolve/route.ts | 180 ++------------------ 1 file changed, 11 insertions(+), 169 deletions(-) diff --git a/src/app/api/admin/disputes/resolve/route.ts b/src/app/api/admin/disputes/resolve/route.ts index b483732..8492ee9 100644 --- a/src/app/api/admin/disputes/resolve/route.ts +++ b/src/app/api/admin/disputes/resolve/route.ts @@ -1,170 +1,12 @@ -import { NextResponse } from "next/server"; -import { getCurrentUser } from "@/lib/auth/auth-utils"; -import { db } from "@/lib/db"; -import { z } from "zod"; +import { NextResponse } from 'next/server'; +import { getCurrentUser } from '@/lib/auth/auth-utils'; -// Schema for dispute resolution -const disputeResolutionSchema = z.object({ - rentalId: z.string().min(1, "Rental ID is required"), - resolution: z.string().min(1, "Resolution explanation is required"), - outcome: z.enum(["FAVOR_RENTER", "FAVOR_OWNER", "COMPROMISE"]), - refundAmount: z.number().nullable(), -}); - -export async function POST(req: Request) { - try { - const user = await getCurrentUser(); - - // Ensure user is an admin - if (!user?.isAdmin) { - return NextResponse.json( - { message: "Unauthorized. Admin access required." }, - { status: 401 } - ); - } - - // Parse and validate request body - const body = await req.json(); - const validationResult = disputeResolutionSchema.safeParse(body); - - if (!validationResult.success) { - return NextResponse.json( - { message: "Invalid input data", errors: validationResult.error.errors }, - { status: 400 } - ); - } - - const { rentalId, resolution, outcome, refundAmount } = validationResult.data; - - // Find the rental - const rental = await db.rental.findUnique({ - where: { id: rentalId }, - include: { - equipment: { - include: { - owner: true, - }, - }, - renter: true, - payment: true, - }, - }); - - if (!rental) { - return NextResponse.json( - { message: "Rental not found" }, - { status: 404 } - ); - } - - if (rental.status !== "DISPUTED") { - return NextResponse.json( - { message: "Rental is not in a disputed state" }, - { status: 400 } - ); - } - - // Find open dispute for this rental - const openDispute = await db.dispute.findFirst({ - where: { - rentalId, - status: "OPEN", - }, - }); - - if (!openDispute) { - return NextResponse.json( - { message: "No open dispute found for this rental" }, - { status: 404 } - ); - } - - // Start a transaction to ensure all updates happen together - const result = await db.$transaction(async (tx) => { - // 1. Update the dispute status - await tx.dispute.update({ - where: { id: openDispute.id }, - data: { - status: "RESOLVED", - resolution, - outcome, - resolvedById: user.id, - resolvedAt: new Date(), - }, - }); - - // 2. Update rental status based on outcome - await tx.rental.update({ - where: { id: rentalId }, - data: { - status: outcome === "FAVOR_OWNER" ? "COMPLETED" : "CANCELLED", - updatedAt: new Date(), - }, - }); - - // 3. Process refund if needed - if ((outcome === "FAVOR_RENTER" || outcome === "COMPROMISE") && refundAmount && refundAmount > 0) { - // Check if payment exists and has a valid amount - if (!rental.payment) { - throw new Error("No payment found for this rental"); - } - - // Record the refund transaction - await tx.transaction.create({ - data: { - amount: refundAmount, - type: "REFUND", - status: "COMPLETED", - description: `Refund for disputed rental #${rentalId.substring(0, 8)}`, - userId: rental.renterId, - rentalId, - }, - }); - } - - // 4. Create notifications for both parties - // For the renter - await tx.notification.create({ - data: { - type: "DISPUTE_RESOLVED", - userId: rental.renterId, - data: { - rentalId, - equipmentName: rental.equipment.title, - resolution, - outcome, - refundAmount: refundAmount || 0, - }, - }, - }); - - // For the owner - await tx.notification.create({ - data: { - type: "DISPUTE_RESOLVED", - userId: rental.equipment.ownerId, - data: { - rentalId, - equipmentName: rental.equipment.title, - resolution, - outcome, - refundAmount: refundAmount || 0, - }, - }, - }); - - return { success: true }; - }); - - return NextResponse.json({ - message: "Dispute resolved successfully", - outcome, - }); - } catch (error) { - console.error("Error resolving dispute:", error); - return NextResponse.json( - { message: "Something went wrong. Please try again." }, - { status: 500 } - ); - } -} \ No newline at end of file +// Disputes need a persisted case model, an audit trail and Stripe refund confirmation. +// The legacy handler referenced tables that do not exist. Never report success here. +export async function POST() { + const user = await getCurrentUser(); + if (!user?.isAdmin) return NextResponse.json({ message: 'Forbidden' }, { status: 403 }); + return NextResponse.json({ + message: 'Dispute resolution is unavailable until the case ledger and payment workflow are enabled.', + }, { status: 501 }); +} From 8c7f1321967233a3031b6288c0c87c4d074198fa Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:31:18 -0400 Subject: [PATCH 029/152] fix: resolve targeted type regressions and avoid duplicate CI runs --- .github/workflows/jackerbox-repair.yml | 3 --- src/app/api/equipment/[id]/availability/route.ts | 2 +- src/app/api/equipment/[id]/route.ts | 2 +- src/app/routes/admin/equipment/page.tsx | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/jackerbox-repair.yml b/.github/workflows/jackerbox-repair.yml index 5ab466a..95dd78d 100644 --- a/.github/workflows/jackerbox-repair.yml +++ b/.github/workflows/jackerbox-repair.yml @@ -1,9 +1,6 @@ name: JackerBox repair checks on: - push: - branches: - - audit/security-and-rental-hardening-2026-10 pull_request: branches: - main diff --git a/src/app/api/equipment/[id]/availability/route.ts b/src/app/api/equipment/[id]/availability/route.ts index fd6dd28..754144e 100644 --- a/src/app/api/equipment/[id]/availability/route.ts +++ b/src/app/api/equipment/[id]/availability/route.ts @@ -217,7 +217,7 @@ export async function POST( // DELETE endpoint to remove an availability period export async function DELETE( req: Request, - { params }: { params: Promise<{ id: string }> } + { params: _params }: { params: Promise<{ id: string }> } ) { try { const user = await getCurrentUser(); diff --git a/src/app/api/equipment/[id]/route.ts b/src/app/api/equipment/[id]/route.ts index 19790fe..7658da4 100644 --- a/src/app/api/equipment/[id]/route.ts +++ b/src/app/api/equipment/[id]/route.ts @@ -173,7 +173,7 @@ export async function DELETE( } export async function PATCH( - _req: Request, + req: Request, { params }: { params: Promise<{ id: string }> } ) { try { diff --git a/src/app/routes/admin/equipment/page.tsx b/src/app/routes/admin/equipment/page.tsx index 2e14c63..7ec8531 100644 --- a/src/app/routes/admin/equipment/page.tsx +++ b/src/app/routes/admin/equipment/page.tsx @@ -82,7 +82,7 @@ export default async function AdminEquipmentPage({ searchParams }: AdminEquipmen // Convert to serializable format const serializedStats = moderationStats.map(stat => ({ moderationStatus: stat.moderationStatus, - count: stat._count._all, + _count: stat._count, })); // Convert equipment to serializable format From 6eaad500db152c4a11d7af06bdbd783e115ed080 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:32:55 -0400 Subject: [PATCH 030/152] fix: replace broken search SQL interpolation with safe Prisma filters --- src/app/api/search/equipment/route.ts | 415 +++++++------------------- 1 file changed, 115 insertions(+), 300 deletions(-) diff --git a/src/app/api/search/equipment/route.ts b/src/app/api/search/equipment/route.ts index 788a84c..9272f1a 100644 --- a/src/app/api/search/equipment/route.ts +++ b/src/app/api/search/equipment/route.ts @@ -1,313 +1,128 @@ import { NextRequest, NextResponse } from 'next/server'; -import { db as prisma } from '@/lib/db'; -import { getCurrentUser } from '@/lib/auth/session'; +import { Prisma } from '@/lib/prisma-client'; +import { db } from '@/lib/db'; export const dynamic = 'force-dynamic'; -export const fetchCache = 'force-no-store'; -export const revalidate = 0; -/** - * Advanced equipment search API with PostgreSQL full-text search and trigram similarity - * Supports hybrid search combining keyword matching, location proximity, and category filtering - */ +const rad = (n: number) => n * Math.PI / 180; +function distanceKm(lat1: number, lng1: number, lat2: number, lng2: number) { + const dLat = rad(lat2 - lat1); + const dLng = rad(lng2 - lng1); + const a = Math.sin(dLat / 2) ** 2 + + Math.cos(rad(lat1)) * Math.cos(rad(lat2)) * Math.sin(dLng / 2) ** 2; + return 6371 * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); +} + +function jsonArray(value: string): string[] { + try { + const parsed: unknown = JSON.parse(value); + return Array.isArray(parsed) ? parsed.filter((v): v is string => typeof v === 'string') : []; + } catch { return []; } +} + export async function GET(req: NextRequest) { + const p = req.nextUrl.searchParams; + const query = (p.get('query') ?? '').trim(); + const category = (p.get('category') ?? '').trim(); + const subcategory = (p.get('subcategory') ?? '').trim(); + const location = (p.get('location') ?? '').trim(); + const page = Number(p.get('page') ?? '1'); + const limit = Number(p.get('limit') ?? '20'); + const sortBy = p.get('sortBy') ?? 'newest'; + + if (query.length > 120 || category.length > 80 || subcategory.length > 80 || location.length > 100 || + !Number.isInteger(page) || page < 1 || page > 1000 || + !Number.isInteger(limit) || limit < 1 || limit > 50) { + return NextResponse.json({ error: 'Invalid search criteria or pagination' }, { status: 400 }); + } + + function optionalNumber(key: string): number | undefined { + const raw = p.get(key); + if (raw == null || raw === '') return undefined; + return Number(raw); + } + const lat = optionalNumber('lat'); + const lng = optionalNumber('lng'); + const maxDistance = optionalNumber('maxDistance'); + const priceMin = optionalNumber('priceMin'); + const priceMax = optionalNumber('priceMax'); + const numbers = [lat, lng, maxDistance, priceMin, priceMax].filter((x): x is number => x !== undefined); + if (numbers.some(x => !Number.isFinite(x)) || + ((lat === undefined) !== (lng === undefined)) || + (lat !== undefined && (Math.abs(lat) > 90 || Math.abs(lng!) > 180)) || + (maxDistance !== undefined && (maxDistance <= 0 || maxDistance > 500)) || + (maxDistance !== undefined && lat === undefined) || + (priceMin !== undefined && priceMin < 0) || + (priceMax !== undefined && priceMax < 0) || + (priceMin !== undefined && priceMax !== undefined && priceMin > priceMax)) { + return NextResponse.json({ error: 'Invalid numeric search filters' }, { status: 400 }); + } + + const where: Prisma.EquipmentWhereInput = { + isAvailable: true, + moderationStatus: 'APPROVED', + ...(category ? { category } : {}), + ...(subcategory ? { subcategory } : {}), + ...(location ? { location: { contains: location, mode: 'insensitive' } } : {}), + }; + const and: Prisma.EquipmentWhereInput[] = []; + if (query) and.push({ OR: [ + { title: { contains: query, mode: 'insensitive' } }, + { description: { contains: query, mode: 'insensitive' } }, + { category: { contains: query, mode: 'insensitive' } }, + { subcategory: { contains: query, mode: 'insensitive' } }, + ] }); + if (priceMin !== undefined || priceMax !== undefined) { + const range = { ...(priceMin !== undefined ? { gte: priceMin } : {}), + ...(priceMax !== undefined ? { lte: priceMax } : {}) }; + and.push({ OR: [{ hourlyRate: range }, { dailyRate: range }, { weeklyRate: range }] }); + } + if (and.length > 0) where.AND = and; + + const sort: Prisma.EquipmentOrderByWithRelationInput = + sortBy === 'price_asc' ? { dailyRate: 'asc' } : + sortBy === 'price_desc' ? { dailyRate: 'desc' } : + { createdAt: 'desc' }; + try { - const { searchParams } = new URL(req.url); - - // Extract search parameters - const query = searchParams.get('query') || ''; - const category = searchParams.get('category') || ''; - const subcategory = searchParams.get('subcategory') || ''; - const lat = searchParams.get('lat') ? parseFloat(searchParams.get('lat')!) : null; - const lng = searchParams.get('lng') ? parseFloat(searchParams.get('lng')!) : null; - const maxDistance = searchParams.get('maxDistance') ? parseFloat(searchParams.get('maxDistance')!) : null; - const priceMin = searchParams.get('priceMin') ? parseFloat(searchParams.get('priceMin')!) : null; - const priceMax = searchParams.get('priceMax') ? parseFloat(searchParams.get('priceMax')!) : null; - const page = parseInt(searchParams.get('page') || '1'); - const limit = parseInt(searchParams.get('limit') || '20'); - const sortBy = searchParams.get('sortBy') || 'relevance'; - - console.log('Search parameters:', { query, category, subcategory, lat, lng, maxDistance, priceMin, priceMax, page, limit, sortBy }); - - // Prepare filter conditions - const conditions: any[] = [ - { isAvailable: true }, - { moderationStatus: 'APPROVED' }, - ]; - - // Category filters - if (category) { - conditions.push({ category }); - } - - if (subcategory) { - conditions.push({ subcategory }); - } - - // Price filters - if (priceMin !== null) { - conditions.push({ - OR: [ - { dailyRate: { gte: priceMin } }, - { hourlyRate: { gte: priceMin } } - ] + if (lat !== undefined && lng !== undefined) { + // Bounded candidate set; safe without interpolated raw SQL. + const candidates = await db.equipment.findMany({ + where: { ...where, latitude: { not: null }, longitude: { not: null } }, + orderBy: sort, + take: 1000, }); - } - - if (priceMax !== null) { - conditions.push({ - OR: [ - { dailyRate: { lte: priceMax } }, - { hourlyRate: { lte: priceMax } } - ] - }); - } - - // Prepare the search query - let searchEquipment; - let totalCount; - - // Skip pagination for first request to get totalCount - const skip = (page - 1) * limit; - - try { - // If there's a search query - if (query.trim()) { - console.log('Executing full-text search query'); - // Generate search vectors from user input - const searchTerms = query.trim().split(/\s+/).filter(Boolean); - - try { - // Create full-text search condition with weights for different fields - // Add trigram similarity for fuzzy matching - const searchConditions = await prisma.$queryRaw` - SELECT id, - title, - description, - category, - subcategory, - location, - hourlyRate, - dailyRate, - weeklyRate, - securityDeposit, - isAvailable, - "createdAt", - "updatedAt", - "moderationStatus", - "isVerified", - "ownerId", - "imagesJson", - "tagsJson", - ts_rank( - setweight(to_tsvector('english', title), 'A') || - setweight(to_tsvector('english', description), 'B') || - setweight(to_tsvector('english', category), 'C') || - setweight(to_tsvector('english', COALESCE(subcategory, '')), 'D'), - plainto_tsquery('english', ${query}) - ) AS rank, - CASE - WHEN ${lat} IS NOT NULL AND ${lng} IS NOT NULL AND latitude IS NOT NULL AND longitude IS NOT NULL - THEN ( - 6371 * acos( - cos(radians(${lat})) * - cos(radians(latitude)) * - cos(radians(longitude) - radians(${lng})) + - sin(radians(${lat})) * - sin(radians(latitude)) - ) - ) - ELSE NULL - END as distance - FROM "Equipment" - WHERE - "moderationStatus" = 'APPROVED' AND - "isAvailable" = true AND - ( - to_tsvector('english', title) || - to_tsvector('english', description) || - to_tsvector('english', category) || - to_tsvector('english', COALESCE(subcategory, '')) - ) @@ plainto_tsquery('english', ${query}) - ${category ? ` AND category = ${category}` : ''} - ${subcategory ? ` AND subcategory = ${subcategory}` : ''} - ${priceMin ? ` AND (COALESCE("dailyRate", 0) >= ${priceMin} OR COALESCE("hourlyRate", 0) >= ${priceMin})` : ''} - ${priceMax ? ` AND (COALESCE("dailyRate", 0) <= ${priceMax} OR COALESCE("hourlyRate", 0) <= ${priceMax})` : ''} - ${(lat && lng && maxDistance) ? ` AND ( - 6371 * acos( - cos(radians(${lat})) * - cos(radians(latitude)) * - cos(radians(longitude) - radians(${lng})) + - sin(radians(${lat})) * - sin(radians(latitude)) - ) - ) <= ${maxDistance}` : ''} - ORDER BY - ${sortBy === 'distance' && lat && lng ? 'distance ASC,' : ''} - ${sortBy === 'price_asc' ? 'COALESCE("dailyRate", "hourlyRate" * 8) ASC,' : ''} - ${sortBy === 'price_desc' ? 'COALESCE("dailyRate", "hourlyRate" * 8) DESC,' : ''} - ${sortBy === 'newest' ? '"createdAt" DESC,' : ''} - ${sortBy === 'relevance' || !sortBy ? 'rank DESC,' : ''} - "createdAt" DESC - LIMIT ${limit} OFFSET ${skip} - `; - - // Get total count for pagination - const countResult = await prisma.$queryRaw` - SELECT COUNT(*) as count - FROM "Equipment" - WHERE - "moderationStatus" = 'APPROVED' AND - "isAvailable" = true AND - ( - to_tsvector('english', title) || - to_tsvector('english', description) || - to_tsvector('english', category) || - to_tsvector('english', COALESCE(subcategory, '')) - ) @@ plainto_tsquery('english', ${query}) - ${category ? ` AND category = ${category}` : ''} - ${subcategory ? ` AND subcategory = ${subcategory}` : ''} - ${priceMin ? ` AND (COALESCE("dailyRate", 0) >= ${priceMin} OR COALESCE("hourlyRate", 0) >= ${priceMin})` : ''} - ${priceMax ? ` AND (COALESCE("dailyRate", 0) <= ${priceMax} OR COALESCE("hourlyRate", 0) <= ${priceMax})` : ''} - ${(lat && lng && maxDistance) ? ` AND ( - 6371 * acos( - cos(radians(${lat})) * - cos(radians(latitude)) * - cos(radians(longitude) - radians(${lng})) + - sin(radians(${lat})) * - sin(radians(latitude)) - ) - ) <= ${maxDistance}` : ''} - `; - - searchEquipment = searchConditions; - totalCount = (countResult as any)[0].count; - } catch (rawQueryError) { - console.error('Raw query error:', rawQueryError); - - // Fallback to standard query if raw query fails (e.g., if ts_rank is not available) - console.log('Falling back to standard query'); - - // Add text search condition - conditions.push({ - OR: [ - { title: { contains: query, mode: 'insensitive' } }, - { description: { contains: query, mode: 'insensitive' } }, - { category: { contains: query, mode: 'insensitive' } }, - { subcategory: { contains: query, mode: 'insensitive' } } - ] - }); - - const baseQuery: any = { - where: { - AND: conditions, - }, - skip, - take: limit, - orderBy: [{ createdAt: 'desc' }] - }; - - searchEquipment = await prisma.equipment.findMany(baseQuery); - - // Get total count for pagination - totalCount = await prisma.equipment.count({ - where: { - AND: conditions, - }, - }); - } - } else { - // If no search query, just use filters - console.log('Executing standard filter query'); - const baseQuery: any = { - where: { - AND: conditions, - }, - skip, - take: limit, - }; - - // Sorting options - if (sortBy === 'price_asc') { - baseQuery.orderBy = [{ dailyRate: 'asc' }]; - } else if (sortBy === 'price_desc') { - baseQuery.orderBy = [{ dailyRate: 'desc' }]; - } else if (sortBy === 'newest') { - baseQuery.orderBy = [{ createdAt: 'desc' }]; - } else { - baseQuery.orderBy = [{ createdAt: 'desc' }]; - } - - // Execute query - searchEquipment = await prisma.equipment.findMany(baseQuery); - - // Get total count for pagination - const count = await prisma.equipment.count({ - where: { - AND: conditions, - }, - }); - - totalCount = count; - } - } catch (queryError) { - console.error('Query execution error:', queryError); - return NextResponse.json( - { - error: 'Query execution failed', - details: queryError instanceof Error ? queryError.message : 'Unknown error' + const filtered = candidates.map(item => ({ + ...item, + distance: distanceKm(lat, lng, item.latitude!, item.longitude!), + })).filter(item => maxDistance === undefined || item.distance <= maxDistance); + if (sortBy === 'distance') filtered.sort((a, b) => a.distance - b.distance); + const results = filtered.slice((page - 1) * limit, page * limit).map(item => ({ + ...item, + distance: Number(item.distance.toFixed(1)), + images: jsonArray(item.imagesJson), + tags: jsonArray(item.tagsJson), + })); + return NextResponse.json({ + results, + pagination: { + total: filtered.length, page, limit, + pages: Math.ceil(filtered.length / limit), + truncated: candidates.length === 1000, }, - { status: 500 } - ); + }); } - - // Process results - console.log(`Found ${Array.isArray(searchEquipment) ? searchEquipment.length : 0} results`); - - const results = Array.isArray(searchEquipment) ? searchEquipment.map(item => { - try { - // Parse JSON strings to objects - const images = item.imagesJson ? JSON.parse(item.imagesJson as string) : []; - const tags = item.tagsJson ? JSON.parse(item.tagsJson as string) : []; - - // Format the item - return { - ...item, - images, - tags, - // Include distance if available - ...(item.distance !== undefined && { distance: parseFloat(item.distance.toFixed(1)) }), - // Include rank score if available - ...(item.rank !== undefined && { relevanceScore: parseFloat(item.rank.toFixed(3)) }), - }; - } catch (parseError) { - console.error('Error parsing item JSON:', parseError, item); - // Return item without attempting to parse JSON fields - return { - ...item, - images: [], - tags: [], - }; - } - }) : []; - + + const [items, total] = await Promise.all([ + db.equipment.findMany({ where, orderBy: sort, skip: (page - 1) * limit, take: limit }), + db.equipment.count({ where }), + ]); return NextResponse.json({ - results, - pagination: { - total: totalCount, - page, - limit, - pages: Math.ceil(totalCount / limit), - }, + results: items.map(item => ({ ...item, images: jsonArray(item.imagesJson), tags: jsonArray(item.tagsJson) })), + pagination: { total, page, limit, pages: Math.ceil(total / limit) }, }); } catch (error) { - console.error('Search error:', error); - return NextResponse.json( - { - error: 'Failed to perform search', - details: error instanceof Error ? error.message : 'Unknown error' - }, - { status: 500 } - ); + console.error('Equipment search failed', error); + return NextResponse.json({ error: 'Search currently unavailable' }, { status: 500 }); } -} \ No newline at end of file +} From 09c0e28ca66f33e14d38c79a474e8a3c586c84a8 Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:34:12 -0400 Subject: [PATCH 031/152] fix: stabilize global provider and booking form typings; correct paid revenue counts --- src/app/routes/admin/page.tsx | 7 +++-- src/components/rentals/booking-form.tsx | 19 ++++++++++-- src/components/root-provider.tsx | 40 +++++-------------------- 3 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/app/routes/admin/page.tsx b/src/app/routes/admin/page.tsx index f28165e..0d4880a 100644 --- a/src/app/routes/admin/page.tsx +++ b/src/app/routes/admin/page.tsx @@ -55,6 +55,7 @@ export default async function AdminDashboardPage() { // Calculate total revenue (simplified) const totalRevenue = await db.rental.aggregate({ + where: { payment: { is: { status: 'COMPLETED' } } }, _sum: { totalPrice: true } @@ -63,11 +64,11 @@ export default async function AdminDashboardPage() { // Get rental status counts const rentalStatusCounts = await Promise.all([ db.rental.count({ where: { status: "PENDING" } }), - db.rental.count({ where: { status: "CONFIRMED" } }), - db.rental.count({ where: { status: "IN_PROGRESS" } }), + db.rental.count({ where: { status: "PAID" } }), + db.rental.count({ where: { status: "ACTIVE" } }), db.rental.count({ where: { status: "COMPLETED" } }), db.rental.count({ where: { status: "CANCELLED" } }), - db.rental.count({ where: { status: "DISPUTED" } }) + db.rental.count({ where: { status: "PAYMENT_FAILED" } }) ]); return ( diff --git a/src/components/rentals/booking-form.tsx b/src/components/rentals/booking-form.tsx index b3d8e6f..1f67413 100644 --- a/src/components/rentals/booking-form.tsx +++ b/src/components/rentals/booking-form.tsx @@ -5,9 +5,21 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { useRouter } from "next/navigation"; -import type { Equipment } from "../../../prisma/generated/client"; +import type { Equipment } from '@/lib/prisma-client'; import { formatCurrency, formatDateRange } from "@/lib/utils/format"; -import { differenceInDays, differenceInHours, addDays } from "date-fns"; +import { addDays } from "date-fns"; + +// The optional calendar widget shares its selection with this form. +declare global { + interface Window { + calendarState?: { + startDate: string; + endDate: string; + setStartDate: (value: string) => void; + setEndDate: (value: string) => void; + }; + } +} // Define the minimum booking schema const bookingSchema = z.object({ @@ -113,6 +125,7 @@ export function BookingForm({ equipment }: BookingFormProps) { } }; } + return undefined; }, [setValue]); // Update calendar when form values change @@ -145,7 +158,7 @@ export function BookingForm({ equipment }: BookingFormProps) { const days = Math.max(1, Math.ceil((end.getTime() - start.getTime()) / 86400000)); price = days * equipment.dailyRate; } else if (rentalType === "weekly" && equipment.weeklyRate) { - const days = differenceInDays(end, start); + const days = Math.ceil((end.getTime() - start.getTime()) / 86400000); const weeks = Math.max(1, Math.ceil(days / 7)); price = weeks * equipment.weeklyRate; } diff --git a/src/components/root-provider.tsx b/src/components/root-provider.tsx index 2ec0bfa..0bb4506 100644 --- a/src/components/root-provider.tsx +++ b/src/components/root-provider.tsx @@ -1,6 +1,4 @@ import React, { createContext, useContext, useState, useEffect, ReactNode, useCallback, useRef } from 'react'; -import { useRouter } from 'next/navigation'; -import { clearExpiredCache } from '@/lib/caching'; import { toast } from 'sonner'; // Context type @@ -32,11 +30,10 @@ export const useRootContext = () => useContext(RootContext); // Main provider component export default function RootProvider({ children }: { children: ReactNode }) { - const router = useRouter(); const [isPageChanging, setIsPageChanging] = useState(false); - const [connectionStatus, setConnectionStatus] = useState({ - socket: 'connecting' as const, - sse: 'connecting' as const + const [connectionStatus, setConnectionStatus] = useState({ + socket: 'connecting', + sse: 'connecting' }); // Refs to track previous status and prevent infinite updates @@ -45,19 +42,6 @@ export default function RootProvider({ children }: { children: ReactNode }) { const toastTimeoutRef = useRef(null); const [toastShown, setToastShown] = useState(false); - // Clean expired cache periodically - useEffect(() => { - // Clean on initial load - clearExpiredCache(); - - // Set up interval to clean expired cache items - const interval = setInterval(() => { - clearExpiredCache(); - }, 5 * 60 * 1000); // Every 5 minutes - - return () => clearInterval(interval); - }, []); - // Monitor page transitions to reduce unnecessary API calls useEffect(() => { // Function to handle the start of a route change @@ -65,14 +49,6 @@ export default function RootProvider({ children }: { children: ReactNode }) { setIsPageChanging(true); }; - // Function to handle the completion of a route change - const handleRouteChangeComplete = () => { - // Small delay to ensure components have time to mount before we mark transition as complete - setTimeout(() => { - setIsPageChanging(false); - }, 100); - }; - // Add event listeners for route changes window.addEventListener('beforeunload', handleRouteChangeStart); @@ -82,7 +58,7 @@ export default function RootProvider({ children }: { children: ReactNode }) { return () => { window.removeEventListener('beforeunload', handleRouteChangeStart); }; - }, [router]); + }, []); // Manage connection statuses with debounced toasts useEffect(() => { @@ -97,8 +73,7 @@ export default function RootProvider({ children }: { children: ReactNode }) { if (socketStatus === 'error' || sseStatus === 'error') { if (!toastShown) { - toast({ - title: 'Connection error', + toast.error('Connection error', { description: 'There was a problem connecting to the server. Some features may not work properly.', duration: 3000 }); @@ -116,8 +91,7 @@ export default function RootProvider({ children }: { children: ReactNode }) { } }, 2000); // Wait 2 seconds before showing to avoid flickering } else if ((socketStatus === 'connected' && sseStatus === 'connected') && toastShown) { - toast({ - title: 'Connection restored', + toast.success('Connection restored', { description: 'You are back online.', duration: 3000 }); @@ -148,7 +122,7 @@ export default function RootProvider({ children }: { children: ReactNode }) { setConnectionStatus(prev => ({ ...prev, - [type]: status + [type]: status as RootContextType['connectionStatus'][typeof type], })); } }, []); From 8c269178964e4f63fbbb835cb9c275719e1675bc Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:34:31 -0400 Subject: [PATCH 032/152] security: block unsigned Apple notifications from mutating accounts --- src/app/api/auth/apple/webhook/route.ts | 56 ++------ src/app/api/webhooks/apple/route.ts | 181 +----------------------- 2 files changed, 15 insertions(+), 222 deletions(-) diff --git a/src/app/api/auth/apple/webhook/route.ts b/src/app/api/auth/apple/webhook/route.ts index ee3983e..3efed8e 100644 --- a/src/app/api/auth/apple/webhook/route.ts +++ b/src/app/api/auth/apple/webhook/route.ts @@ -1,50 +1,10 @@ import { NextResponse } from 'next/server'; -import prisma from '@/lib/db'; -export async function POST(req: Request) { - try { - const payload = await req.json(); - - // Log the notification for debugging - console.log('Received Apple notification:', payload); - - // Handle different types of notifications - switch (payload.type) { - case 'email-disabled': - case 'email-enabled': - await prisma.user.update({ - where: { - appleId: payload.sub - }, - data: { - emailVerified: payload.type === 'email-enabled' - } - }); - break; - - case 'consent-revoked': - // Handle user revoking consent - await prisma.account.deleteMany({ - where: { - provider: 'apple', - providerAccountId: payload.sub - } - }); - break; - - case 'account-delete': - // Handle account deletion - await prisma.user.delete({ - where: { - appleId: payload.sub - } - }); - break; - } - - return NextResponse.json({ success: true }); - } catch (error) { - console.error('Error handling Apple webhook:', error); - return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); - } -} \ No newline at end of file +// Apple server-to-server messages must be cryptographically verified against Apple's +// current signing keys before changing any linked account or personal data. +// Never trust an unauthenticated JSON body for deletion or verification. +export async function POST() { + return NextResponse.json({ + error: 'Apple notification processing is not configured', + }, { status: 501 }); +} diff --git a/src/app/api/webhooks/apple/route.ts b/src/app/api/webhooks/apple/route.ts index 17e5c07..3efed8e 100644 --- a/src/app/api/webhooks/apple/route.ts +++ b/src/app/api/webhooks/apple/route.ts @@ -1,177 +1,10 @@ import { NextResponse } from 'next/server'; -import prisma from '@/lib/db'; -import crypto from 'crypto'; -// Initialize rate limiter (with fallback if Upstash is not available) -let ratelimit: any = null; -try { - const { Ratelimit } = require('@upstash/ratelimit'); - const { Redis } = require('@upstash/redis'); - - // Only initialize if both packages are available and Redis URL is configured - if (process.env.UPSTASH_REDIS_REST_URL) { - ratelimit = new Ratelimit({ - redis: Redis.fromEnv(), - limiter: Ratelimit.slidingWindow(10, '1 m'), // 10 requests per minute - analytics: true, - }); - } -} catch (error) { - console.warn('Upstash rate limiting not available:', error.message); +// Apple server-to-server messages must be cryptographically verified against Apple's +// current signing keys before changing any linked account or personal data. +// Never trust an unauthenticated JSON body for deletion or verification. +export async function POST() { + return NextResponse.json({ + error: 'Apple notification processing is not configured', + }, { status: 501 }); } - -// Verify Apple webhook signature -const verifyAppleSignature = (payload: string, signature: string): boolean => { - try { - const publicKey = process.env.APPLE_WEBHOOK_PUBLIC_KEY; - if (!publicKey) { - console.error('Apple webhook public key not configured'); - return false; - } - - const verifier = crypto.createVerify('sha256'); - verifier.update(payload); - return verifier.verify(publicKey, signature, 'base64'); - } catch (error) { - console.error('Error verifying Apple webhook signature:', error); - return false; - } -}; - -// Validate webhook payload -const validatePayload = (payload: any): boolean => { - const requiredFields = ['type', 'sub']; - return requiredFields.every(field => payload[field]); -}; - -export async function POST(req: Request) { - try { - // Rate limiting check (only if ratelimit is configured) - if (ratelimit) { - const ip = req.headers.get('x-forwarded-for') || 'anonymous'; - const rateLimitResult = await ratelimit.limit(ip); - - if (!rateLimitResult.success) { - return NextResponse.json( - { error: 'Too many requests' }, - { status: 429 } - ); - } - } - - // Get the raw body for signature verification - const rawBody = await req.text(); - const signature = req.headers.get('x-apple-signature'); - - // Verify signature if in production - if (process.env.NODE_ENV === 'production' && signature) { - if (!verifyAppleSignature(rawBody, signature)) { - return NextResponse.json( - { error: 'Invalid signature' }, - { status: 401 } - ); - } - } - - // Parse and validate payload - const payload = JSON.parse(rawBody); - if (!validatePayload(payload)) { - return NextResponse.json( - { error: 'Invalid payload' }, - { status: 400 } - ); - } - - // Log webhook event in development - if (process.env.NODE_ENV === 'development') { - console.log('Apple webhook payload:', payload); - } - - // Handle different event types - switch (payload.type) { - case 'email-disabled': - case 'consent-revoked': - // User has revoked access or disabled their Apple ID - if (payload.sub) { - // First find the user by email since Apple ID might be in sub - const user = await prisma.user.findFirst({ - where: { - OR: [ - { email: payload.email }, - { appleId: payload.sub } - ] - } - }); - - if (user) { - await prisma.user.update({ - where: { id: user.id }, - data: { - appleId: null, - // Log the event - updatedAt: new Date(), - } - }); - - // Log the event - await prisma.notification.create({ - data: { - type: 'APPLE_AUTH_REVOKED', - userId: user.id, - data: { - event: payload.type, - timestamp: new Date().toISOString() - } - } - }); - } - } - break; - - case 'account-delete': - if (payload.sub) { - const user = await prisma.user.findFirst({ - where: { - OR: [ - { email: payload.email }, - { appleId: payload.sub } - ] - } - }); - - if (user) { - // Create a notification before deleting - await prisma.notification.create({ - data: { - type: 'ACCOUNT_DELETED', - userId: user.id, - data: { - event: 'apple_account_delete', - timestamp: new Date().toISOString() - } - } - }); - - await prisma.user.delete({ - where: { id: user.id } - }); - } - } - break; - - default: - console.log('Unhandled Apple webhook event:', payload.type); - } - - return NextResponse.json({ - received: true, - timestamp: new Date().toISOString() - }); - } catch (error) { - console.error('Error processing Apple webhook:', error); - return NextResponse.json( - { error: 'Internal server error' }, - { status: 500 } - ); - } -} \ No newline at end of file From d5f8f3903afff469bc8256c15fd52df79c49043a Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:34:59 -0400 Subject: [PATCH 033/152] fix: accurate admin dashboard status labels and zero-safe metrics --- src/app/routes/admin/page.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/routes/admin/page.tsx b/src/app/routes/admin/page.tsx index 0d4880a..b7c090f 100644 --- a/src/app/routes/admin/page.tsx +++ b/src/app/routes/admin/page.tsx @@ -187,8 +187,8 @@ export default async function AdminDashboardPage() {
-

Disputed Rentals

-

{rentalStatusCounts[5]} rentals in dispute

+

Payment Failures

+

{rentalStatusCounts[5]} rentals with failed payments

@@ -225,7 +225,7 @@ export default async function AdminDashboardPage() {
- Confirmed + Paid {rentalStatusCounts[1]}
@@ -233,7 +233,7 @@ export default async function AdminDashboardPage() {
- In Progress + Active {rentalStatusCounts[2]}
@@ -257,7 +257,7 @@ export default async function AdminDashboardPage() {
- Disputed + Payment Failed {rentalStatusCounts[5]}
From 036eb8fc52b79e646a70cba424d3996f9e10350b Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:35:09 -0400 Subject: [PATCH 034/152] fix: avoid NaN rental percentages when marketplace has no rentals --- src/app/routes/admin/page.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/routes/admin/page.tsx b/src/app/routes/admin/page.tsx index b7c090f..108ab05 100644 --- a/src/app/routes/admin/page.tsx +++ b/src/app/routes/admin/page.tsx @@ -221,7 +221,7 @@ export default async function AdminDashboardPage() { {rentalStatusCounts[0]}
-
+
@@ -229,7 +229,7 @@ export default async function AdminDashboardPage() { {rentalStatusCounts[1]}
-
+
@@ -237,7 +237,7 @@ export default async function AdminDashboardPage() { {rentalStatusCounts[2]}
-
+
@@ -245,7 +245,7 @@ export default async function AdminDashboardPage() { {rentalStatusCounts[3]}
-
+
@@ -253,7 +253,7 @@ export default async function AdminDashboardPage() { {rentalStatusCounts[4]}
-
+
@@ -261,7 +261,7 @@ export default async function AdminDashboardPage() { {rentalStatusCounts[5]}
-
+
From 825cf607a9359db27ec79968d937a118c3fb0cee Mon Sep 17 00:00:00 2001 From: Baheem Ferrell <110173147+BTheCoderr@users.noreply.github.com> Date: Sat, 10 Oct 2026 10:36:28 -0400 Subject: [PATCH 035/152] fix: replace broken admin rental detail with payment-aware functional actions --- src/app/routes/admin/rentals/[id]/page.tsx | 589 ++---------------- .../admin/refund-security-deposit-button.tsx | 4 +- src/components/admin/rental-status-change.tsx | 138 +--- 3 files changed, 98 insertions(+), 633 deletions(-) diff --git a/src/app/routes/admin/rentals/[id]/page.tsx b/src/app/routes/admin/rentals/[id]/page.tsx index ba400c9..31eca3d 100644 --- a/src/app/routes/admin/rentals/[id]/page.tsx +++ b/src/app/routes/admin/rentals/[id]/page.tsx @@ -1,541 +1,82 @@ -// Add dynamic export to ensure proper server-side rendering export const dynamic = 'force-dynamic'; -import { getCurrentUser } from "@/lib/auth/auth-utils"; -import { db } from "@/lib/db"; -import Link from "next/link"; -import { notFound } from "next/navigation"; -import { DisputeResolutionForm } from "@/components/admin/dispute-resolution-form"; -import { RentalStatusChange } from "@/components/admin/rental-status-change"; -import { RefundSecurityDepositButton } from "@/components/admin/refund-security-deposit-button"; +import Link from 'next/link'; +import { notFound, redirect } from 'next/navigation'; +import { db } from '@/lib/db'; +import { getCurrentUser } from '@/lib/auth/auth-utils'; +import { RentalStatusChange } from '@/components/admin/rental-status-change'; +import { RefundSecurityDepositButton } from '@/components/admin/refund-security-deposit-button'; -// Helper function to format currency -const formatCurrency = (amount: number) => { - return new Intl.NumberFormat('en-US', { - style: 'currency', - currency: 'USD', - }).format(amount); -}; +const usd = (n: number) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(n); +const date = (d: Date) => new Date(d).toLocaleDateString('en-US'); -// Helper function to format dates -const formatDate = (date: Date) => { - return new Date(date).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - }); -}; - -interface AdminRentalDetailPageProps { - params: { - id: string; - }; -} +export default async function AdminRentalDetailPage({ params }: { params: Promise<{ id: string }> }) { + const admin = await getCurrentUser(); + if (!admin?.isAdmin) redirect('/'); -export default async function AdminRentalDetailPage({ params }: AdminRentalDetailPageProps) { - const user = await getCurrentUser(); - - if (!user?.isAdmin) { - throw new Error("Unauthorized"); - } - - // Get rental with related data + const { id } = await params; const rental = await db.rental.findUnique({ - where: { - id: params.id, - }, + where: { id }, include: { - equipment: { - include: { - owner: { - select: { - id: true, - name: true, - email: true, - image: true, - }, - }, - }, - }, - renter: { - select: { - id: true, - name: true, - email: true, - image: true, - }, - }, + equipment: { include: { owner: { select: { id: true, name: true, email: true } } } }, + renter: { select: { id: true, name: true, email: true, idVerified: true } }, payment: true, }, }); - - if (!rental) { - notFound(); - } - - // Calculate rental duration in days - const startDate = new Date(rental.startDate); - const endDate = new Date(rental.endDate); - const durationInMs = endDate.getTime() - startDate.getTime(); - const durationInDays = Math.ceil(durationInMs / (1000 * 60 * 60 * 24)); - - // Fetch any disputes related to this rental - const disputes = await db.dispute.findMany({ - where: { - rentalId: rental.id, - }, - orderBy: { - createdAt: "desc", - }, - include: { - createdBy: { - select: { - id: true, - name: true, - }, - }, - resolvedBy: { - select: { - id: true, - name: true, - }, - }, - }, - }); - + if (!rental) notFound(); + + const paymentStatus = rental.payment?.status ?? 'NOT_STARTED'; + const chargedAmount = rental.totalPrice + (rental.securityDeposit ?? 0); + const canRefundDeposit = rental.status === 'COMPLETED' && + paymentStatus === 'COMPLETED' && (rental.securityDeposit ?? 0) > 0; + return ( -
-
- - - - - Back to Rentals - -
- -
-

Rental Details

-
- +
+ ← Back to rentals +
+
+

Rental details

+

{rental.id}

+ {rental.status}
- -
- {/* Main Content */} -
- {/* Rental Overview */} -
-
-

Rental Overview

-
-
-
-
-

Rental ID

-

{rental.id}

-
-
-

Status

-

- - {rental.status} - -

-
-
-

Start Date

-

{formatDate(rental.startDate)}

-
-
-

End Date

-

{formatDate(rental.endDate)}

-
-
-

Duration

-

{durationInDays} days

-
-
-

Created At

-

{formatDate(rental.createdAt)}

-
-
-
-
- - {/* Equipment Details */} -
-
-

Equipment Details

-
-
-
-
- {/* Equipment image would go here */} -
- No Image -
-
-
-

- - {rental.equipment.title} - -

-

- Category: {rental.equipment.category || 'Uncategorized'} -

-
- - Owner: {rental.equipment.owner.name} - -
-
-
-
-
- - {/* Renter Details */} -
-
-

Renter Details

-
-
-
-
- {/* Renter avatar would go here */} -
- - - -
-
-
-

- - {rental.renter.name} - -

-

{rental.renter.email}

-

- ID Verification: {rental.renter.idVerified ? 'Verified' : 'Not Verified'} -

-
-
-
-
- - {/* Admin Actions */} -
-
-

Admin Actions

-
-
-
-
-

Update Rental Status

-
- - - - - -
-
- -
-

Add Admin Note

-
- -
-
- -
-
-
-
-
-
- - {/* Sidebar */} -
- {/* Payment Details */} -
-
-

Payment Details

-
-
-
-
- Rental Fee - {formatCurrency(rental.totalPrice)} -
- {rental.securityDeposit && ( -
- Security Deposit - {formatCurrency(rental.securityDeposit)} -
- )} -
- Platform Fee - {formatCurrency(rental.totalPrice * 0.1)} -
-
-
- Total - {formatCurrency(rental.totalPrice + (rental.securityDeposit || 0))} -
-
-
-
-
- - {/* Quick Actions */} -
-
-

Quick Actions

-
-
-
- - - -
-
-
- - {/* Rental Timeline */} -
-
-

Rental Timeline

-
-
-
-
-
-

Rental Created

-

{formatDate(rental.createdAt)}

-
- -
-
-

Rental Start

-

{formatDate(rental.startDate)}

-
- -
-
-

Rental End

-

{formatDate(rental.endDate)}

-
-
-
-
-
-
- - {/* Payment Information */} - {rental.payment && ( -
-

Payment Information

-
-
-
- Payment Status: - - {rental.payment.status} - -
-
- Amount: - {formatCurrency(rental.payment.amount)} -
- {rental.payment.rentalAmount && ( -
- Rental Amount: - {formatCurrency(rental.payment.rentalAmount)} -
- )} - {rental.payment.securityDepositAmount && ( -
- Security Deposit: - {formatCurrency(rental.payment.securityDepositAmount)} - {rental.payment.securityDepositReturned ? ( - (Refunded) - ) : ( - - )} -
- )} - {rental.payment.platformFee && ( -
- Platform Fee: - {formatCurrency(rental.payment.platformFee)} -
- )} -
-
-
- Owner Payout Status: - - {rental.payment.ownerPaidOut ? 'Paid Out' : 'Pending'} - -
- {rental.payment.ownerPaidOutAmount && ( -
- Payout Amount: - {formatCurrency(rental.payment.ownerPaidOutAmount)} -
- )} -
- Payment Method: - {rental.payment.paymentMethod || "Stripe"} -
-
- Payment Date: - {new Date(rental.payment.createdAt).toLocaleString()} -
-
-
-
- )} - - {/* Admin Actions */} -
-

Admin Actions

-
- - - {rental.status === "DISPUTED" && ( - +
+
+

Equipment and schedule

+

{rental.equipment.title}

+

Starts: {date(rental.startDate)}

+

Ends: {date(rental.endDate)}

+

Owner: {rental.equipment.owner.name || rental.equipment.owner.email}

+

Renter: {rental.renter.name || rental.renter.email}

+

Renter verification: {rental.renter.idVerified ? 'Verified' : 'Not verified'}

+

Created {date(rental.createdAt)}

+
+
+

Payment

+
Rental price{usd(rental.totalPrice)}
+
Security deposit{usd(rental.securityDeposit ?? 0)}
+
Checkout total{usd(chargedAmount)}
+

Status: {paymentStatus}

+

Stripe intent: {rental.payment?.stripePaymentIntentId || 'None'}

+ {canRefundDeposit && ( + )} -
+
- - {/* Dispute History */} - {disputes.length > 0 && ( -
-

Dispute History

-
- {disputes.map((dispute) => ( -
-
-

- Dispute #{dispute.id.substring(0, 8)} -

- - {dispute.status} - -
-

- Filed by: {dispute.createdBy.name} on {new Date(dispute.createdAt).toLocaleString()} -

-

{dispute.reason}

- - {dispute.resolution && ( -
-

Resolution

-

{dispute.resolution}

- {dispute.resolvedBy && ( -

- Resolved by {dispute.resolvedBy.name} on {new Date(dispute.resolvedAt || "").toLocaleString()} -

- )} -
- )} -
- ))} -
+
+

Admin rental actions

+ +

+ Changes are restricted to valid transitions. Paid cancellations and charge disputes require reviewed refund handling. +

+
+
+

Contact participants

+
+ Message renter + Message owner
- )} -
+ +
); -} \ No newline at end of file +} diff --git a/src/components/admin/refund-security-deposit-button.tsx b/src/components/admin/refund-security-deposit-button.tsx index da82f94..770961f 100644 --- a/src/components/admin/refund-security-deposit-button.tsx +++ b/src/components/admin/refund-security-deposit-button.tsx @@ -34,11 +34,9 @@ export function RefundSecurityDepositButton({ if (!response.ok) { const error = await response.json(); - throw new Error(error.message || "Failed to refund security deposit"); + throw new Error(error.message || error.error || "Failed to refund security deposit"); } - const data = await response.json(); - toast.success("Security deposit refunded successfully"); router.refresh(); } catch (error) { diff --git a/src/components/admin/rental-status-change.tsx b/src/components/admin/rental-status-change.tsx index 185bcfa..76b9123 100644 --- a/src/components/admin/rental-status-change.tsx +++ b/src/components/admin/rental-status-change.tsx @@ -1,121 +1,47 @@ "use client"; -import { useState } from "react"; -import { toast } from "sonner"; -import { useRouter } from "next/navigation"; +import { useState } from 'react'; +import { toast } from 'sonner'; +import { useRouter } from 'next/navigation'; -interface RentalStatusChangeProps { - rentalId: string; - currentStatus: string; -} +type Target = 'ACTIVE' | 'COMPLETED' | 'CANCELLED'; -export function RentalStatusChange({ rentalId, currentStatus }: RentalStatusChangeProps) { - const [status, setStatus] = useState(currentStatus); - const [isLoading, setIsLoading] = useState(false); - const [reason, setReason] = useState(""); +export function RentalStatusChange({ rentalId, currentStatus }: { rentalId: string; currentStatus: string }) { const router = useRouter(); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - // Only proceed if status has actually changed - if (status === currentStatus) { - toast.error("Please select a different status"); - return; - } - - // If changing to DISPUTED, require a reason - if (status === "DISPUTED" && !reason.trim()) { - toast.error("Please provide a reason for the dispute"); - return; - } - - setIsLoading(true); - + const [busy, setBusy] = useState(false); + const options: { label: string; value: Target }[] = + currentStatus === 'PENDING' ? [{ label: 'Cancel unpaid request', value: 'CANCELLED' }] : + currentStatus === 'PAID' ? [{ label: 'Start rental', value: 'ACTIVE' }] : + currentStatus === 'ACTIVE' ? [{ label: 'Mark completed', value: 'COMPLETED' }] : []; + + const submit = async (status: Target) => { + setBusy(true); try { - const response = await fetch(`/api/admin/rentals/${rentalId}/update-status`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - status, - reason: status === "DISPUTED" ? reason : undefined, - }), + const res = await fetch(`/api/admin/rentals/${rentalId}/update-status`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ status }), }); - - if (!response.ok) { - const error = await response.json(); - throw new Error(error.message || "Failed to update rental status"); - } - - toast.success(`Rental status updated to ${status}`); + const payload = await res.json().catch(() => ({})); + if (!res.ok) throw new Error(payload.message || 'Unable to update rental'); + toast.success('Rental status updated'); router.refresh(); } catch (error) { - console.error("Error updating rental status:", error); - toast.error(error instanceof Error ? error.message : "Failed to update rental status"); + toast.error(error instanceof Error ? error.message : 'Unable to update rental'); } finally { - setIsLoading(false); + setBusy(false); } }; - + if (!options.length) return

No status changes available.

; return ( - -
- - -
- - {status === "DISPUTED" && ( -
- -