From d64f6d84c4fac5f2cadbd7e030e2040476c00007 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Sun, 26 Oct 2025 21:29:27 +0100 Subject: [PATCH] feat: implement dual stop system and database tracking - Add PostgreSQL database with Prisma ORM - Trade model: tracks entry/exit, P&L, order signatures, config snapshots - PriceUpdate model: tracks price movements for drawdown analysis - SystemEvent model: logs errors and system events - DailyStats model: aggregated performance metrics - Implement dual stop loss system (enabled by default) - Soft stop (TRIGGER_LIMIT) at -1.5% to avoid wicks - Hard stop (TRIGGER_MARKET) at -2.5% to guarantee exit - Configurable via USE_DUAL_STOPS, SOFT_STOP_PERCENT, HARD_STOP_PERCENT - Backward compatible with single stop modes - Add database service layer (lib/database/trades.ts) - createTrade(): save new trades with all details - updateTradeExit(): close trades with P&L calculations - addPriceUpdate(): track price movements during trade - getTradeStats(): calculate win rate, profit factor, avg win/loss - logSystemEvent(): log errors and system events - Update execute endpoint to use dual stops and save to database - Calculate dual stop prices when enabled - Pass dual stop parameters to placeExitOrders - Save complete trade record to database after execution - Add test trade button to settings page - New /api/trading/test endpoint for executing test trades - Displays detailed results including dual stop prices - Confirmation dialog before execution - Shows entry price, position size, stops, and TX signature - Generate Prisma client in Docker build - Update DATABASE_URL for container networking --- .env | 33 +- Dockerfile | 3 + app/api/trading/execute/route.ts | 61 +- app/api/trading/test/route.ts | 303 ++++ app/settings/page.tsx | 87 +- config/trading.ts | 24 + lib/database/trades.ts | 245 +++ lib/drift/orders.ts | 136 +- package-lock.json | 1543 ++++++++++++++++- package.json | 2 + .../20251026200052_init/migration.sql | 123 ++ prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 131 ++ 13 files changed, 2616 insertions(+), 78 deletions(-) create mode 100644 app/api/trading/test/route.ts create mode 100644 lib/database/trades.ts create mode 100644 prisma/migrations/20251026200052_init/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 prisma/schema.prisma diff --git a/.env b/.env index c6aaf32..5498589 100644 --- a/.env +++ b/.env @@ -72,6 +72,25 @@ LEVERAGE=5 # Example: -1.5% on 10x = -15% account loss STOP_LOSS_PERCENT=-2.0 +# ================================ +# DUAL STOP SYSTEM (Advanced) +# ================================ +# Enable dual stop system to avoid wicks while guaranteeing exit +# When enabled, places TWO stop orders: +# 1. Soft Stop (TRIGGER_LIMIT) - Avoids false breakouts/wicks +# 2. Hard Stop (TRIGGER_MARKET) - Guarantees exit if price keeps falling +USE_DUAL_STOPS=true + +# Soft Stop (Primary, Stop-Limit) +# Triggers first, tries to avoid wicks +SOFT_STOP_PERCENT=-1.5 +SOFT_STOP_BUFFER=0.4 # Buffer between trigger and limit (0.4% = limit at -1.9%) + +# Hard Stop (Backup, Stop-Market) +# Only triggers if soft stop doesn't fill +# Guarantees exit during strong breakdowns +HARD_STOP_PERCENT=-2.5 + # Take Profit 1: Close 50% of position at this profit level # Example: +0.7% on 10x = +7% account gain TAKE_PROFIT_1_PERCENT=0.5 @@ -186,11 +205,15 @@ EMAIL_PASSWORD=your_16_character_app_password # PostgreSQL connection string # Format: postgresql://username:password@host:port/database # -# Local setup: -# 1. Install PostgreSQL: https://www.postgresql.org/download/ -# 2. Create database: createdb trading_bot_v4 -# 3. Update connection string below -DATABASE_URL=postgresql://postgres:password@localhost:5432/trading_bot_v4 +# IMPORTANT: Use different URLs for different environments: +# - Docker container (runtime): trading-bot-postgres (container name) +# - Local development (Prisma CLI): localhost:5432 +# +# The URL below is for Docker runtime. For Prisma migrations from host: +# DATABASE_URL="postgresql://postgres:postgres@localhost:5432/trading_bot_v4" npx prisma migrate dev +# +# PostgreSQL Database (for trade history and analytics) +DATABASE_URL=postgresql://postgres:postgres@trading-bot-postgres:5432/trading_bot_v4 # Cloud PostgreSQL providers: # - Supabase: https://supabase.com (free tier available) diff --git a/Dockerfile b/Dockerfile index a12c450..4154ae4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,6 +35,9 @@ COPY --from=deps /app/node_modules ./node_modules # Copy source code COPY . . +# Generate Prisma client before building +RUN npx prisma generate + # Build Next.js application ENV NEXT_TELEMETRY_DISABLED 1 ENV NODE_ENV production diff --git a/app/api/trading/execute/route.ts b/app/api/trading/execute/route.ts index a281b9a..2144967 100644 --- a/app/api/trading/execute/route.ts +++ b/app/api/trading/execute/route.ts @@ -11,6 +11,7 @@ import { openPosition, placeExitOrders } from '@/lib/drift/orders' import { normalizeTradingViewSymbol } from '@/config/trading' import { getMergedConfig } from '@/config/trading' import { getPositionManager, ActiveTrade } from '@/lib/trading/position-manager' +import { createTrade } from '@/lib/database/trades' export interface ExecuteTradeRequest { symbol: string // TradingView symbol (e.g., 'SOLUSDT') @@ -135,6 +136,26 @@ export async function POST(request: NextRequest): Promise> { + try { + // Parse request body + const body: TestTradeRequest = await request.json().catch(() => ({})) + + const symbol = body.symbol || 'SOLUSDT' + const direction = body.direction || 'long' + + console.log('๐Ÿงช Test trade request:', { symbol, direction }) + + // Normalize symbol + const driftSymbol = normalizeTradingViewSymbol(symbol) + console.log(`๐Ÿ“Š Normalized symbol: ${symbol} โ†’ ${driftSymbol}`) + + // Get trading configuration + const config = getMergedConfig() + + // Initialize Drift service if not already initialized + const driftService = await initializeDriftService() + + // Check account health before trading + const health = await driftService.getAccountHealth() + console.log('๐Ÿ’Š Account health:', health) + + if (health.freeCollateral <= 0) { + return NextResponse.json( + { + success: false, + error: 'Insufficient collateral', + message: `Free collateral: $${health.freeCollateral.toFixed(2)}`, + }, + { status: 400 } + ) + } + + // Calculate position size with leverage + const positionSizeUSD = config.positionSize * config.leverage + + console.log(`๐Ÿ’ฐ Opening ${direction} position:`) + console.log(` Symbol: ${driftSymbol}`) + console.log(` Base size: $${config.positionSize}`) + console.log(` Leverage: ${config.leverage}x`) + console.log(` Total position: $${positionSizeUSD}`) + + // Open position + const openResult = await openPosition({ + symbol: driftSymbol, + direction: direction, + sizeUSD: positionSizeUSD, + slippageTolerance: config.slippageTolerance, + }) + + if (!openResult.success) { + return NextResponse.json( + { + success: false, + error: 'Position open failed', + message: openResult.error, + }, + { status: 500 } + ) + } + + // Calculate stop loss and take profit prices + const entryPrice = openResult.fillPrice! + + const stopLossPrice = calculatePrice( + entryPrice, + config.stopLossPercent, + direction + ) + + // Calculate dual stop prices if enabled + let softStopPrice: number | undefined + let hardStopPrice: number | undefined + + if (config.useDualStops) { + softStopPrice = calculatePrice( + entryPrice, + config.softStopPercent, + direction + ) + hardStopPrice = calculatePrice( + entryPrice, + config.hardStopPercent, + direction + ) + console.log('๐Ÿ›ก๏ธ๐Ÿ›ก๏ธ Dual stop system enabled:') + console.log(` Soft stop: $${softStopPrice.toFixed(4)} (${config.softStopPercent}%)`) + console.log(` Hard stop: $${hardStopPrice.toFixed(4)} (${config.hardStopPercent}%)`) + } + + const tp1Price = calculatePrice( + entryPrice, + config.takeProfit1Percent, + direction + ) + + const tp2Price = calculatePrice( + entryPrice, + config.takeProfit2Percent, + direction + ) + + console.log('๐Ÿ“Š Trade targets:') + console.log(` Entry: $${entryPrice.toFixed(4)}`) + console.log(` SL: $${stopLossPrice.toFixed(4)} (${config.stopLossPercent}%)`) + console.log(` TP1: $${tp1Price.toFixed(4)} (${config.takeProfit1Percent}%)`) + console.log(` TP2: $${tp2Price.toFixed(4)} (${config.takeProfit2Percent}%)`) + + // Calculate emergency stop + const emergencyStopPrice = calculatePrice( + entryPrice, + config.emergencyStopPercent, + direction + ) + + // Create active trade object + const activeTrade: ActiveTrade = { + id: `test-trade-${Date.now()}`, + positionId: openResult.transactionSignature!, + symbol: driftSymbol, + direction: direction, + entryPrice, + entryTime: Date.now(), + positionSize: positionSizeUSD, + leverage: config.leverage, + stopLossPrice, + tp1Price, + tp2Price, + emergencyStopPrice, + currentSize: positionSizeUSD, + tp1Hit: false, + slMovedToBreakeven: false, + slMovedToProfit: false, + realizedPnL: 0, + unrealizedPnL: 0, + peakPnL: 0, + priceCheckCount: 0, + lastPrice: entryPrice, + lastUpdateTime: Date.now(), + } + + // Add to position manager for monitoring + const positionManager = getPositionManager() + await positionManager.addTrade(activeTrade) + + console.log('โœ… Trade added to position manager for monitoring') + + // Create response object + const response: TestTradeResponse = { + success: true, + positionId: openResult.transactionSignature, + symbol: driftSymbol, + direction: direction, + entryPrice: entryPrice, + positionSize: positionSizeUSD, + stopLoss: stopLossPrice, + takeProfit1: tp1Price, + takeProfit2: tp2Price, + softStopPrice: softStopPrice, + hardStopPrice: hardStopPrice, + useDualStops: config.useDualStops, + timestamp: new Date().toISOString(), + } + + // Place on-chain TP/SL orders so they appear in Drift UI + let exitOrderSignatures: string[] = [] + try { + const exitRes = await placeExitOrders({ + symbol: driftSymbol, + positionSizeUSD: positionSizeUSD, + tp1Price, + tp2Price, + stopLossPrice, + tp1SizePercent: config.takeProfit1SizePercent || 50, + tp2SizePercent: config.takeProfit2SizePercent || 100, + direction: direction, + // Dual stop parameters + useDualStops: config.useDualStops, + softStopPrice: softStopPrice, + softStopBuffer: config.softStopBuffer, + hardStopPrice: hardStopPrice, + }) + + if (!exitRes.success) { + console.error('โŒ Failed to place on-chain exit orders:', exitRes.error) + } else { + console.log('๐Ÿ“จ Exit orders placed on-chain:', exitRes.signatures) + exitOrderSignatures = exitRes.signatures || [] + } + + // Attach signatures to response when available + if (exitRes.signatures && exitRes.signatures.length > 0) { + ;(response as any).exitOrderSignatures = exitRes.signatures + } + } catch (err) { + console.error('โŒ Unexpected error placing exit orders:', err) + } + + // Save trade to database + try { + await createTrade({ + positionId: openResult.transactionSignature!, + symbol: driftSymbol, + direction: direction, + entryPrice, + positionSizeUSD: positionSizeUSD, + leverage: config.leverage, + stopLossPrice, + takeProfit1Price: tp1Price, + takeProfit2Price: tp2Price, + tp1SizePercent: config.takeProfit1SizePercent || 50, + tp2SizePercent: config.takeProfit2SizePercent || 100, + configSnapshot: config, + entryOrderTx: openResult.transactionSignature!, + tp1OrderTx: exitOrderSignatures[0], + tp2OrderTx: exitOrderSignatures[1], + slOrderTx: config.useDualStops ? undefined : exitOrderSignatures[2], + softStopOrderTx: config.useDualStops ? exitOrderSignatures[2] : undefined, + hardStopOrderTx: config.useDualStops ? exitOrderSignatures[3] : undefined, + softStopPrice, + hardStopPrice, + signalStrength: 'test', + timeframe: 'manual', + }) + + console.log('๐Ÿ’พ Trade saved to database') + } catch (dbError) { + console.error('โŒ Failed to save trade to database:', dbError) + // Don't fail the trade if database save fails + } + + console.log('โœ… Test trade executed successfully!') + + return NextResponse.json(response) + + } catch (error) { + console.error('โŒ Test trade execution error:', error) + + return NextResponse.json( + { + success: false, + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error', + }, + { status: 500 } + ) + } +} + +/** + * Helper function to calculate price based on percentage + */ +function calculatePrice( + entryPrice: number, + percent: number, + direction: 'long' | 'short' +): number { + if (direction === 'long') { + return entryPrice * (1 + percent / 100) + } else { + return entryPrice * (1 - percent / 100) + } +} diff --git a/app/settings/page.tsx b/app/settings/page.tsx index 0ce2b70..003a7ee 100644 --- a/app/settings/page.tsx +++ b/app/settings/page.tsx @@ -32,6 +32,7 @@ export default function SettingsPage() { const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [restarting, setRestarting] = useState(false) + const [testing, setTesting] = useState(false) const [message, setMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null) useEffect(() => { @@ -90,6 +91,44 @@ export default function SettingsPage() { setRestarting(false) } + const testTrade = async () => { + if (!confirm('โš ๏ธ This will execute a REAL trade with current settings. Continue?')) { + return + } + + setTesting(true) + setMessage(null) + try { + const response = await fetch('/api/trading/test', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + symbol: 'SOLUSDT', + direction: 'long', + }), + }) + + const data = await response.json() + + if (data.success) { + const dualStopsMsg = data.useDualStops + ? `Dual stops: Soft $${data.softStopPrice?.toFixed(4)} | Hard $${data.hardStopPrice?.toFixed(4)}` + : `SL: $${data.stopLoss?.toFixed(4)}` + setMessage({ + type: 'success', + text: `โœ… Test trade executed! Size: $${data.positionSize?.toFixed(2)} | Entry: $${data.entryPrice?.toFixed(4)} | ${dualStopsMsg} | TX: ${data.positionId?.substring(0, 8)}...` + }) + } else { + setMessage({ type: 'error', text: `Failed: ${data.error || data.message}` }) + } + } catch (error) { + setMessage({ type: 'error', text: `Test trade failed: ${error instanceof Error ? error.message : 'Unknown error'}` }) + } + setTesting(false) + } + const updateSetting = (key: keyof TradingSettings, value: any) => { if (!settings) return setSettings({ ...settings, [key]: value }) @@ -342,26 +381,38 @@ export default function SettingsPage() { {/* Action Buttons */} -
+
+ {/* Primary Actions */} +
+ + + +
+ + {/* Test Trade Button */} - -
diff --git a/config/trading.ts b/config/trading.ts index daa8da2..e390209 100644 --- a/config/trading.ts +++ b/config/trading.ts @@ -15,6 +15,12 @@ export interface TradingConfig { takeProfit2Percent: number // Positive number (e.g., 1.5) emergencyStopPercent: number // Hard stop (e.g., -2.0) + // Dual Stop System (Advanced) + useDualStops: boolean // Enable dual stop system + softStopPercent: number // Soft stop trigger (e.g., -1.5) + softStopBuffer: number // Buffer for soft stop limit (e.g., 0.4) + hardStopPercent: number // Hard stop trigger (e.g., -2.5) + // Dynamic adjustments breakEvenTriggerPercent: number // When to move SL to breakeven profitLockTriggerPercent: number // When to lock in profit @@ -57,6 +63,12 @@ export const DEFAULT_TRADING_CONFIG: TradingConfig = { takeProfit2Percent: 1.5, // +1.5% price = +15% account gain (closes 50%) emergencyStopPercent: -2.0, // -2% hard stop = -20% account loss + // Dual Stop System + useDualStops: false, // Disabled by default + softStopPercent: -1.5, // Soft stop (TRIGGER_LIMIT) + softStopBuffer: 0.4, // 0.4% buffer (limit at -1.9%) + hardStopPercent: -2.5, // Hard stop (TRIGGER_MARKET) + // Dynamic adjustments breakEvenTriggerPercent: 0.4, // Move SL to breakeven at +0.4% profitLockTriggerPercent: 1.0, // Lock profit at +1.0% @@ -164,6 +176,18 @@ export function getConfigFromEnv(): Partial { stopLossPercent: process.env.STOP_LOSS_PERCENT ? parseFloat(process.env.STOP_LOSS_PERCENT) : undefined, + useDualStops: process.env.USE_DUAL_STOPS + ? process.env.USE_DUAL_STOPS === 'true' + : undefined, + softStopPercent: process.env.SOFT_STOP_PERCENT + ? parseFloat(process.env.SOFT_STOP_PERCENT) + : undefined, + softStopBuffer: process.env.SOFT_STOP_BUFFER + ? parseFloat(process.env.SOFT_STOP_BUFFER) + : undefined, + hardStopPercent: process.env.HARD_STOP_PERCENT + ? parseFloat(process.env.HARD_STOP_PERCENT) + : undefined, takeProfit1Percent: process.env.TAKE_PROFIT_1_PERCENT ? parseFloat(process.env.TAKE_PROFIT_1_PERCENT) : undefined, diff --git a/lib/database/trades.ts b/lib/database/trades.ts new file mode 100644 index 0000000..e7f9fc5 --- /dev/null +++ b/lib/database/trades.ts @@ -0,0 +1,245 @@ +/** + * Database Service for Trade Tracking and Analytics + */ + +import { PrismaClient } from '@prisma/client' + +// Singleton Prisma client +let prisma: PrismaClient | null = null + +export function getPrismaClient(): PrismaClient { + if (!prisma) { + prisma = new PrismaClient({ + log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'], + }) + console.log('โœ… Prisma client initialized') + } + return prisma +} + +export interface CreateTradeParams { + positionId: string + symbol: string + direction: 'long' | 'short' + entryPrice: number + entrySlippage?: number + positionSizeUSD: number + leverage: number + stopLossPrice: number + softStopPrice?: number + hardStopPrice?: number + takeProfit1Price: number + takeProfit2Price: number + tp1SizePercent: number + tp2SizePercent: number + entryOrderTx: string + tp1OrderTx?: string + tp2OrderTx?: string + slOrderTx?: string + softStopOrderTx?: string + hardStopOrderTx?: string + configSnapshot: any + signalSource?: string + signalStrength?: string + timeframe?: string +} + +export interface UpdateTradeExitParams { + positionId: string + exitPrice: number + exitReason: 'TP1' | 'TP2' | 'SL' | 'SOFT_SL' | 'HARD_SL' | 'manual' | 'emergency' + realizedPnL: number + exitOrderTx: string + holdTimeSeconds: number + maxDrawdown?: number + maxGain?: number +} + +/** + * Create a new trade record + */ +export async function createTrade(params: CreateTradeParams) { + const prisma = getPrismaClient() + + try { + const trade = await prisma.trade.create({ + data: { + positionId: params.positionId, + symbol: params.symbol, + direction: params.direction, + entryPrice: params.entryPrice, + entryTime: new Date(), + entrySlippage: params.entrySlippage, + positionSizeUSD: params.positionSizeUSD, + leverage: params.leverage, + stopLossPrice: params.stopLossPrice, + softStopPrice: params.softStopPrice, + hardStopPrice: params.hardStopPrice, + takeProfit1Price: params.takeProfit1Price, + takeProfit2Price: params.takeProfit2Price, + tp1SizePercent: params.tp1SizePercent, + tp2SizePercent: params.tp2SizePercent, + entryOrderTx: params.entryOrderTx, + tp1OrderTx: params.tp1OrderTx, + tp2OrderTx: params.tp2OrderTx, + slOrderTx: params.slOrderTx, + softStopOrderTx: params.softStopOrderTx, + hardStopOrderTx: params.hardStopOrderTx, + configSnapshot: params.configSnapshot, + signalSource: params.signalSource, + signalStrength: params.signalStrength, + timeframe: params.timeframe, + status: 'open', + }, + }) + + console.log(`๐Ÿ“Š Trade record created: ${trade.id}`) + return trade + } catch (error) { + console.error('โŒ Failed to create trade record:', error) + throw error + } +} + +/** + * Update trade when position exits + */ +export async function updateTradeExit(params: UpdateTradeExitParams) { + const prisma = getPrismaClient() + + try { + // First fetch the trade to get positionSizeUSD + const existingTrade = await prisma.trade.findUnique({ + where: { positionId: params.positionId }, + select: { positionSizeUSD: true }, + }) + + if (!existingTrade) { + throw new Error(`Trade not found: ${params.positionId}`) + } + + const trade = await prisma.trade.update({ + where: { positionId: params.positionId }, + data: { + exitPrice: params.exitPrice, + exitTime: new Date(), + exitReason: params.exitReason, + realizedPnL: params.realizedPnL, + realizedPnLPercent: (params.realizedPnL / existingTrade.positionSizeUSD) * 100, + exitOrderTx: params.exitOrderTx, + holdTimeSeconds: params.holdTimeSeconds, + maxDrawdown: params.maxDrawdown, + maxGain: params.maxGain, + status: 'closed', + }, + }) + + console.log(`๐Ÿ“Š Trade closed: ${trade.id} | P&L: $${params.realizedPnL.toFixed(2)}`) + return trade + } catch (error) { + console.error('โŒ Failed to update trade exit:', error) + throw error + } +} + +/** + * Add price update for a trade (for tracking max gain/drawdown) + */ +export async function addPriceUpdate( + tradeId: string, + price: number, + pnl: number, + pnlPercent: number +) { + const prisma = getPrismaClient() + + try { + await prisma.priceUpdate.create({ + data: { + tradeId, + price, + pnl, + pnlPercent, + }, + }) + } catch (error) { + console.error('โŒ Failed to add price update:', error) + // Don't throw - price updates are non-critical + } +} + +/** + * Log system event + */ +export async function logSystemEvent( + eventType: string, + message: string, + details?: any +) { + const prisma = getPrismaClient() + + try { + await prisma.systemEvent.create({ + data: { + eventType, + message, + details: details ? JSON.parse(JSON.stringify(details)) : null, + }, + }) + } catch (error) { + console.error('โŒ Failed to log system event:', error) + } +} + +/** + * Get trade statistics + */ +export async function getTradeStats(days: number = 30) { + const prisma = getPrismaClient() + + const since = new Date() + since.setDate(since.getDate() - days) + + const trades = await prisma.trade.findMany({ + where: { + createdAt: { gte: since }, + status: 'closed', + }, + }) + + const winning = trades.filter((t) => (t.realizedPnL ?? 0) > 0) + const losing = trades.filter((t) => (t.realizedPnL ?? 0) < 0) + + const totalPnL = trades.reduce((sum, t) => sum + (t.realizedPnL ?? 0), 0) + const winRate = trades.length > 0 ? (winning.length / trades.length) * 100 : 0 + + const avgWin = winning.length > 0 + ? winning.reduce((sum, t) => sum + (t.realizedPnL ?? 0), 0) / winning.length + : 0 + + const avgLoss = losing.length > 0 + ? losing.reduce((sum, t) => sum + (t.realizedPnL ?? 0), 0) / losing.length + : 0 + + return { + totalTrades: trades.length, + winningTrades: winning.length, + losingTrades: losing.length, + winRate: winRate.toFixed(2), + totalPnL: totalPnL.toFixed(2), + avgWin: avgWin.toFixed(2), + avgLoss: avgLoss.toFixed(2), + profitFactor: avgLoss !== 0 ? (avgWin / Math.abs(avgLoss)).toFixed(2) : 'N/A', + } +} + +/** + * Disconnect Prisma client (for graceful shutdown) + */ +export async function disconnectPrisma() { + if (prisma) { + await prisma.$disconnect() + prisma = null + console.log('โœ… Prisma client disconnected') + } +} diff --git a/lib/drift/orders.ts b/lib/drift/orders.ts index 35930e2..730e8a6 100644 --- a/lib/drift/orders.ts +++ b/lib/drift/orders.ts @@ -63,6 +63,11 @@ export interface PlaceExitOrdersOptions { direction: 'long' | 'short' useStopLimit?: boolean // Optional: use TRIGGER_LIMIT instead of TRIGGER_MARKET for SL stopLimitBuffer?: number // Optional: buffer percentage for stop-limit (default 0.5%) + // Dual Stop System + useDualStops?: boolean // Enable dual stop system + softStopPrice?: number // Soft stop trigger price (TRIGGER_LIMIT) + softStopBuffer?: number // Buffer for soft stop limit price + hardStopPrice?: number // Hard stop trigger price (TRIGGER_MARKET) } /** @@ -273,64 +278,127 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise< } } - // Place Stop-Loss order - // Default: TRIGGER_MARKET (guaranteed execution, RECOMMENDED for most traders) - // Optional: TRIGGER_LIMIT with buffer (only for very liquid markets to avoid extreme wicks) + // Place Stop-Loss order(s) + // Supports three modes: + // 1. Dual Stop System (soft stop-limit + hard stop-market) + // 2. Single TRIGGER_LIMIT (for liquid markets) + // 3. Single TRIGGER_MARKET (default, guaranteed execution) + const slUSD = options.positionSizeUSD const slBaseAmount = usdToBase(slUSD, options.stopLossPrice) if (slBaseAmount >= Math.floor(marketConfig.minOrderSize * 1e9)) { - const useStopLimit = options.useStopLimit ?? false - const stopLimitBuffer = options.stopLimitBuffer ?? 0.5 // default 0.5% buffer + const useDualStops = options.useDualStops ?? false - if (useStopLimit) { - // TRIGGER_LIMIT: Protects against extreme wicks but may not fill during fast moves - const limitPriceMultiplier = options.direction === 'long' - ? (1 - stopLimitBuffer / 100) // Long: limit below trigger - : (1 + stopLimitBuffer / 100) // Short: limit above trigger + if (useDualStops && options.softStopPrice && options.hardStopPrice) { + // ============== DUAL STOP SYSTEM ============== + console.log('๐Ÿ›ก๏ธ๐Ÿ›ก๏ธ Placing DUAL STOP SYSTEM...') - const orderParams: any = { + // 1. Soft Stop (TRIGGER_LIMIT) - Avoids wicks + const softStopBuffer = options.softStopBuffer ?? 0.4 + const softStopMultiplier = options.direction === 'long' + ? (1 - softStopBuffer / 100) + : (1 + softStopBuffer / 100) + + const softStopParams: any = { orderType: OrderType.TRIGGER_LIMIT, marketIndex: marketConfig.driftMarketIndex, direction: orderDirection, baseAssetAmount: new BN(slBaseAmount), - triggerPrice: new BN(Math.floor(options.stopLossPrice * 1e6)), - price: new BN(Math.floor(options.stopLossPrice * limitPriceMultiplier * 1e6)), - triggerCondition: options.direction === 'long' - ? OrderTriggerCondition.BELOW + triggerPrice: new BN(Math.floor(options.softStopPrice * 1e6)), + price: new BN(Math.floor(options.softStopPrice * softStopMultiplier * 1e6)), + triggerCondition: options.direction === 'long' + ? OrderTriggerCondition.BELOW : OrderTriggerCondition.ABOVE, reduceOnly: true, } - console.log(`๐Ÿ›ก๏ธ Placing SL as TRIGGER_LIMIT (${stopLimitBuffer}% buffer)...`) - console.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`) - console.log(` Limit: $${(options.stopLossPrice * limitPriceMultiplier).toFixed(4)}`) - console.log(` โš ๏ธ May not fill during fast moves - use for liquid markets only!`) + console.log(` 1๏ธโƒฃ Soft Stop (TRIGGER_LIMIT):`) + console.log(` Trigger: $${options.softStopPrice.toFixed(4)}`) + console.log(` Limit: $${(options.softStopPrice * softStopMultiplier).toFixed(4)}`) + console.log(` Purpose: Avoid false breakouts/wicks`) - const sig = await (driftClient as any).placePerpOrder(orderParams) - console.log('โœ… SL trigger-limit order placed:', sig) - signatures.push(sig) - } else { - // TRIGGER_MARKET: Guaranteed execution (RECOMMENDED) - const orderParams: any = { + const softStopSig = await (driftClient as any).placePerpOrder(softStopParams) + console.log(` โœ… Soft stop placed: ${softStopSig}`) + signatures.push(softStopSig) + + // 2. Hard Stop (TRIGGER_MARKET) - Guarantees exit + const hardStopParams: any = { orderType: OrderType.TRIGGER_MARKET, marketIndex: marketConfig.driftMarketIndex, direction: orderDirection, baseAssetAmount: new BN(slBaseAmount), - triggerPrice: new BN(Math.floor(options.stopLossPrice * 1e6)), - triggerCondition: options.direction === 'long' - ? OrderTriggerCondition.BELOW + triggerPrice: new BN(Math.floor(options.hardStopPrice * 1e6)), + triggerCondition: options.direction === 'long' + ? OrderTriggerCondition.BELOW : OrderTriggerCondition.ABOVE, reduceOnly: true, } - console.log(`๐Ÿ›ก๏ธ Placing SL as TRIGGER_MARKET (guaranteed execution - RECOMMENDED)...`) - console.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`) - console.log(` โœ… Will execute at market price when triggered (may slip but WILL fill)`) + console.log(` 2๏ธโƒฃ Hard Stop (TRIGGER_MARKET):`) + console.log(` Trigger: $${options.hardStopPrice.toFixed(4)}`) + console.log(` Purpose: Guaranteed exit if soft stop doesn't fill`) - const sig = await (driftClient as any).placePerpOrder(orderParams) - console.log('โœ… SL trigger-market order placed:', sig) - signatures.push(sig) + const hardStopSig = await (driftClient as any).placePerpOrder(hardStopParams) + console.log(` โœ… Hard stop placed: ${hardStopSig}`) + signatures.push(hardStopSig) + + console.log(`๐ŸŽฏ Dual stop system active: Soft @ $${options.softStopPrice.toFixed(2)} | Hard @ $${options.hardStopPrice.toFixed(2)}`) + + } else { + // ============== SINGLE STOP SYSTEM ============== + const useStopLimit = options.useStopLimit ?? false + const stopLimitBuffer = options.stopLimitBuffer ?? 0.5 + + if (useStopLimit) { + // TRIGGER_LIMIT: For liquid markets + const limitPriceMultiplier = options.direction === 'long' + ? (1 - stopLimitBuffer / 100) + : (1 + stopLimitBuffer / 100) + + const orderParams: any = { + orderType: OrderType.TRIGGER_LIMIT, + marketIndex: marketConfig.driftMarketIndex, + direction: orderDirection, + baseAssetAmount: new BN(slBaseAmount), + triggerPrice: new BN(Math.floor(options.stopLossPrice * 1e6)), + price: new BN(Math.floor(options.stopLossPrice * limitPriceMultiplier * 1e6)), + triggerCondition: options.direction === 'long' + ? OrderTriggerCondition.BELOW + : OrderTriggerCondition.ABOVE, + reduceOnly: true, + } + + console.log(`๐Ÿ›ก๏ธ Placing SL as TRIGGER_LIMIT (${stopLimitBuffer}% buffer)...`) + console.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`) + console.log(` Limit: $${(options.stopLossPrice * limitPriceMultiplier).toFixed(4)}`) + console.log(` โš ๏ธ May not fill during fast moves - use for liquid markets only!`) + + const sig = await (driftClient as any).placePerpOrder(orderParams) + console.log('โœ… SL trigger-limit order placed:', sig) + signatures.push(sig) + } else { + // TRIGGER_MARKET: Default, guaranteed execution + const orderParams: any = { + orderType: OrderType.TRIGGER_MARKET, + marketIndex: marketConfig.driftMarketIndex, + direction: orderDirection, + baseAssetAmount: new BN(slBaseAmount), + triggerPrice: new BN(Math.floor(options.stopLossPrice * 1e6)), + triggerCondition: options.direction === 'long' + ? OrderTriggerCondition.BELOW + : OrderTriggerCondition.ABOVE, + reduceOnly: true, + } + + console.log(`๐Ÿ›ก๏ธ Placing SL as TRIGGER_MARKET (guaranteed execution - RECOMMENDED)...`) + console.log(` Trigger: ${options.direction === 'long' ? 'BELOW' : 'ABOVE'} $${options.stopLossPrice.toFixed(4)}`) + console.log(` โœ… Will execute at market price when triggered (may slip but WILL fill)`) + + const sig = await (driftClient as any).placePerpOrder(orderParams) + console.log('โœ… SL trigger-market order placed:', sig) + signatures.push(sig) + } } } else { console.log('โš ๏ธ SL size below market min, skipping on-chain SL') diff --git a/package-lock.json b/package-lock.json index c46f67c..66954a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,28 +9,42 @@ "version": "4.0.0", "dependencies": { "@drift-labs/sdk": "^2.75.0", + "@prisma/client": "^6.18.0", "@pythnetwork/hermes-client": "^1.0.0", "@pythnetwork/price-service-client": "^1.3.0", "@solana/web3.js": "^1.91.1", + "autoprefixer": "^10.4.21", "bs58": "^5.0.0", "next": "^15.0.0", + "postcss": "^8.5.6", + "prisma": "^6.18.0", "react": "^18.3.0", - "react-dom": "^18.3.0" + "react-dom": "^18.3.0", + "tailwindcss": "^3.4.1" }, "devDependencies": { "@types/bn.js": "^5.2.0", "@types/node": "^20.11.0", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", - "autoprefixer": "^10.4.21", - "postcss": "^8.5.6", - "tailwindcss": "^4.1.16", "typescript": "^5.3.0" }, "engines": { "node": ">=20.0.0" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@babel/runtime": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", @@ -948,6 +962,102 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@isaacs/ttlcache": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", @@ -957,6 +1067,41 @@ "node": ">=12" } }, + "node_modules/@jridgewell/gen-mapping": { + "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/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "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", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@js-sdsl/ordered-map": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", @@ -1208,6 +1353,41 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@openbook-dex/openbook-v2": { "version": "0.2.10", "resolved": "https://registry.npmjs.org/@openbook-dex/openbook-v2/-/openbook-v2-0.2.10.tgz", @@ -1279,6 +1459,95 @@ "base-x": "^3.0.2" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@prisma/client": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.18.0.tgz", + "integrity": "sha512-jnL2I9gDnPnw4A+4h5SuNn8Gc+1mL1Z79U/3I9eE2gbxJG1oSA+62ByPW4xkeDgwE0fqMzzpAZ7IHxYnLZ4iQA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.18.0.tgz", + "integrity": "sha512-rgFzspCpwsE+q3OF/xkp0fI2SJ3PfNe9LLMmuSVbAZ4nN66WfBiKqJKo/hLz3ysxiPQZf8h1SMf2ilqPMeWATQ==", + "license": "Apache-2.0", + "dependencies": { + "c12": "3.1.0", + "deepmerge-ts": "7.1.5", + "effect": "3.18.4", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.18.0.tgz", + "integrity": "sha512-PMVPMmxPj0ps1VY75DIrT430MoOyQx9hmm174k6cmLZpcI95rAPXOQ+pp8ANQkJtNyLVDxnxVJ0QLbrm/ViBcg==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.18.0.tgz", + "integrity": "sha512-i5RzjGF/ex6AFgqEe2o1IW8iIxJGYVQJVRau13kHPYEL1Ck8Zvwuzamqed/1iIljs5C7L+Opiz5TzSsUebkriA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.18.0", + "@prisma/engines-version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f", + "@prisma/fetch-engine": "6.18.0", + "@prisma/get-platform": "6.18.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f.tgz", + "integrity": "sha512-T7Af4QsJQnSgWN1zBbX+Cha5t4qjHRxoeoWpK4JugJzG/ipmmDMY5S+O0N1ET6sCBNVkf6lz+Y+ZNO9+wFU8pQ==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.18.0.tgz", + "integrity": "sha512-TdaBvTtBwP3IoqVYoGIYpD4mWlk0pJpjTJjir/xLeNWlwog7Sl3bD2J0jJ8+5+q/6RBg+acb9drsv5W6lqae7A==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.18.0", + "@prisma/engines-version": "6.18.0-8.34b5a692b7bd79939a9a2c3ef97d816e749cda2f", + "@prisma/get-platform": "6.18.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.18.0.tgz", + "integrity": "sha512-uXNJCJGhxTCXo2B25Ta91Rk1/Nmlqg9p7G9GKh8TPhxvAyXCvMNQoogj4JLEUy+3ku8g59cpyQIKFhqY2xO2bg==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "6.18.0" + } + }, "node_modules/@project-serum/anchor": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.11.1.tgz", @@ -3834,6 +4103,12 @@ "node": ">=14.0.0" } }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -4070,6 +4345,31 @@ "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", "license": "MIT" }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4099,7 +4399,6 @@ "version": "10.4.21", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4171,6 +4470,12 @@ "axios": "0.x || 1.x" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, "node_modules/base-x": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.1.tgz", @@ -4201,7 +4506,6 @@ "version": "2.8.20", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz", "integrity": "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -4242,6 +4546,18 @@ "node": "*" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -4286,11 +4602,31 @@ "base-x": "^3.0.2" } }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.27.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4376,6 +4712,34 @@ "node": ">=6.14.2" } }, + "node_modules/c12": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz", + "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^16.6.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.4.2", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -4435,6 +4799,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001751", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", @@ -4467,6 +4840,30 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -4535,6 +4932,21 @@ "node": ">=18" } }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/cross-fetch": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", @@ -4544,6 +4956,20 @@ "node-fetch": "^2.7.0" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/crypto-hash": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz", @@ -4556,6 +4982,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -4586,6 +5024,15 @@ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "license": "MIT" }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -4620,6 +5067,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, "node_modules/delay": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", @@ -4641,6 +5094,12 @@ "node": ">=0.4.0" } }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -4651,6 +5110,18 @@ "node": ">=8" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", @@ -4687,11 +5158,26 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/effect": { + "version": "3.18.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz", + "integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.240", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.240.tgz", "integrity": "sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==", - "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -4700,6 +5186,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -4796,6 +5291,12 @@ "node": ">=18.0.0" } }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "license": "MIT" + }, "node_modules/eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -4804,6 +5305,56 @@ "node": "> 0.1.90" } }, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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": ">=8.6.0" + } + }, + "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/fast-stable-stringify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", @@ -4817,12 +5368,33 @@ "license": "CC0-1.0", "peer": true }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "license": "MIT" }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/find/-/find-0.3.0.tgz", @@ -4897,6 +5469,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -4917,7 +5505,6 @@ "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -4927,6 +5514,20 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -4991,6 +5592,23 @@ "node": ">= 0.4" } }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, "node_modules/gill": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/gill/-/gill-0.10.3.tgz", @@ -5145,6 +5763,38 @@ "node": ">=20" } }, + "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==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -5375,6 +6025,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -5387,6 +6049,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5415,6 +6101,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-nan": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", @@ -5431,6 +6129,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -5476,6 +6183,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, "node_modules/isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", @@ -5485,6 +6198,21 @@ "ws": "*" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jayson": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", @@ -5553,6 +6281,15 @@ } } }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/jito-ts": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/jito-ts/-/jito-ts-3.0.1.tgz", @@ -5655,6 +6392,24 @@ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "license": "ISC" }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -5701,6 +6456,12 @@ "tslib": "^2.0.3" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5710,6 +6471,28 @@ "node": ">= 0.4" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -5731,12 +6514,47 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", @@ -5889,6 +6707,12 @@ } } }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, "node_modules/node-gyp-build": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", @@ -5905,19 +6729,63 @@ "version": "2.0.26", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", - "dev": true, "license": "MIT" }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-range": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/nypm": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz", + "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-is": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", @@ -5963,18 +6831,114 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", "license": "(MIT AND Zlib)" }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -5988,7 +6952,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -6013,18 +6976,138 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, "license": "MIT" }, "node_modules/postcss/node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -6054,6 +7137,31 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prisma": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.18.0.tgz", + "integrity": "sha512-bXWy3vTk8mnRmT+SLyZBQoC2vtV9Z8u7OHvEu+aULYxwiop/CPiFZ+F56KsNRNf35jw+8wcu8pmLsjxpBxAO9g==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/config": "6.18.0", + "@prisma/engines": "6.18.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/protobufjs": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", @@ -6084,6 +7192,52 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -6109,6 +7263,28 @@ "react": "^18.3.1" } }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6118,6 +7294,36 @@ "node": ">=0.10.0" } }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rpc-websockets": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.5.1.tgz", @@ -6138,6 +7344,29 @@ "utf-8-validate": "^5.0.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6256,6 +7485,39 @@ "@img/sharp-win32-x64": "0.34.4" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -6443,6 +7705,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6455,6 +7732,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -6478,6 +7768,37 @@ } } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/superstruct": { "version": "0.15.5", "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", @@ -6496,12 +7817,111 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tailwindcss": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz", - "integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==", - "dev": true, - "license": "MIT" + "version": "3.4.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", + "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "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", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/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/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } }, "node_modules/text-encoding-utf-8": { "version": "1.0.2", @@ -6514,6 +7934,45 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "license": "MIT" }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toml": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", @@ -6532,6 +7991,12 @@ "integrity": "sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg==", "license": "MIT" }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, "node_modules/ts-log": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.7.tgz", @@ -6579,7 +8044,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -6633,6 +8097,12 @@ "which-typed-array": "^1.1.2" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -6658,6 +8128,21 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/which-typed-array": { "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", @@ -6696,6 +8181,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", diff --git a/package.json b/package.json index ed641c3..3c0f9ca 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@drift-labs/sdk": "^2.75.0", + "@prisma/client": "^6.18.0", "@pythnetwork/hermes-client": "^1.0.0", "@pythnetwork/price-service-client": "^1.3.0", "@solana/web3.js": "^1.91.1", @@ -18,6 +19,7 @@ "bs58": "^5.0.0", "next": "^15.0.0", "postcss": "^8.5.6", + "prisma": "^6.18.0", "react": "^18.3.0", "react-dom": "^18.3.0", "tailwindcss": "^3.4.1" diff --git a/prisma/migrations/20251026200052_init/migration.sql b/prisma/migrations/20251026200052_init/migration.sql new file mode 100644 index 0000000..e223813 --- /dev/null +++ b/prisma/migrations/20251026200052_init/migration.sql @@ -0,0 +1,123 @@ +-- CreateTable +CREATE TABLE "Trade" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "positionId" TEXT NOT NULL, + "symbol" TEXT NOT NULL, + "direction" TEXT NOT NULL, + "entryPrice" DOUBLE PRECISION NOT NULL, + "entryTime" TIMESTAMP(3) NOT NULL, + "entrySlippage" DOUBLE PRECISION, + "positionSizeUSD" DOUBLE PRECISION NOT NULL, + "leverage" DOUBLE PRECISION NOT NULL, + "stopLossPrice" DOUBLE PRECISION NOT NULL, + "softStopPrice" DOUBLE PRECISION, + "hardStopPrice" DOUBLE PRECISION, + "takeProfit1Price" DOUBLE PRECISION NOT NULL, + "takeProfit2Price" DOUBLE PRECISION NOT NULL, + "tp1SizePercent" DOUBLE PRECISION NOT NULL, + "tp2SizePercent" DOUBLE PRECISION NOT NULL, + "exitPrice" DOUBLE PRECISION, + "exitTime" TIMESTAMP(3), + "exitReason" TEXT, + "realizedPnL" DOUBLE PRECISION, + "realizedPnLPercent" DOUBLE PRECISION, + "holdTimeSeconds" INTEGER, + "maxDrawdown" DOUBLE PRECISION, + "maxGain" DOUBLE PRECISION, + "entryOrderTx" TEXT NOT NULL, + "tp1OrderTx" TEXT, + "tp2OrderTx" TEXT, + "slOrderTx" TEXT, + "softStopOrderTx" TEXT, + "hardStopOrderTx" TEXT, + "exitOrderTx" TEXT, + "configSnapshot" JSONB NOT NULL, + "signalSource" TEXT, + "signalStrength" TEXT, + "timeframe" TEXT, + "status" TEXT NOT NULL DEFAULT 'open', + + CONSTRAINT "Trade_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PriceUpdate" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "tradeId" TEXT NOT NULL, + "price" DOUBLE PRECISION NOT NULL, + "pnl" DOUBLE PRECISION NOT NULL, + "pnlPercent" DOUBLE PRECISION NOT NULL, + + CONSTRAINT "PriceUpdate_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SystemEvent" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "eventType" TEXT NOT NULL, + "message" TEXT NOT NULL, + "details" JSONB, + + CONSTRAINT "SystemEvent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "DailyStats" ( + "id" TEXT NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "tradesCount" INTEGER NOT NULL, + "winningTrades" INTEGER NOT NULL, + "losingTrades" INTEGER NOT NULL, + "totalPnL" DOUBLE PRECISION NOT NULL, + "totalPnLPercent" DOUBLE PRECISION NOT NULL, + "winRate" DOUBLE PRECISION NOT NULL, + "avgWin" DOUBLE PRECISION NOT NULL, + "avgLoss" DOUBLE PRECISION NOT NULL, + "profitFactor" DOUBLE PRECISION NOT NULL, + "maxDrawdown" DOUBLE PRECISION NOT NULL, + "sharpeRatio" DOUBLE PRECISION, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "DailyStats_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Trade_positionId_key" ON "Trade"("positionId"); + +-- CreateIndex +CREATE INDEX "Trade_symbol_idx" ON "Trade"("symbol"); + +-- CreateIndex +CREATE INDEX "Trade_createdAt_idx" ON "Trade"("createdAt"); + +-- CreateIndex +CREATE INDEX "Trade_status_idx" ON "Trade"("status"); + +-- CreateIndex +CREATE INDEX "Trade_exitReason_idx" ON "Trade"("exitReason"); + +-- CreateIndex +CREATE INDEX "PriceUpdate_tradeId_idx" ON "PriceUpdate"("tradeId"); + +-- CreateIndex +CREATE INDEX "PriceUpdate_createdAt_idx" ON "PriceUpdate"("createdAt"); + +-- CreateIndex +CREATE INDEX "SystemEvent_eventType_idx" ON "SystemEvent"("eventType"); + +-- CreateIndex +CREATE INDEX "SystemEvent_createdAt_idx" ON "SystemEvent"("createdAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "DailyStats_date_key" ON "DailyStats"("date"); + +-- CreateIndex +CREATE INDEX "DailyStats_date_idx" ON "DailyStats"("date"); + +-- AddForeignKey +ALTER TABLE "PriceUpdate" ADD CONSTRAINT "PriceUpdate_tradeId_fkey" FOREIGN KEY ("tradeId") REFERENCES "Trade"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..cf27182 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,131 @@ +// Prisma Schema for Trading Bot v4 +// Database: PostgreSQL + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +// Trade records for analysis and performance tracking +model Trade { + id String @id @default(cuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Trade identification + positionId String @unique // Transaction signature from entry order + symbol String // e.g., "SOL-PERP" + direction String // "long" or "short" + + // Entry details + entryPrice Float + entryTime DateTime + entrySlippage Float? + positionSizeUSD Float + leverage Float + + // Exit targets (planned) + stopLossPrice Float + softStopPrice Float? // Dual stop: soft stop-limit trigger + hardStopPrice Float? // Dual stop: hard stop-market trigger + takeProfit1Price Float + takeProfit2Price Float + tp1SizePercent Float + tp2SizePercent Float + + // Exit details (actual) + exitPrice Float? + exitTime DateTime? + exitReason String? // "TP1", "TP2", "SL", "SOFT_SL", "HARD_SL", "manual", "emergency" + + // Performance metrics + realizedPnL Float? + realizedPnLPercent Float? + holdTimeSeconds Int? + maxDrawdown Float? // Peak to valley during trade + maxGain Float? // Peak gain reached + + // Order signatures + entryOrderTx String + tp1OrderTx String? + tp2OrderTx String? + slOrderTx String? + softStopOrderTx String? // Dual stop: soft stop tx + hardStopOrderTx String? // Dual stop: hard stop tx + exitOrderTx String? + + // Configuration snapshot + configSnapshot Json // Store settings used for this trade + + // Signal data + signalSource String? // "tradingview", "manual", etc. + signalStrength String? // "strong", "moderate", "weak" + timeframe String? // "5", "15", "60" + + // Status + status String @default("open") // "open", "closed", "failed" + + // Relations + priceUpdates PriceUpdate[] + + @@index([symbol]) + @@index([createdAt]) + @@index([status]) + @@index([exitReason]) +} + +// Real-time price updates during trade (for analysis) +model PriceUpdate { + id String @id @default(cuid()) + createdAt DateTime @default(now()) + + tradeId String + trade Trade @relation(fields: [tradeId], references: [id], onDelete: Cascade) + + price Float + pnl Float + pnlPercent Float + + @@index([tradeId]) + @@index([createdAt]) +} + +// System events and errors +model SystemEvent { + id String @id @default(cuid()) + createdAt DateTime @default(now()) + + eventType String // "error", "warning", "info", "trade_executed", etc. + message String + details Json? + + @@index([eventType]) + @@index([createdAt]) +} + +// Performance analytics (daily aggregates) +model DailyStats { + id String @id @default(cuid()) + date DateTime @unique + + tradesCount Int + winningTrades Int + losingTrades Int + totalPnL Float + totalPnLPercent Float + winRate Float + avgWin Float + avgLoss Float + profitFactor Float + maxDrawdown Float + sharpeRatio Float? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([date]) +}