mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
v0.5.24: agent tool and UX improvements, redis service overhaul (#2291)
* feat(folders): add the ability to create a folder within a folder in popover (#2287) * fix(agent): filter out empty params to ensure LLM can set tool params at runtime (#2288) * fix(mcp): added backfill effect to add missing descriptions for mcp tools (#2290) * fix(redis): cleanup access pattern across callsites (#2289) * fix(redis): cleanup access pattern across callsites * swap redis command to be non blocking * improvement(log-details): polling, trace spans (#2292) --------- Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com> Co-authored-by: Emir Karabeg <78010029+emir-karabeg@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,8 @@ import { eq } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { renderOTPEmail } from '@/components/emails/render-email'
|
||||
import { getRedisClient, markMessageAsProcessed, releaseLock } from '@/lib/core/config/redis'
|
||||
import { getRedisClient } from '@/lib/core/config/redis'
|
||||
import { getStorageMethod } from '@/lib/core/storage'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import { sendEmail } from '@/lib/messaging/email/mailer'
|
||||
@@ -17,87 +18,80 @@ function generateOTP() {
|
||||
return Math.floor(100000 + Math.random() * 900000).toString()
|
||||
}
|
||||
|
||||
// OTP storage utility functions using Redis
|
||||
// We use 15 minutes (900 seconds) expiry for OTPs
|
||||
const OTP_EXPIRY = 15 * 60
|
||||
const OTP_EXPIRY = 15 * 60 // 15 minutes
|
||||
const OTP_EXPIRY_MS = OTP_EXPIRY * 1000
|
||||
|
||||
/**
|
||||
* In-memory OTP storage for single-instance deployments without Redis.
|
||||
* Only used when REDIS_URL is not configured (determined once at startup).
|
||||
*
|
||||
* Warning: This does NOT work in multi-instance/serverless deployments.
|
||||
*/
|
||||
const inMemoryOTPStore = new Map<string, { otp: string; expiresAt: number }>()
|
||||
|
||||
function cleanupExpiredOTPs() {
|
||||
const now = Date.now()
|
||||
for (const [key, value] of inMemoryOTPStore.entries()) {
|
||||
if (value.expiresAt < now) {
|
||||
inMemoryOTPStore.delete(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store OTP in Redis
|
||||
async function storeOTP(email: string, chatId: string, otp: string): Promise<void> {
|
||||
const key = `otp:${email}:${chatId}`
|
||||
const redis = getRedisClient()
|
||||
const storageMethod = getStorageMethod()
|
||||
|
||||
if (redis) {
|
||||
// Use Redis if available
|
||||
if (storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis configured but client unavailable')
|
||||
}
|
||||
await redis.set(key, otp, 'EX', OTP_EXPIRY)
|
||||
} else {
|
||||
// Use the existing function as fallback to mark that an OTP exists
|
||||
await markMessageAsProcessed(key, OTP_EXPIRY)
|
||||
|
||||
// For the fallback case, we need to handle storing the OTP value separately
|
||||
// since markMessageAsProcessed only stores "1"
|
||||
const valueKey = `${key}:value`
|
||||
try {
|
||||
// Access the in-memory cache directly - hacky but works for fallback
|
||||
const inMemoryCache = (global as any).inMemoryCache
|
||||
if (inMemoryCache) {
|
||||
const fullKey = `processed:${valueKey}`
|
||||
const expiry = OTP_EXPIRY ? Date.now() + OTP_EXPIRY * 1000 : null
|
||||
inMemoryCache.set(fullKey, { value: otp, expiry })
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error storing OTP in fallback cache:', error)
|
||||
}
|
||||
cleanupExpiredOTPs()
|
||||
inMemoryOTPStore.set(key, {
|
||||
otp,
|
||||
expiresAt: Date.now() + OTP_EXPIRY_MS,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Get OTP from Redis
|
||||
async function getOTP(email: string, chatId: string): Promise<string | null> {
|
||||
const key = `otp:${email}:${chatId}`
|
||||
const redis = getRedisClient()
|
||||
const storageMethod = getStorageMethod()
|
||||
|
||||
if (redis) {
|
||||
// Use Redis if available
|
||||
return await redis.get(key)
|
||||
}
|
||||
// Use the existing function as fallback - check if it exists
|
||||
const exists = await new Promise((resolve) => {
|
||||
try {
|
||||
// Check the in-memory cache directly - hacky but works for fallback
|
||||
const inMemoryCache = (global as any).inMemoryCache
|
||||
const fullKey = `processed:${key}`
|
||||
const cacheEntry = inMemoryCache?.get(fullKey)
|
||||
resolve(!!cacheEntry)
|
||||
} catch {
|
||||
resolve(false)
|
||||
if (storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis configured but client unavailable')
|
||||
}
|
||||
})
|
||||
return redis.get(key)
|
||||
}
|
||||
|
||||
if (!exists) return null
|
||||
const entry = inMemoryOTPStore.get(key)
|
||||
if (!entry) return null
|
||||
|
||||
// Try to get the value key
|
||||
const valueKey = `${key}:value`
|
||||
try {
|
||||
const inMemoryCache = (global as any).inMemoryCache
|
||||
const fullKey = `processed:${valueKey}`
|
||||
const cacheEntry = inMemoryCache?.get(fullKey)
|
||||
return cacheEntry?.value || null
|
||||
} catch {
|
||||
if (entry.expiresAt < Date.now()) {
|
||||
inMemoryOTPStore.delete(key)
|
||||
return null
|
||||
}
|
||||
|
||||
return entry.otp
|
||||
}
|
||||
|
||||
// Delete OTP from Redis
|
||||
async function deleteOTP(email: string, chatId: string): Promise<void> {
|
||||
const key = `otp:${email}:${chatId}`
|
||||
const redis = getRedisClient()
|
||||
const storageMethod = getStorageMethod()
|
||||
|
||||
if (redis) {
|
||||
// Use Redis if available
|
||||
if (storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis configured but client unavailable')
|
||||
}
|
||||
await redis.del(key)
|
||||
} else {
|
||||
// Use the existing function as fallback
|
||||
await releaseLock(`processed:${key}`)
|
||||
await releaseLock(`processed:${key}:value`)
|
||||
inMemoryOTPStore.delete(key)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +104,6 @@ const otpVerifySchema = z.object({
|
||||
otp: z.string().length(6, 'OTP must be 6 digits'),
|
||||
})
|
||||
|
||||
// Send OTP endpoint
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ identifier: string }> }
|
||||
@@ -121,101 +114,82 @@ export async function POST(
|
||||
try {
|
||||
logger.debug(`[${requestId}] Processing OTP request for identifier: ${identifier}`)
|
||||
|
||||
// Parse request body
|
||||
let body
|
||||
try {
|
||||
body = await request.json()
|
||||
const { email } = otpRequestSchema.parse(body)
|
||||
const body = await request.json()
|
||||
const { email } = otpRequestSchema.parse(body)
|
||||
|
||||
// Find the chat deployment
|
||||
const deploymentResult = await db
|
||||
.select({
|
||||
id: chat.id,
|
||||
authType: chat.authType,
|
||||
allowedEmails: chat.allowedEmails,
|
||||
title: chat.title,
|
||||
})
|
||||
.from(chat)
|
||||
.where(eq(chat.identifier, identifier))
|
||||
.limit(1)
|
||||
const deploymentResult = await db
|
||||
.select({
|
||||
id: chat.id,
|
||||
authType: chat.authType,
|
||||
allowedEmails: chat.allowedEmails,
|
||||
title: chat.title,
|
||||
})
|
||||
.from(chat)
|
||||
.where(eq(chat.identifier, identifier))
|
||||
.limit(1)
|
||||
|
||||
if (deploymentResult.length === 0) {
|
||||
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
|
||||
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
|
||||
}
|
||||
if (deploymentResult.length === 0) {
|
||||
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
|
||||
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
|
||||
}
|
||||
|
||||
const deployment = deploymentResult[0]
|
||||
const deployment = deploymentResult[0]
|
||||
|
||||
// Verify this is an email-protected chat
|
||||
if (deployment.authType !== 'email') {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse('This chat does not use email authentication', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
|
||||
const allowedEmails: string[] = Array.isArray(deployment.allowedEmails)
|
||||
? deployment.allowedEmails
|
||||
: []
|
||||
|
||||
const isEmailAllowed =
|
||||
allowedEmails.includes(email) ||
|
||||
allowedEmails.some((allowed: string) => {
|
||||
if (allowed.startsWith('@')) {
|
||||
const domain = email.split('@')[1]
|
||||
return domain && allowed === `@${domain}`
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if (!isEmailAllowed) {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse('Email not authorized for this chat', 403),
|
||||
request
|
||||
)
|
||||
}
|
||||
|
||||
const otp = generateOTP()
|
||||
|
||||
await storeOTP(email, deployment.id, otp)
|
||||
|
||||
const emailHtml = await renderOTPEmail(
|
||||
otp,
|
||||
email,
|
||||
'email-verification',
|
||||
deployment.title || 'Chat'
|
||||
if (deployment.authType !== 'email') {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse('This chat does not use email authentication', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
|
||||
const emailResult = await sendEmail({
|
||||
to: email,
|
||||
subject: `Verification code for ${deployment.title || 'Chat'}`,
|
||||
html: emailHtml,
|
||||
const allowedEmails: string[] = Array.isArray(deployment.allowedEmails)
|
||||
? deployment.allowedEmails
|
||||
: []
|
||||
|
||||
const isEmailAllowed =
|
||||
allowedEmails.includes(email) ||
|
||||
allowedEmails.some((allowed: string) => {
|
||||
if (allowed.startsWith('@')) {
|
||||
const domain = email.split('@')[1]
|
||||
return domain && allowed === `@${domain}`
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if (!emailResult.success) {
|
||||
logger.error(`[${requestId}] Failed to send OTP email:`, emailResult.message)
|
||||
return addCorsHeaders(
|
||||
createErrorResponse('Failed to send verification email', 500),
|
||||
request
|
||||
)
|
||||
}
|
||||
|
||||
// Add a small delay to ensure Redis has fully processed the operation
|
||||
// This helps with eventual consistency in distributed systems
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
logger.info(`[${requestId}] OTP sent to ${email} for chat ${deployment.id}`)
|
||||
return addCorsHeaders(createSuccessResponse({ message: 'Verification code sent' }), request)
|
||||
} catch (error: any) {
|
||||
if (error instanceof z.ZodError) {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse(error.errors[0]?.message || 'Invalid request', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
throw error
|
||||
if (!isEmailAllowed) {
|
||||
return addCorsHeaders(createErrorResponse('Email not authorized for this chat', 403), request)
|
||||
}
|
||||
|
||||
const otp = generateOTP()
|
||||
await storeOTP(email, deployment.id, otp)
|
||||
|
||||
const emailHtml = await renderOTPEmail(
|
||||
otp,
|
||||
email,
|
||||
'email-verification',
|
||||
deployment.title || 'Chat'
|
||||
)
|
||||
|
||||
const emailResult = await sendEmail({
|
||||
to: email,
|
||||
subject: `Verification code for ${deployment.title || 'Chat'}`,
|
||||
html: emailHtml,
|
||||
})
|
||||
|
||||
if (!emailResult.success) {
|
||||
logger.error(`[${requestId}] Failed to send OTP email:`, emailResult.message)
|
||||
return addCorsHeaders(createErrorResponse('Failed to send verification email', 500), request)
|
||||
}
|
||||
|
||||
logger.info(`[${requestId}] OTP sent to ${email} for chat ${deployment.id}`)
|
||||
return addCorsHeaders(createSuccessResponse({ message: 'Verification code sent' }), request)
|
||||
} catch (error: any) {
|
||||
if (error instanceof z.ZodError) {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse(error.errors[0]?.message || 'Invalid request', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
logger.error(`[${requestId}] Error processing OTP request:`, error)
|
||||
return addCorsHeaders(
|
||||
createErrorResponse(error.message || 'Failed to process request', 500),
|
||||
@@ -224,7 +198,6 @@ export async function POST(
|
||||
}
|
||||
}
|
||||
|
||||
// Verify OTP endpoint
|
||||
export async function PUT(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ identifier: string }> }
|
||||
@@ -235,63 +208,50 @@ export async function PUT(
|
||||
try {
|
||||
logger.debug(`[${requestId}] Verifying OTP for identifier: ${identifier}`)
|
||||
|
||||
// Parse request body
|
||||
let body
|
||||
try {
|
||||
body = await request.json()
|
||||
const { email, otp } = otpVerifySchema.parse(body)
|
||||
const body = await request.json()
|
||||
const { email, otp } = otpVerifySchema.parse(body)
|
||||
|
||||
// Find the chat deployment
|
||||
const deploymentResult = await db
|
||||
.select({
|
||||
id: chat.id,
|
||||
authType: chat.authType,
|
||||
})
|
||||
.from(chat)
|
||||
.where(eq(chat.identifier, identifier))
|
||||
.limit(1)
|
||||
const deploymentResult = await db
|
||||
.select({
|
||||
id: chat.id,
|
||||
authType: chat.authType,
|
||||
})
|
||||
.from(chat)
|
||||
.where(eq(chat.identifier, identifier))
|
||||
.limit(1)
|
||||
|
||||
if (deploymentResult.length === 0) {
|
||||
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
|
||||
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
|
||||
}
|
||||
|
||||
const deployment = deploymentResult[0]
|
||||
|
||||
// Check if OTP exists and is valid
|
||||
const storedOTP = await getOTP(email, deployment.id)
|
||||
if (!storedOTP) {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse('No verification code found, request a new one', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
|
||||
// Check if OTP matches
|
||||
if (storedOTP !== otp) {
|
||||
return addCorsHeaders(createErrorResponse('Invalid verification code', 400), request)
|
||||
}
|
||||
|
||||
// OTP is valid, clean up
|
||||
await deleteOTP(email, deployment.id)
|
||||
|
||||
// Create success response with auth cookie
|
||||
const response = addCorsHeaders(createSuccessResponse({ authenticated: true }), request)
|
||||
|
||||
// Set authentication cookie
|
||||
setChatAuthCookie(response, deployment.id, deployment.authType)
|
||||
|
||||
return response
|
||||
} catch (error: any) {
|
||||
if (error instanceof z.ZodError) {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse(error.errors[0]?.message || 'Invalid request', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
throw error
|
||||
if (deploymentResult.length === 0) {
|
||||
logger.warn(`[${requestId}] Chat not found for identifier: ${identifier}`)
|
||||
return addCorsHeaders(createErrorResponse('Chat not found', 404), request)
|
||||
}
|
||||
|
||||
const deployment = deploymentResult[0]
|
||||
|
||||
const storedOTP = await getOTP(email, deployment.id)
|
||||
if (!storedOTP) {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse('No verification code found, request a new one', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
|
||||
if (storedOTP !== otp) {
|
||||
return addCorsHeaders(createErrorResponse('Invalid verification code', 400), request)
|
||||
}
|
||||
|
||||
await deleteOTP(email, deployment.id)
|
||||
|
||||
const response = addCorsHeaders(createSuccessResponse({ authenticated: true }), request)
|
||||
setChatAuthCookie(response, deployment.id, deployment.authType)
|
||||
|
||||
return response
|
||||
} catch (error: any) {
|
||||
if (error instanceof z.ZodError) {
|
||||
return addCorsHeaders(
|
||||
createErrorResponse(error.errors[0]?.message || 'Invalid request', 400),
|
||||
request
|
||||
)
|
||||
}
|
||||
logger.error(`[${requestId}] Error verifying OTP:`, error)
|
||||
return addCorsHeaders(
|
||||
createErrorResponse(error.message || 'Failed to process request', 500),
|
||||
|
||||
@@ -16,15 +16,17 @@ export async function GET(request: NextRequest) {
|
||||
const requestId = nanoid()
|
||||
logger.info(`Inactivity alert polling triggered (${requestId})`)
|
||||
|
||||
let lockAcquired = false
|
||||
|
||||
try {
|
||||
const authError = verifyCronAuth(request, 'Inactivity alert polling')
|
||||
if (authError) {
|
||||
return authError
|
||||
}
|
||||
|
||||
const locked = await acquireLock(LOCK_KEY, requestId, LOCK_TTL_SECONDS)
|
||||
lockAcquired = await acquireLock(LOCK_KEY, requestId, LOCK_TTL_SECONDS)
|
||||
|
||||
if (!locked) {
|
||||
if (!lockAcquired) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: true,
|
||||
@@ -57,6 +59,8 @@ export async function GET(request: NextRequest) {
|
||||
{ status: 500 }
|
||||
)
|
||||
} finally {
|
||||
await releaseLock(LOCK_KEY).catch(() => {})
|
||||
if (lockAcquired) {
|
||||
await releaseLock(LOCK_KEY, requestId).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ export async function GET(request: NextRequest) {
|
||||
{ status: 500 }
|
||||
)
|
||||
} finally {
|
||||
await releaseLock(LOCK_KEY).catch(() => {})
|
||||
if (lockValue) {
|
||||
await releaseLock(LOCK_KEY, lockValue).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ export async function GET(request: NextRequest) {
|
||||
{ status: 500 }
|
||||
)
|
||||
} finally {
|
||||
await releaseLock(LOCK_KEY).catch(() => {})
|
||||
if (lockValue) {
|
||||
await releaseLock(LOCK_KEY, lockValue).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,8 @@ export async function GET(request: NextRequest) {
|
||||
{ status: 500 }
|
||||
)
|
||||
} finally {
|
||||
await releaseLock(LOCK_KEY).catch(() => {})
|
||||
if (lockValue) {
|
||||
await releaseLock(LOCK_KEY, lockValue).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import {
|
||||
MAX_LOG_DETAILS_WIDTH,
|
||||
MIN_LOG_DETAILS_WIDTH,
|
||||
useLogDetailsUIStore,
|
||||
} from '@/stores/logs/store'
|
||||
import { MIN_LOG_DETAILS_WIDTH, useLogDetailsUIStore } from '@/stores/logs/store'
|
||||
|
||||
/**
|
||||
* Hook for handling log details panel resize via mouse drag.
|
||||
@@ -29,10 +25,8 @@ export function useLogDetailsResize() {
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
// Calculate new width from right edge of window
|
||||
const newWidth = window.innerWidth - e.clientX
|
||||
const clampedWidth = Math.max(
|
||||
MIN_LOG_DETAILS_WIDTH,
|
||||
Math.min(newWidth, MAX_LOG_DETAILS_WIDTH)
|
||||
)
|
||||
const maxWidth = window.innerWidth * 0.5 // 50vw
|
||||
const clampedWidth = Math.max(MIN_LOG_DETAILS_WIDTH, Math.min(newWidth, maxWidth))
|
||||
|
||||
setPanelWidth(clampedWidth)
|
||||
}
|
||||
|
||||
@@ -107,21 +107,42 @@ export default function Logs() {
|
||||
}
|
||||
}, [debouncedSearchQuery, setStoreSearchQuery])
|
||||
|
||||
// Track previous log state for efficient change detection
|
||||
const prevSelectedLogRef = useRef<WorkflowLog | null>(null)
|
||||
|
||||
// Sync selected log with refreshed data from logs list
|
||||
useEffect(() => {
|
||||
if (!selectedLog?.id || logs.length === 0) return
|
||||
|
||||
const updatedLog = logs.find((l) => l.id === selectedLog.id)
|
||||
if (updatedLog) {
|
||||
// Update selectedLog with fresh data from the list
|
||||
if (!updatedLog) return
|
||||
|
||||
const prevLog = prevSelectedLogRef.current
|
||||
|
||||
// Check if status-related fields have changed (e.g., running -> done)
|
||||
const hasStatusChange =
|
||||
prevLog?.id === updatedLog.id &&
|
||||
(updatedLog.duration !== prevLog.duration ||
|
||||
updatedLog.level !== prevLog.level ||
|
||||
updatedLog.hasPendingPause !== prevLog.hasPendingPause)
|
||||
|
||||
// Only update if the log data actually changed
|
||||
if (updatedLog !== selectedLog) {
|
||||
setSelectedLog(updatedLog)
|
||||
// Update index in case position changed
|
||||
const newIndex = logs.findIndex((l) => l.id === selectedLog.id)
|
||||
if (newIndex !== selectedLogIndex) {
|
||||
setSelectedLogIndex(newIndex)
|
||||
}
|
||||
prevSelectedLogRef.current = updatedLog
|
||||
}
|
||||
}, [logs, selectedLog?.id, selectedLogIndex])
|
||||
|
||||
// Update index in case position changed
|
||||
const newIndex = logs.findIndex((l) => l.id === selectedLog.id)
|
||||
if (newIndex !== selectedLogIndex) {
|
||||
setSelectedLogIndex(newIndex)
|
||||
}
|
||||
|
||||
// Refetch log details if status changed to keep details panel in sync
|
||||
if (hasStatusChange) {
|
||||
logDetailQuery.refetch()
|
||||
}
|
||||
}, [logs, selectedLog?.id, selectedLogIndex, logDetailQuery.refetch])
|
||||
|
||||
// Refetch log details during live mode
|
||||
useEffect(() => {
|
||||
@@ -143,6 +164,7 @@ export default function Logs() {
|
||||
|
||||
// Otherwise, select the log and open the sidebar
|
||||
setSelectedLog(log)
|
||||
prevSelectedLogRef.current = log
|
||||
const index = logs.findIndex((l) => l.id === log.id)
|
||||
setSelectedLogIndex(index)
|
||||
setIsSidebarOpen(true)
|
||||
@@ -154,6 +176,7 @@ export default function Logs() {
|
||||
setSelectedLogIndex(nextIndex)
|
||||
const nextLog = logs[nextIndex]
|
||||
setSelectedLog(nextLog)
|
||||
prevSelectedLogRef.current = nextLog
|
||||
}
|
||||
}, [selectedLogIndex, logs])
|
||||
|
||||
@@ -163,6 +186,7 @@ export default function Logs() {
|
||||
setSelectedLogIndex(prevIndex)
|
||||
const prevLog = logs[prevIndex]
|
||||
setSelectedLog(prevLog)
|
||||
prevSelectedLogRef.current = prevLog
|
||||
}
|
||||
}, [selectedLogIndex, logs])
|
||||
|
||||
@@ -170,6 +194,7 @@ export default function Logs() {
|
||||
setIsSidebarOpen(false)
|
||||
setSelectedLog(null)
|
||||
setSelectedLogIndex(-1)
|
||||
prevSelectedLogRef.current = null
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -332,6 +357,7 @@ export default function Logs() {
|
||||
e.preventDefault()
|
||||
setSelectedLogIndex(0)
|
||||
setSelectedLog(logs[0])
|
||||
prevSelectedLogRef.current = logs[0]
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ const IconComponent = ({ icon: Icon, className }: { icon: any; className?: strin
|
||||
interface McpTool {
|
||||
id: string
|
||||
name: string
|
||||
description?: string
|
||||
serverId: string
|
||||
serverName: string
|
||||
icon: React.ComponentType<any>
|
||||
@@ -76,7 +77,10 @@ export function McpToolsList({
|
||||
},
|
||||
isExpanded: true,
|
||||
usageControl: 'auto',
|
||||
schema: mcpTool.inputSchema,
|
||||
schema: {
|
||||
...mcpTool.inputSchema,
|
||||
description: mcpTool.description,
|
||||
},
|
||||
}
|
||||
|
||||
onToolSelect(newTool)
|
||||
|
||||
@@ -858,16 +858,22 @@ export function ToolInput({
|
||||
return
|
||||
}
|
||||
|
||||
const mcpToolsNeedingSchema = selectedTools.filter(
|
||||
(tool) => tool.type === 'mcp' && !tool.schema && tool.params?.toolName
|
||||
// Find MCP tools that need schema or are missing description
|
||||
const mcpToolsNeedingUpdate = selectedTools.filter(
|
||||
(tool) =>
|
||||
tool.type === 'mcp' && tool.params?.toolName && (!tool.schema || !tool.schema.description)
|
||||
)
|
||||
|
||||
if (mcpToolsNeedingSchema.length === 0) {
|
||||
if (mcpToolsNeedingUpdate.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const updatedTools = selectedTools.map((tool) => {
|
||||
if (tool.type !== 'mcp' || tool.schema || !tool.params?.toolName) {
|
||||
if (tool.type !== 'mcp' || !tool.params?.toolName) {
|
||||
return tool
|
||||
}
|
||||
|
||||
if (tool.schema?.description) {
|
||||
return tool
|
||||
}
|
||||
|
||||
@@ -877,17 +883,27 @@ export function ToolInput({
|
||||
|
||||
if (mcpTool?.inputSchema) {
|
||||
logger.info(`Backfilling schema for MCP tool: ${tool.params.toolName}`)
|
||||
return { ...tool, schema: mcpTool.inputSchema }
|
||||
return {
|
||||
...tool,
|
||||
schema: {
|
||||
...mcpTool.inputSchema,
|
||||
description: mcpTool.description,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return tool
|
||||
})
|
||||
|
||||
const hasChanges = updatedTools.some((tool, i) => tool.schema && !selectedTools[i].schema)
|
||||
const hasChanges = updatedTools.some(
|
||||
(tool, i) =>
|
||||
(tool.schema && !selectedTools[i].schema) ||
|
||||
(tool.schema?.description && !selectedTools[i].schema?.description)
|
||||
)
|
||||
|
||||
if (hasChanges) {
|
||||
hasBackfilledRef.current = true
|
||||
logger.info(`Backfilled schemas for ${mcpToolsNeedingSchema.length} MCP tool(s)`)
|
||||
logger.info(`Backfilled schemas for ${mcpToolsNeedingUpdate.length} MCP tool(s)`)
|
||||
setStoreValue(updatedTools)
|
||||
}
|
||||
}, [mcpTools, mcpLoading, selectedTools, isPreview, setStoreValue])
|
||||
|
||||
@@ -28,9 +28,13 @@ interface ContextMenuProps {
|
||||
*/
|
||||
onRename?: () => void
|
||||
/**
|
||||
* Callback when create is clicked (for folders)
|
||||
* Callback when create workflow is clicked (for folders)
|
||||
*/
|
||||
onCreate?: () => void
|
||||
/**
|
||||
* Callback when create folder is clicked (for folders)
|
||||
*/
|
||||
onCreateFolder?: () => void
|
||||
/**
|
||||
* Callback when duplicate is clicked
|
||||
*/
|
||||
@@ -54,10 +58,15 @@ interface ContextMenuProps {
|
||||
*/
|
||||
showRename?: boolean
|
||||
/**
|
||||
* Whether to show the create option (default: false)
|
||||
* Whether to show the create workflow option (default: false)
|
||||
* Set to true for folders to create workflows inside
|
||||
*/
|
||||
showCreate?: boolean
|
||||
/**
|
||||
* Whether to show the create folder option (default: false)
|
||||
* Set to true for folders to create sub-folders inside
|
||||
*/
|
||||
showCreateFolder?: boolean
|
||||
/**
|
||||
* Whether to show the duplicate option (default: true)
|
||||
* Set to false for items that cannot be duplicated
|
||||
@@ -89,10 +98,15 @@ interface ContextMenuProps {
|
||||
*/
|
||||
disableDelete?: boolean
|
||||
/**
|
||||
* Whether the create option is disabled (default: false)
|
||||
* Whether the create workflow option is disabled (default: false)
|
||||
* Set to true when creation is in progress or user lacks permissions
|
||||
*/
|
||||
disableCreate?: boolean
|
||||
/**
|
||||
* Whether the create folder option is disabled (default: false)
|
||||
* Set to true when creation is in progress or user lacks permissions
|
||||
*/
|
||||
disableCreateFolder?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,12 +124,14 @@ export function ContextMenu({
|
||||
onOpenInNewTab,
|
||||
onRename,
|
||||
onCreate,
|
||||
onCreateFolder,
|
||||
onDuplicate,
|
||||
onExport,
|
||||
onDelete,
|
||||
showOpenInNewTab = false,
|
||||
showRename = true,
|
||||
showCreate = false,
|
||||
showCreateFolder = false,
|
||||
showDuplicate = true,
|
||||
showExport = false,
|
||||
disableExport = false,
|
||||
@@ -123,6 +139,7 @@ export function ContextMenu({
|
||||
disableDuplicate = false,
|
||||
disableDelete = false,
|
||||
disableCreate = false,
|
||||
disableCreateFolder = false,
|
||||
}: ContextMenuProps) {
|
||||
return (
|
||||
<Popover open={isOpen} onOpenChange={onClose} variant='primary'>
|
||||
@@ -168,6 +185,17 @@ export function ContextMenu({
|
||||
Create workflow
|
||||
</PopoverItem>
|
||||
)}
|
||||
{showCreateFolder && onCreateFolder && (
|
||||
<PopoverItem
|
||||
disabled={disableCreateFolder}
|
||||
onClick={() => {
|
||||
onCreateFolder()
|
||||
onClose()
|
||||
}}
|
||||
>
|
||||
Create folder
|
||||
</PopoverItem>
|
||||
)}
|
||||
{showDuplicate && onDuplicate && (
|
||||
<PopoverItem
|
||||
disabled={disableDuplicate}
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
useItemRename,
|
||||
} from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks'
|
||||
import { useDeleteFolder, useDuplicateFolder } from '@/app/workspace/[workspaceId]/w/hooks'
|
||||
import { useUpdateFolder } from '@/hooks/queries/folders'
|
||||
import { useCreateFolder, useUpdateFolder } from '@/hooks/queries/folders'
|
||||
import { useCreateWorkflow } from '@/hooks/queries/workflows'
|
||||
import type { FolderTreeNode } from '@/stores/folders/store'
|
||||
import {
|
||||
@@ -48,6 +48,7 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
|
||||
const workspaceId = params.workspaceId as string
|
||||
const updateFolderMutation = useUpdateFolder()
|
||||
const createWorkflowMutation = useCreateWorkflow()
|
||||
const createFolderMutation = useCreateFolder()
|
||||
const userPermissions = useUserPermissionsContext()
|
||||
|
||||
// Delete modal state
|
||||
@@ -93,6 +94,22 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
|
||||
}
|
||||
}, [createWorkflowMutation, workspaceId, folder.id, router])
|
||||
|
||||
/**
|
||||
* Handle create sub-folder using React Query mutation.
|
||||
* Creates a new folder inside the current folder.
|
||||
*/
|
||||
const handleCreateFolderInFolder = useCallback(async () => {
|
||||
try {
|
||||
await createFolderMutation.mutateAsync({
|
||||
workspaceId,
|
||||
name: 'New Folder',
|
||||
parentId: folder.id,
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Failed to create folder:', error)
|
||||
}
|
||||
}, [createFolderMutation, workspaceId, folder.id])
|
||||
|
||||
// Folder expand hook
|
||||
const {
|
||||
isExpanded,
|
||||
@@ -279,11 +296,14 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
|
||||
onClose={closeMenu}
|
||||
onRename={handleStartEdit}
|
||||
onCreate={handleCreateWorkflowInFolder}
|
||||
onCreateFolder={handleCreateFolderInFolder}
|
||||
onDuplicate={handleDuplicateFolder}
|
||||
onDelete={() => setIsDeleteModalOpen(true)}
|
||||
showCreate={true}
|
||||
showCreateFolder={true}
|
||||
disableRename={!userPermissions.canEdit}
|
||||
disableCreate={!userPermissions.canEdit || createWorkflowMutation.isPending}
|
||||
disableCreateFolder={!userPermissions.canEdit || createFolderMutation.isPending}
|
||||
disableDuplicate={!userPermissions.canEdit}
|
||||
disableDelete={!userPermissions.canEdit}
|
||||
/>
|
||||
|
||||
@@ -4,242 +4,182 @@ import { createLogger } from '@/lib/logs/console/logger'
|
||||
|
||||
const logger = createLogger('Redis')
|
||||
|
||||
// Only use Redis if explicitly configured
|
||||
const redisUrl = env.REDIS_URL
|
||||
|
||||
// Global Redis client for connection pooling
|
||||
let globalRedisClient: Redis | null = null
|
||||
|
||||
// Fallback in-memory cache for when Redis is not available
|
||||
const inMemoryCache = new Map<string, { value: string; expiry: number | null }>()
|
||||
const MAX_CACHE_SIZE = 1000
|
||||
|
||||
/**
|
||||
* Get a Redis client instance
|
||||
* Uses connection pooling to avoid creating a new connection for each request
|
||||
* Get a Redis client instance.
|
||||
* Uses connection pooling to reuse connections across requests.
|
||||
*
|
||||
* ioredis handles command queuing internally via `enableOfflineQueue` (default: true),
|
||||
* so commands are queued and executed once connected. No manual connection checks needed.
|
||||
*/
|
||||
export function getRedisClient(): Redis | null {
|
||||
// For server-side only
|
||||
if (typeof window !== 'undefined') return null
|
||||
|
||||
// Return null immediately if no Redis URL is configured
|
||||
if (!redisUrl) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!redisUrl) return null
|
||||
if (globalRedisClient) return globalRedisClient
|
||||
|
||||
try {
|
||||
// Create a new Redis client with optimized settings for serverless
|
||||
logger.info('Initializing Redis client')
|
||||
|
||||
globalRedisClient = new Redis(redisUrl, {
|
||||
// Keep alive is critical for serverless to reuse connections
|
||||
keepAlive: 1000,
|
||||
// Faster connection timeout for serverless
|
||||
connectTimeout: 5000,
|
||||
// Disable reconnection attempts in serverless
|
||||
maxRetriesPerRequest: 3,
|
||||
// Retry strategy with exponential backoff
|
||||
connectTimeout: 10000,
|
||||
commandTimeout: 5000,
|
||||
maxRetriesPerRequest: 5,
|
||||
enableOfflineQueue: true,
|
||||
|
||||
retryStrategy: (times) => {
|
||||
if (times > 5) {
|
||||
logger.warn('Redis connection failed after 5 attempts, using fallback')
|
||||
return null // Stop retrying
|
||||
if (times > 10) {
|
||||
logger.error(`Redis reconnection attempt ${times}`, { nextRetryMs: 30000 })
|
||||
return 30000
|
||||
}
|
||||
return Math.min(times * 200, 2000) // Exponential backoff
|
||||
const delay = Math.min(times * 500, 5000)
|
||||
logger.warn(`Redis reconnecting`, { attempt: times, nextRetryMs: delay })
|
||||
return delay
|
||||
},
|
||||
|
||||
reconnectOnError: (err) => {
|
||||
const targetErrors = ['READONLY', 'ECONNRESET', 'ETIMEDOUT', 'ECONNREFUSED']
|
||||
return targetErrors.some((e) => err.message.includes(e))
|
||||
},
|
||||
})
|
||||
|
||||
// Handle connection events
|
||||
globalRedisClient.on('error', (err: any) => {
|
||||
logger.error('Redis connection error:', { err })
|
||||
if (err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT') {
|
||||
globalRedisClient = null
|
||||
}
|
||||
globalRedisClient.on('connect', () => logger.info('Redis connected'))
|
||||
globalRedisClient.on('ready', () => logger.info('Redis ready'))
|
||||
globalRedisClient.on('error', (err: Error) => {
|
||||
logger.error('Redis error', { error: err.message, code: (err as any).code })
|
||||
})
|
||||
|
||||
globalRedisClient.on('connect', () => {})
|
||||
globalRedisClient.on('close', () => logger.warn('Redis connection closed'))
|
||||
globalRedisClient.on('end', () => logger.error('Redis connection ended'))
|
||||
|
||||
return globalRedisClient
|
||||
} catch (error) {
|
||||
logger.error('Failed to initialize Redis client:', { error })
|
||||
logger.error('Failed to initialize Redis client', { error })
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// Message ID cache functions
|
||||
const MESSAGE_ID_PREFIX = 'processed:' // Generic prefix
|
||||
const MESSAGE_ID_EXPIRY = 60 * 60 * 24 * 7 // 7 days in seconds
|
||||
|
||||
/**
|
||||
* Check if a key exists in Redis or fallback cache.
|
||||
* @param key The key to check (e.g., messageId, lockKey).
|
||||
* @returns True if the key exists and hasn't expired, false otherwise.
|
||||
* Check if Redis is ready for commands.
|
||||
* Use for health checks only - commands should be sent regardless (ioredis queues them).
|
||||
*/
|
||||
export async function hasProcessedMessage(key: string): Promise<boolean> {
|
||||
try {
|
||||
const redis = getRedisClient()
|
||||
const fullKey = `${MESSAGE_ID_PREFIX}${key}` // Use generic prefix
|
||||
|
||||
if (redis) {
|
||||
// Use Redis if available
|
||||
const result = await redis.exists(fullKey)
|
||||
return result === 1
|
||||
}
|
||||
// Fallback to in-memory cache
|
||||
const cacheEntry = inMemoryCache.get(fullKey)
|
||||
if (!cacheEntry) return false
|
||||
|
||||
// Check if the entry has expired
|
||||
if (cacheEntry.expiry && cacheEntry.expiry < Date.now()) {
|
||||
inMemoryCache.delete(fullKey)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
logger.error(`Error checking key ${key}:`, { error })
|
||||
// Fallback to in-memory cache on error
|
||||
const fullKey = `${MESSAGE_ID_PREFIX}${key}`
|
||||
const cacheEntry = inMemoryCache.get(fullKey)
|
||||
return !!cacheEntry && (!cacheEntry.expiry || cacheEntry.expiry > Date.now())
|
||||
}
|
||||
export function isRedisConnected(): boolean {
|
||||
return globalRedisClient?.status === 'ready'
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a key as processed/present in Redis or fallback cache.
|
||||
* @param key The key to mark (e.g., messageId, lockKey).
|
||||
* @param expirySeconds Optional expiry time in seconds (defaults to 7 days).
|
||||
* Get Redis connection status for diagnostics.
|
||||
*/
|
||||
export function getRedisStatus(): string {
|
||||
return globalRedisClient?.status ?? 'not initialized'
|
||||
}
|
||||
|
||||
const MESSAGE_ID_PREFIX = 'processed:'
|
||||
const MESSAGE_ID_EXPIRY = 60 * 60 * 24 * 7
|
||||
|
||||
/**
|
||||
* Check if a message has been processed (for idempotency).
|
||||
* Requires Redis - throws if Redis is not available.
|
||||
*/
|
||||
export async function hasProcessedMessage(key: string): Promise<boolean> {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available for message deduplication')
|
||||
}
|
||||
|
||||
const result = await redis.exists(`${MESSAGE_ID_PREFIX}${key}`)
|
||||
return result === 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a message as processed (for idempotency).
|
||||
* Requires Redis - throws if Redis is not available.
|
||||
*/
|
||||
export async function markMessageAsProcessed(
|
||||
key: string,
|
||||
expirySeconds: number = MESSAGE_ID_EXPIRY
|
||||
): Promise<void> {
|
||||
try {
|
||||
const redis = getRedisClient()
|
||||
const fullKey = `${MESSAGE_ID_PREFIX}${key}` // Use generic prefix
|
||||
|
||||
if (redis) {
|
||||
// Use Redis if available - use pipelining for efficiency
|
||||
await redis.set(fullKey, '1', 'EX', expirySeconds)
|
||||
} else {
|
||||
// Fallback to in-memory cache
|
||||
const expiry = expirySeconds ? Date.now() + expirySeconds * 1000 : null
|
||||
inMemoryCache.set(fullKey, { value: '1', expiry })
|
||||
|
||||
// Clean up old message IDs if cache gets too large
|
||||
if (inMemoryCache.size > MAX_CACHE_SIZE) {
|
||||
const now = Date.now()
|
||||
|
||||
// First try to remove expired entries
|
||||
for (const [cacheKey, entry] of inMemoryCache.entries()) {
|
||||
if (entry.expiry && entry.expiry < now) {
|
||||
inMemoryCache.delete(cacheKey)
|
||||
}
|
||||
}
|
||||
|
||||
// If still too large, remove oldest entries (FIFO based on insertion order)
|
||||
if (inMemoryCache.size > MAX_CACHE_SIZE) {
|
||||
const keysToDelete = Array.from(inMemoryCache.keys()).slice(
|
||||
0,
|
||||
inMemoryCache.size - MAX_CACHE_SIZE
|
||||
)
|
||||
|
||||
for (const keyToDelete of keysToDelete) {
|
||||
inMemoryCache.delete(keyToDelete)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error marking key ${key} as processed:`, { error })
|
||||
// Fallback to in-memory cache on error
|
||||
const fullKey = `${MESSAGE_ID_PREFIX}${key}`
|
||||
const expiry = expirySeconds ? Date.now() + expirySeconds * 1000 : null
|
||||
inMemoryCache.set(fullKey, { value: '1', expiry })
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available for message deduplication')
|
||||
}
|
||||
|
||||
await redis.set(`${MESSAGE_ID_PREFIX}${key}`, '1', 'EX', expirySeconds)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to acquire a lock using Redis SET NX command.
|
||||
* @param lockKey The key to use for the lock.
|
||||
* @param value The value to set (e.g., a unique identifier for the process holding the lock).
|
||||
* @param expirySeconds The lock's time-to-live in seconds.
|
||||
* @returns True if the lock was acquired successfully, false otherwise.
|
||||
* Lua script for safe lock release.
|
||||
* Only deletes the key if the value matches (ownership verification).
|
||||
* Returns 1 if deleted, 0 if not (value mismatch or key doesn't exist).
|
||||
*/
|
||||
const RELEASE_LOCK_SCRIPT = `
|
||||
if redis.call("get", KEYS[1]) == ARGV[1] then
|
||||
return redis.call("del", KEYS[1])
|
||||
else
|
||||
return 0
|
||||
end
|
||||
`
|
||||
|
||||
/**
|
||||
* Acquire a distributed lock using Redis SET NX.
|
||||
* Returns true if lock acquired, false if already held.
|
||||
* Requires Redis - throws if Redis is not available.
|
||||
*/
|
||||
export async function acquireLock(
|
||||
lockKey: string,
|
||||
value: string,
|
||||
expirySeconds: number
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
logger.warn('Redis client not available, cannot acquire lock.')
|
||||
// Fallback behavior: maybe allow processing but log a warning?
|
||||
// Or treat as lock acquired if no Redis? Depends on desired behavior.
|
||||
return true // Or false, depending on safety requirements
|
||||
}
|
||||
|
||||
// Use SET key value EX expirySeconds NX
|
||||
// Returns "OK" if successful, null if key already exists (lock held)
|
||||
const result = await redis.set(lockKey, value, 'EX', expirySeconds, 'NX')
|
||||
|
||||
return result === 'OK'
|
||||
} catch (error) {
|
||||
logger.error(`Error acquiring lock for key ${lockKey}:`, { error })
|
||||
// Treat errors as failure to acquire lock for safety
|
||||
return false
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available for distributed locking')
|
||||
}
|
||||
|
||||
const result = await redis.set(lockKey, value, 'EX', expirySeconds, 'NX')
|
||||
return result === 'OK'
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a key from Redis.
|
||||
* @param key The key to retrieve.
|
||||
* @returns The value of the key, or null if the key doesn't exist or an error occurs.
|
||||
* Get the value of a lock key.
|
||||
* Requires Redis - throws if Redis is not available.
|
||||
*/
|
||||
export async function getLockValue(key: string): Promise<string | null> {
|
||||
try {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
logger.warn('Redis client not available, cannot get lock value.')
|
||||
return null // Cannot determine lock value
|
||||
}
|
||||
return await redis.get(key)
|
||||
} catch (error) {
|
||||
logger.error(`Error getting value for key ${key}:`, { error })
|
||||
return null
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available')
|
||||
}
|
||||
|
||||
return redis.get(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a lock by deleting the key.
|
||||
* Ideally, use Lua script for safe release (check value before deleting),
|
||||
* but simple DEL is often sufficient if lock expiry is handled well.
|
||||
* @param lockKey The key of the lock to release.
|
||||
* Release a distributed lock safely.
|
||||
* Only releases if the caller owns the lock (value matches).
|
||||
* Returns true if lock was released, false if not owned or already expired.
|
||||
* Requires Redis - throws if Redis is not available.
|
||||
*/
|
||||
export async function releaseLock(lockKey: string): Promise<void> {
|
||||
try {
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
await redis.del(lockKey)
|
||||
} else {
|
||||
logger.warn('Redis client not available, cannot release lock.')
|
||||
// No fallback needed for releasing if using in-memory cache for locking wasn't implemented
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error releasing lock for key ${lockKey}:`, { error })
|
||||
export async function releaseLock(lockKey: string, value: string): Promise<boolean> {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available for distributed locking')
|
||||
}
|
||||
|
||||
const result = await redis.eval(RELEASE_LOCK_SCRIPT, 1, lockKey, value)
|
||||
return result === 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the Redis connection
|
||||
* Important for proper cleanup in serverless environments
|
||||
* Close the Redis connection.
|
||||
* Use for graceful shutdown.
|
||||
*/
|
||||
export async function closeRedisConnection(): Promise<void> {
|
||||
if (globalRedisClient) {
|
||||
try {
|
||||
await globalRedisClient.quit()
|
||||
} catch (error) {
|
||||
logger.error('Error closing Redis connection:', { error })
|
||||
logger.error('Error closing Redis connection', { error })
|
||||
} finally {
|
||||
globalRedisClient = null
|
||||
}
|
||||
|
||||
@@ -3,45 +3,22 @@ import { db } from '@sim/db'
|
||||
import { idempotencyKey } from '@sim/db/schema'
|
||||
import { and, eq } from 'drizzle-orm'
|
||||
import { getRedisClient } from '@/lib/core/config/redis'
|
||||
import { getStorageMethod, type StorageMethod } from '@/lib/core/storage'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import { extractProviderIdentifierFromBody } from '@/lib/webhooks/provider-utils'
|
||||
|
||||
const logger = createLogger('IdempotencyService')
|
||||
|
||||
export interface IdempotencyConfig {
|
||||
/**
|
||||
* Time-to-live for the idempotency key in seconds
|
||||
* Default: 7 days (604800 seconds)
|
||||
*/
|
||||
ttlSeconds?: number
|
||||
|
||||
/**
|
||||
* Namespace for the idempotency key (e.g., 'gmail', 'webhook', 'trigger')
|
||||
* Default: 'default'
|
||||
*/
|
||||
namespace?: string
|
||||
}
|
||||
|
||||
export interface IdempotencyResult {
|
||||
/**
|
||||
* Whether this is the first time processing this key
|
||||
*/
|
||||
isFirstTime: boolean
|
||||
|
||||
/**
|
||||
* The normalized idempotency key used for storage
|
||||
*/
|
||||
normalizedKey: string
|
||||
|
||||
/**
|
||||
* Previous result if this key was already processed
|
||||
*/
|
||||
previousResult?: any
|
||||
|
||||
/**
|
||||
* Storage method used ('redis', 'database')
|
||||
*/
|
||||
storageMethod: 'redis' | 'database'
|
||||
storageMethod: StorageMethod
|
||||
}
|
||||
|
||||
export interface ProcessingResult {
|
||||
@@ -56,31 +33,37 @@ export interface AtomicClaimResult {
|
||||
claimed: boolean
|
||||
existingResult?: ProcessingResult
|
||||
normalizedKey: string
|
||||
storageMethod: 'redis' | 'database'
|
||||
storageMethod: StorageMethod
|
||||
}
|
||||
|
||||
const DEFAULT_TTL = 60 * 60 * 24 * 7 // 7 days
|
||||
const REDIS_KEY_PREFIX = 'idempotency:'
|
||||
const MAX_WAIT_TIME_MS = 300000 // 5 minutes max wait for in-progress operations
|
||||
const POLL_INTERVAL_MS = 1000 // Check every 1 second for completion
|
||||
const MAX_WAIT_TIME_MS = 300000 // 5 minutes max wait
|
||||
const POLL_INTERVAL_MS = 1000
|
||||
|
||||
/**
|
||||
* Universal idempotency service for webhooks, triggers, and any other operations
|
||||
* that need duplicate prevention.
|
||||
*
|
||||
* Storage is determined once based on configuration:
|
||||
* - If REDIS_URL is set → Redis
|
||||
* - If REDIS_URL is not set → PostgreSQL
|
||||
*/
|
||||
export class IdempotencyService {
|
||||
private config: Required<IdempotencyConfig>
|
||||
private storageMethod: StorageMethod
|
||||
|
||||
constructor(config: IdempotencyConfig = {}) {
|
||||
this.config = {
|
||||
ttlSeconds: config.ttlSeconds ?? DEFAULT_TTL,
|
||||
namespace: config.namespace ?? 'default',
|
||||
}
|
||||
this.storageMethod = getStorageMethod()
|
||||
logger.info(`IdempotencyService using ${this.storageMethod} storage`, {
|
||||
namespace: this.config.namespace,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a normalized idempotency key from various sources
|
||||
*/
|
||||
private normalizeKey(
|
||||
provider: string,
|
||||
identifier: string,
|
||||
@@ -89,7 +72,6 @@ export class IdempotencyService {
|
||||
const base = `${this.config.namespace}:${provider}:${identifier}`
|
||||
|
||||
if (additionalContext && Object.keys(additionalContext).length > 0) {
|
||||
// Sort keys for consistent hashing
|
||||
const sortedKeys = Object.keys(additionalContext).sort()
|
||||
const contextStr = sortedKeys.map((key) => `${key}=${additionalContext[key]}`).join('&')
|
||||
return `${base}:${contextStr}`
|
||||
@@ -98,296 +80,280 @@ export class IdempotencyService {
|
||||
return base
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an operation has already been processed
|
||||
*/
|
||||
async checkIdempotency(
|
||||
provider: string,
|
||||
identifier: string,
|
||||
additionalContext?: Record<string, any>
|
||||
): Promise<IdempotencyResult> {
|
||||
const normalizedKey = this.normalizeKey(provider, identifier, additionalContext)
|
||||
const redisKey = `${REDIS_KEY_PREFIX}${normalizedKey}`
|
||||
|
||||
try {
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
const cachedResult = await redis.get(redisKey)
|
||||
if (cachedResult) {
|
||||
logger.debug(`Idempotency hit in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
isFirstTime: false,
|
||||
normalizedKey,
|
||||
previousResult: JSON.parse(cachedResult),
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
}
|
||||
if (this.storageMethod === 'redis') {
|
||||
return this.checkIdempotencyRedis(normalizedKey)
|
||||
}
|
||||
return this.checkIdempotencyDb(normalizedKey)
|
||||
}
|
||||
|
||||
logger.debug(`Idempotency miss in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
isFirstTime: true,
|
||||
normalizedKey,
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`Redis idempotency check failed for ${normalizedKey}:`, error)
|
||||
private async checkIdempotencyRedis(normalizedKey: string): Promise<IdempotencyResult> {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available for idempotency check')
|
||||
}
|
||||
|
||||
// Always fallback to database when Redis is not available
|
||||
try {
|
||||
const existing = await db
|
||||
.select({ result: idempotencyKey.result, createdAt: idempotencyKey.createdAt })
|
||||
.from(idempotencyKey)
|
||||
.where(
|
||||
and(
|
||||
eq(idempotencyKey.key, normalizedKey),
|
||||
eq(idempotencyKey.namespace, this.config.namespace)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
const redisKey = `${REDIS_KEY_PREFIX}${normalizedKey}`
|
||||
const cachedResult = await redis.get(redisKey)
|
||||
|
||||
if (existing.length > 0) {
|
||||
const item = existing[0]
|
||||
const isExpired = Date.now() - item.createdAt.getTime() > this.config.ttlSeconds * 1000
|
||||
|
||||
if (!isExpired) {
|
||||
logger.debug(`Idempotency hit in database: ${normalizedKey}`)
|
||||
return {
|
||||
isFirstTime: false,
|
||||
normalizedKey,
|
||||
previousResult: item.result,
|
||||
storageMethod: 'database',
|
||||
}
|
||||
}
|
||||
await db
|
||||
.delete(idempotencyKey)
|
||||
.where(eq(idempotencyKey.key, normalizedKey))
|
||||
.catch((err) => logger.warn(`Failed to clean up expired key ${normalizedKey}:`, err))
|
||||
}
|
||||
|
||||
logger.debug(`Idempotency miss in database: ${normalizedKey}`)
|
||||
if (cachedResult) {
|
||||
logger.debug(`Idempotency hit in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
isFirstTime: true,
|
||||
isFirstTime: false,
|
||||
normalizedKey,
|
||||
storageMethod: 'database',
|
||||
previousResult: JSON.parse(cachedResult),
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Database idempotency check failed for ${normalizedKey}:`, error)
|
||||
throw new Error(`Failed to check idempotency: database unavailable`)
|
||||
}
|
||||
|
||||
logger.debug(`Idempotency miss in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
isFirstTime: true,
|
||||
normalizedKey,
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
}
|
||||
|
||||
private async checkIdempotencyDb(normalizedKey: string): Promise<IdempotencyResult> {
|
||||
const existing = await db
|
||||
.select({ result: idempotencyKey.result, createdAt: idempotencyKey.createdAt })
|
||||
.from(idempotencyKey)
|
||||
.where(
|
||||
and(
|
||||
eq(idempotencyKey.key, normalizedKey),
|
||||
eq(idempotencyKey.namespace, this.config.namespace)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
|
||||
if (existing.length > 0) {
|
||||
const item = existing[0]
|
||||
const isExpired = Date.now() - item.createdAt.getTime() > this.config.ttlSeconds * 1000
|
||||
|
||||
if (!isExpired) {
|
||||
logger.debug(`Idempotency hit in database: ${normalizedKey}`)
|
||||
return {
|
||||
isFirstTime: false,
|
||||
normalizedKey,
|
||||
previousResult: item.result,
|
||||
storageMethod: 'database',
|
||||
}
|
||||
}
|
||||
|
||||
await db
|
||||
.delete(idempotencyKey)
|
||||
.where(eq(idempotencyKey.key, normalizedKey))
|
||||
.catch((err) => logger.warn(`Failed to clean up expired key ${normalizedKey}:`, err))
|
||||
}
|
||||
|
||||
logger.debug(`Idempotency miss in database: ${normalizedKey}`)
|
||||
return {
|
||||
isFirstTime: true,
|
||||
normalizedKey,
|
||||
storageMethod: 'database',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically claim an idempotency key for processing
|
||||
* Returns true if successfully claimed, false if already exists
|
||||
*/
|
||||
async atomicallyClaim(
|
||||
provider: string,
|
||||
identifier: string,
|
||||
additionalContext?: Record<string, any>
|
||||
): Promise<AtomicClaimResult> {
|
||||
const normalizedKey = this.normalizeKey(provider, identifier, additionalContext)
|
||||
const redisKey = `${REDIS_KEY_PREFIX}${normalizedKey}`
|
||||
const inProgressResult: ProcessingResult = {
|
||||
success: false,
|
||||
status: 'in-progress',
|
||||
startedAt: Date.now(),
|
||||
}
|
||||
|
||||
try {
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
const claimed = await redis.set(
|
||||
redisKey,
|
||||
JSON.stringify(inProgressResult),
|
||||
'EX',
|
||||
this.config.ttlSeconds,
|
||||
'NX'
|
||||
)
|
||||
if (this.storageMethod === 'redis') {
|
||||
return this.atomicallyClaimRedis(normalizedKey, inProgressResult)
|
||||
}
|
||||
return this.atomicallyClaimDb(normalizedKey, inProgressResult)
|
||||
}
|
||||
|
||||
if (claimed === 'OK') {
|
||||
logger.debug(`Atomically claimed idempotency key in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
claimed: true,
|
||||
normalizedKey,
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
}
|
||||
const existingData = await redis.get(redisKey)
|
||||
const existingResult = existingData ? JSON.parse(existingData) : null
|
||||
logger.debug(`Idempotency key already claimed in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
claimed: false,
|
||||
existingResult,
|
||||
normalizedKey,
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`Redis atomic claim failed for ${normalizedKey}:`, error)
|
||||
private async atomicallyClaimRedis(
|
||||
normalizedKey: string,
|
||||
inProgressResult: ProcessingResult
|
||||
): Promise<AtomicClaimResult> {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available for atomic claim')
|
||||
}
|
||||
|
||||
// Always fallback to database when Redis is not available
|
||||
try {
|
||||
const insertResult = await db
|
||||
.insert(idempotencyKey)
|
||||
.values({
|
||||
key: normalizedKey,
|
||||
namespace: this.config.namespace,
|
||||
result: inProgressResult,
|
||||
createdAt: new Date(),
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.returning({ key: idempotencyKey.key })
|
||||
const redisKey = `${REDIS_KEY_PREFIX}${normalizedKey}`
|
||||
const claimed = await redis.set(
|
||||
redisKey,
|
||||
JSON.stringify(inProgressResult),
|
||||
'EX',
|
||||
this.config.ttlSeconds,
|
||||
'NX'
|
||||
)
|
||||
|
||||
if (insertResult.length > 0) {
|
||||
logger.debug(`Atomically claimed idempotency key in database: ${normalizedKey}`)
|
||||
return {
|
||||
claimed: true,
|
||||
normalizedKey,
|
||||
storageMethod: 'database',
|
||||
}
|
||||
}
|
||||
const existing = await db
|
||||
.select({ result: idempotencyKey.result })
|
||||
.from(idempotencyKey)
|
||||
.where(
|
||||
and(
|
||||
eq(idempotencyKey.key, normalizedKey),
|
||||
eq(idempotencyKey.namespace, this.config.namespace)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
|
||||
const existingResult =
|
||||
existing.length > 0 ? (existing[0].result as ProcessingResult) : undefined
|
||||
logger.debug(`Idempotency key already claimed in database: ${normalizedKey}`)
|
||||
if (claimed === 'OK') {
|
||||
logger.debug(`Atomically claimed idempotency key in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
claimed: false,
|
||||
existingResult,
|
||||
claimed: true,
|
||||
normalizedKey,
|
||||
storageMethod: 'database',
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Database atomic claim failed for ${normalizedKey}:`, error)
|
||||
throw new Error(`Failed to claim idempotency key: database unavailable`)
|
||||
}
|
||||
|
||||
const existingData = await redis.get(redisKey)
|
||||
const existingResult = existingData ? JSON.parse(existingData) : null
|
||||
logger.debug(`Idempotency key already claimed in Redis: ${normalizedKey}`)
|
||||
return {
|
||||
claimed: false,
|
||||
existingResult,
|
||||
normalizedKey,
|
||||
storageMethod: 'redis',
|
||||
}
|
||||
}
|
||||
|
||||
private async atomicallyClaimDb(
|
||||
normalizedKey: string,
|
||||
inProgressResult: ProcessingResult
|
||||
): Promise<AtomicClaimResult> {
|
||||
const insertResult = await db
|
||||
.insert(idempotencyKey)
|
||||
.values({
|
||||
key: normalizedKey,
|
||||
namespace: this.config.namespace,
|
||||
result: inProgressResult,
|
||||
createdAt: new Date(),
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.returning({ key: idempotencyKey.key })
|
||||
|
||||
if (insertResult.length > 0) {
|
||||
logger.debug(`Atomically claimed idempotency key in database: ${normalizedKey}`)
|
||||
return {
|
||||
claimed: true,
|
||||
normalizedKey,
|
||||
storageMethod: 'database',
|
||||
}
|
||||
}
|
||||
|
||||
const existing = await db
|
||||
.select({ result: idempotencyKey.result })
|
||||
.from(idempotencyKey)
|
||||
.where(
|
||||
and(
|
||||
eq(idempotencyKey.key, normalizedKey),
|
||||
eq(idempotencyKey.namespace, this.config.namespace)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
|
||||
const existingResult =
|
||||
existing.length > 0 ? (existing[0].result as ProcessingResult) : undefined
|
||||
logger.debug(`Idempotency key already claimed in database: ${normalizedKey}`)
|
||||
return {
|
||||
claimed: false,
|
||||
existingResult,
|
||||
normalizedKey,
|
||||
storageMethod: 'database',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for an in-progress operation to complete and return its result
|
||||
*/
|
||||
async waitForResult<T>(normalizedKey: string, storageMethod: 'redis' | 'database'): Promise<T> {
|
||||
const startTime = Date.now()
|
||||
const redisKey = `${REDIS_KEY_PREFIX}${normalizedKey}`
|
||||
|
||||
while (Date.now() - startTime < MAX_WAIT_TIME_MS) {
|
||||
try {
|
||||
let currentResult: ProcessingResult | null = null
|
||||
let currentResult: ProcessingResult | null = null
|
||||
|
||||
if (storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
const data = await redis.get(redisKey)
|
||||
currentResult = data ? JSON.parse(data) : null
|
||||
}
|
||||
} else if (storageMethod === 'database') {
|
||||
const existing = await db
|
||||
.select({ result: idempotencyKey.result })
|
||||
.from(idempotencyKey)
|
||||
.where(
|
||||
and(
|
||||
eq(idempotencyKey.key, normalizedKey),
|
||||
eq(idempotencyKey.namespace, this.config.namespace)
|
||||
)
|
||||
if (storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available')
|
||||
}
|
||||
const data = await redis.get(redisKey)
|
||||
currentResult = data ? JSON.parse(data) : null
|
||||
} else {
|
||||
const existing = await db
|
||||
.select({ result: idempotencyKey.result })
|
||||
.from(idempotencyKey)
|
||||
.where(
|
||||
and(
|
||||
eq(idempotencyKey.key, normalizedKey),
|
||||
eq(idempotencyKey.namespace, this.config.namespace)
|
||||
)
|
||||
.limit(1)
|
||||
currentResult = existing.length > 0 ? (existing[0].result as ProcessingResult) : null
|
||||
}
|
||||
)
|
||||
.limit(1)
|
||||
currentResult = existing.length > 0 ? (existing[0].result as ProcessingResult) : null
|
||||
}
|
||||
|
||||
if (currentResult?.status === 'completed') {
|
||||
logger.debug(`Operation completed, returning result: ${normalizedKey}`)
|
||||
if (currentResult.success === false) {
|
||||
throw new Error(currentResult.error || 'Previous operation failed')
|
||||
}
|
||||
return currentResult.result as T
|
||||
}
|
||||
|
||||
if (currentResult?.status === 'failed') {
|
||||
logger.debug(`Operation failed, throwing error: ${normalizedKey}`)
|
||||
if (currentResult?.status === 'completed') {
|
||||
logger.debug(`Operation completed, returning result: ${normalizedKey}`)
|
||||
if (currentResult.success === false) {
|
||||
throw new Error(currentResult.error || 'Previous operation failed')
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message.includes('operation failed')) {
|
||||
throw error
|
||||
}
|
||||
logger.warn(`Error while waiting for result ${normalizedKey}:`, error)
|
||||
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
|
||||
return currentResult.result as T
|
||||
}
|
||||
|
||||
if (currentResult?.status === 'failed') {
|
||||
logger.debug(`Operation failed, throwing error: ${normalizedKey}`)
|
||||
throw new Error(currentResult.error || 'Previous operation failed')
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
|
||||
}
|
||||
|
||||
throw new Error(`Timeout waiting for idempotency operation to complete: ${normalizedKey}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the result of processing for future idempotency checks
|
||||
*/
|
||||
async storeResult(
|
||||
normalizedKey: string,
|
||||
result: ProcessingResult,
|
||||
storageMethod: 'redis' | 'database'
|
||||
): Promise<void> {
|
||||
const serializedResult = JSON.stringify(result)
|
||||
|
||||
try {
|
||||
if (storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
await redis.setex(
|
||||
`${REDIS_KEY_PREFIX}${normalizedKey}`,
|
||||
this.config.ttlSeconds,
|
||||
serializedResult
|
||||
)
|
||||
logger.debug(`Stored idempotency result in Redis: ${normalizedKey}`)
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to store result in Redis for ${normalizedKey}:`, error)
|
||||
}
|
||||
|
||||
// Always fallback to database when Redis is not available
|
||||
try {
|
||||
await db
|
||||
.insert(idempotencyKey)
|
||||
.values({
|
||||
key: normalizedKey,
|
||||
namespace: this.config.namespace,
|
||||
result: result,
|
||||
createdAt: new Date(),
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: [idempotencyKey.key, idempotencyKey.namespace],
|
||||
set: {
|
||||
result: result,
|
||||
createdAt: new Date(),
|
||||
},
|
||||
})
|
||||
|
||||
logger.debug(`Stored idempotency result in database: ${normalizedKey}`)
|
||||
} catch (error) {
|
||||
logger.error(`Failed to store result in database for ${normalizedKey}:`, error)
|
||||
throw new Error(`Failed to store idempotency result: database unavailable`)
|
||||
if (storageMethod === 'redis') {
|
||||
return this.storeResultRedis(normalizedKey, result)
|
||||
}
|
||||
return this.storeResultDb(normalizedKey, result)
|
||||
}
|
||||
|
||||
private async storeResultRedis(normalizedKey: string, result: ProcessingResult): Promise<void> {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis not available for storing result')
|
||||
}
|
||||
|
||||
await redis.setex(
|
||||
`${REDIS_KEY_PREFIX}${normalizedKey}`,
|
||||
this.config.ttlSeconds,
|
||||
JSON.stringify(result)
|
||||
)
|
||||
logger.debug(`Stored idempotency result in Redis: ${normalizedKey}`)
|
||||
}
|
||||
|
||||
private async storeResultDb(normalizedKey: string, result: ProcessingResult): Promise<void> {
|
||||
await db
|
||||
.insert(idempotencyKey)
|
||||
.values({
|
||||
key: normalizedKey,
|
||||
namespace: this.config.namespace,
|
||||
result: result,
|
||||
createdAt: new Date(),
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: [idempotencyKey.key, idempotencyKey.namespace],
|
||||
set: {
|
||||
result: result,
|
||||
createdAt: new Date(),
|
||||
},
|
||||
})
|
||||
|
||||
logger.debug(`Stored idempotency result in database: ${normalizedKey}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an operation with idempotency protection using atomic claims
|
||||
* Eliminates race conditions by claiming the key before execution
|
||||
*/
|
||||
async executeWithIdempotency<T>(
|
||||
provider: string,
|
||||
identifier: string,
|
||||
@@ -450,16 +416,6 @@ export class IdempotencyService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an idempotency key from a webhook payload following RFC best practices
|
||||
* Checks both headers and body for unique identifiers to prevent duplicate executions
|
||||
*
|
||||
* @param webhookId - The webhook database ID
|
||||
* @param headers - HTTP headers from the webhook request
|
||||
* @param body - Parsed webhook body (optional, used for provider-specific identifiers)
|
||||
* @param provider - Provider name for body extraction (optional)
|
||||
* @returns A unique idempotency key for this webhook event
|
||||
*/
|
||||
static createWebhookIdempotencyKey(
|
||||
webhookId: string,
|
||||
headers?: Record<string, string>,
|
||||
@@ -470,7 +426,6 @@ export class IdempotencyService {
|
||||
? Object.fromEntries(Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]))
|
||||
: undefined
|
||||
|
||||
// Check standard webhook headers first
|
||||
const webhookIdHeader =
|
||||
normalizedHeaders?.['webhook-id'] ||
|
||||
normalizedHeaders?.['x-webhook-id'] ||
|
||||
@@ -483,17 +438,13 @@ export class IdempotencyService {
|
||||
return `${webhookId}:${webhookIdHeader}`
|
||||
}
|
||||
|
||||
// Check body for provider-specific unique identifiers
|
||||
if (body && provider) {
|
||||
const bodyIdentifier = extractProviderIdentifierFromBody(provider, body)
|
||||
|
||||
if (bodyIdentifier) {
|
||||
return `${webhookId}:${bodyIdentifier}`
|
||||
}
|
||||
}
|
||||
|
||||
// No unique identifier found - generate random UUID
|
||||
// This means duplicate detection will not work for this webhook
|
||||
const uniqueId = randomUUID()
|
||||
logger.warn('No unique identifier found, duplicate executions may occur', {
|
||||
webhookId,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getRedisClient } from '@/lib/core/config/redis'
|
||||
import { getStorageMethod, type StorageMethod } from '@/lib/core/storage'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import type { RateLimitStorageAdapter } from './adapter'
|
||||
import { DbTokenBucket } from './db-token-bucket'
|
||||
@@ -13,18 +14,27 @@ export function createStorageAdapter(): RateLimitStorageAdapter {
|
||||
return cachedAdapter
|
||||
}
|
||||
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
logger.info('Using Redis for rate limiting')
|
||||
const storageMethod = getStorageMethod()
|
||||
|
||||
if (storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis configured but client unavailable')
|
||||
}
|
||||
logger.info('Rate limiting: Using Redis')
|
||||
cachedAdapter = new RedisTokenBucket(redis)
|
||||
} else {
|
||||
logger.info('Using PostgreSQL for rate limiting')
|
||||
logger.info('Rate limiting: Using PostgreSQL')
|
||||
cachedAdapter = new DbTokenBucket()
|
||||
}
|
||||
|
||||
return cachedAdapter
|
||||
}
|
||||
|
||||
export function getAdapterType(): StorageMethod {
|
||||
return getStorageMethod()
|
||||
}
|
||||
|
||||
export function resetStorageAdapter(): void {
|
||||
cachedAdapter = null
|
||||
}
|
||||
|
||||
@@ -5,5 +5,10 @@ export type {
|
||||
TokenStatus,
|
||||
} from './adapter'
|
||||
export { DbTokenBucket } from './db-token-bucket'
|
||||
export { createStorageAdapter, resetStorageAdapter, setStorageAdapter } from './factory'
|
||||
export {
|
||||
createStorageAdapter,
|
||||
getAdapterType,
|
||||
resetStorageAdapter,
|
||||
setStorageAdapter,
|
||||
} from './factory'
|
||||
export { RedisTokenBucket } from './redis-token-bucket'
|
||||
|
||||
8
apps/sim/lib/core/storage/index.ts
Normal file
8
apps/sim/lib/core/storage/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export {
|
||||
getStorageMethod,
|
||||
isDatabaseStorage,
|
||||
isRedisStorage,
|
||||
requireRedis,
|
||||
resetStorageMethod,
|
||||
type StorageMethod,
|
||||
} from './storage'
|
||||
79
apps/sim/lib/core/storage/storage.ts
Normal file
79
apps/sim/lib/core/storage/storage.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { getRedisClient } from '@/lib/core/config/redis'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
|
||||
const logger = createLogger('Storage')
|
||||
|
||||
export type StorageMethod = 'redis' | 'database'
|
||||
|
||||
let cachedStorageMethod: StorageMethod | null = null
|
||||
|
||||
/**
|
||||
* Determine the storage method once based on configuration.
|
||||
* This decision is made at first call and cached for the lifetime of the process.
|
||||
*
|
||||
* - If REDIS_URL is configured and client initializes → 'redis'
|
||||
* - If REDIS_URL is not configured → 'database'
|
||||
*
|
||||
* Transient failures do NOT change the storage method.
|
||||
* If Redis is configured but fails, operations will fail (not fallback to DB).
|
||||
*/
|
||||
export function getStorageMethod(): StorageMethod {
|
||||
if (cachedStorageMethod) {
|
||||
return cachedStorageMethod
|
||||
}
|
||||
|
||||
const redis = getRedisClient()
|
||||
|
||||
if (redis) {
|
||||
cachedStorageMethod = 'redis'
|
||||
logger.info('Storage method: Redis')
|
||||
} else {
|
||||
cachedStorageMethod = 'database'
|
||||
logger.info('Storage method: PostgreSQL')
|
||||
}
|
||||
|
||||
return cachedStorageMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Redis is the configured storage method.
|
||||
* Use this for conditional logic that depends on storage type.
|
||||
*/
|
||||
export function isRedisStorage(): boolean {
|
||||
return getStorageMethod() === 'redis'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if database is the configured storage method.
|
||||
*/
|
||||
export function isDatabaseStorage(): boolean {
|
||||
return getStorageMethod() === 'database'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Redis client, but only if Redis is the configured storage method.
|
||||
* Throws if Redis is configured but client is unavailable.
|
||||
*
|
||||
* Use this instead of getRedisClient() directly when you need to ensure
|
||||
* consistency with the storage method decision.
|
||||
*/
|
||||
export function requireRedis() {
|
||||
if (!isRedisStorage()) {
|
||||
throw new Error('Redis storage not configured')
|
||||
}
|
||||
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis client unavailable')
|
||||
}
|
||||
|
||||
return redis
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cached storage method.
|
||||
* Only use for testing purposes.
|
||||
*/
|
||||
export function resetStorageMethod(): void {
|
||||
cachedStorageMethod = null
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getRedisClient } from '@/lib/core/config/redis'
|
||||
import { getStorageMethod, type StorageMethod } from '@/lib/core/storage'
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
|
||||
const logger = createLogger('DocumentQueue')
|
||||
@@ -18,20 +19,23 @@ interface QueueConfig {
|
||||
maxRetries: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Document processing queue that uses either Redis or in-memory storage.
|
||||
* Storage method is determined once at construction based on configuration.
|
||||
* No switching on transient errors.
|
||||
*/
|
||||
export class DocumentProcessingQueue {
|
||||
private config: QueueConfig
|
||||
private storageMethod: StorageMethod
|
||||
private processing = new Map<string, Promise<void>>()
|
||||
private fallbackQueue: QueueJob[] = []
|
||||
private fallbackProcessing = 0
|
||||
private inMemoryQueue: QueueJob[] = []
|
||||
private inMemoryProcessing = 0
|
||||
private processingStarted = false
|
||||
|
||||
constructor(config: QueueConfig) {
|
||||
this.config = config
|
||||
}
|
||||
|
||||
private isRedisAvailable(): boolean {
|
||||
const redis = getRedisClient()
|
||||
return redis !== null
|
||||
this.storageMethod = getStorageMethod()
|
||||
logger.info(`DocumentProcessingQueue using ${this.storageMethod} storage`)
|
||||
}
|
||||
|
||||
async addJob<T>(type: string, data: T, options: { maxAttempts?: number } = {}): Promise<string> {
|
||||
@@ -44,20 +48,18 @@ export class DocumentProcessingQueue {
|
||||
maxAttempts: options.maxAttempts || this.config.maxRetries,
|
||||
}
|
||||
|
||||
if (this.isRedisAvailable()) {
|
||||
try {
|
||||
const redis = getRedisClient()!
|
||||
await redis.lpush('document-queue', JSON.stringify(job))
|
||||
logger.info(`Job ${job.id} added to Redis queue`)
|
||||
return job.id
|
||||
} catch (error) {
|
||||
logger.warn('Failed to add job to Redis, using fallback:', error)
|
||||
if (this.storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
throw new Error('Redis configured but client unavailable')
|
||||
}
|
||||
await redis.lpush('document-queue', JSON.stringify(job))
|
||||
logger.info(`Job ${job.id} added to Redis queue`)
|
||||
} else {
|
||||
this.inMemoryQueue.push(job)
|
||||
logger.info(`Job ${job.id} added to in-memory queue`)
|
||||
}
|
||||
|
||||
// Fallback to in-memory queue
|
||||
this.fallbackQueue.push(job)
|
||||
logger.info(`Job ${job.id} added to in-memory fallback queue`)
|
||||
return job.id
|
||||
}
|
||||
|
||||
@@ -68,121 +70,86 @@ export class DocumentProcessingQueue {
|
||||
}
|
||||
|
||||
this.processingStarted = true
|
||||
logger.info('Starting queue processing')
|
||||
logger.info(`Starting queue processing (${this.storageMethod})`)
|
||||
|
||||
if (this.isRedisAvailable()) {
|
||||
if (this.storageMethod === 'redis') {
|
||||
await this.processRedisJobs(processor)
|
||||
} else {
|
||||
await this.processFallbackJobs(processor)
|
||||
await this.processInMemoryJobs(processor)
|
||||
}
|
||||
}
|
||||
|
||||
private async processRedisJobs(processor: (job: QueueJob) => Promise<void>) {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
logger.warn('Redis client not available, falling back to in-memory processing')
|
||||
await this.processFallbackJobs(processor)
|
||||
return
|
||||
throw new Error('Redis configured but client unavailable')
|
||||
}
|
||||
|
||||
const processJobsContinuously = async () => {
|
||||
let consecutiveErrors = 0
|
||||
while (true) {
|
||||
if (this.processing.size >= this.config.maxConcurrent) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100)) // Wait before checking again
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
const currentRedis = getRedisClient()
|
||||
if (!currentRedis) {
|
||||
logger.warn('Redis connection lost, switching to fallback processing')
|
||||
await this.processFallbackJobs(processor)
|
||||
return
|
||||
const result = await redis.rpop('document-queue')
|
||||
if (!result) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
continue
|
||||
}
|
||||
|
||||
const result = await currentRedis.brpop('document-queue', 1)
|
||||
if (!result || !result[1]) {
|
||||
consecutiveErrors = 0 // Reset error counter on successful operation
|
||||
continue // Continue polling for jobs
|
||||
}
|
||||
|
||||
const job: QueueJob = JSON.parse(result[1])
|
||||
const job: QueueJob = JSON.parse(result)
|
||||
const promise = this.executeJob(job, processor)
|
||||
this.processing.set(job.id, promise)
|
||||
|
||||
promise.finally(() => {
|
||||
this.processing.delete(job.id)
|
||||
})
|
||||
|
||||
consecutiveErrors = 0 // Reset error counter on success
|
||||
// Don't await here - let it process in background while we get next job
|
||||
} catch (error: any) {
|
||||
consecutiveErrors++
|
||||
|
||||
if (
|
||||
error.message?.includes('Connection is closed') ||
|
||||
error.message?.includes('ECONNREFUSED') ||
|
||||
error.code === 'ECONNREFUSED' ||
|
||||
consecutiveErrors >= 5
|
||||
) {
|
||||
logger.warn(
|
||||
`Redis connection failed (${consecutiveErrors} consecutive errors), switching to fallback processing:`,
|
||||
error.message
|
||||
)
|
||||
await this.processFallbackJobs(processor)
|
||||
return
|
||||
}
|
||||
|
||||
logger.error('Error processing Redis job:', error)
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, Math.min(1000 * consecutiveErrors, 5000))
|
||||
) // Exponential backoff
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start multiple concurrent processors that run continuously
|
||||
const processors = Array(this.config.maxConcurrent)
|
||||
.fill(null)
|
||||
.map(() => processJobsContinuously())
|
||||
|
||||
// Don't await - let processors run in background
|
||||
Promise.allSettled(processors).catch((error) => {
|
||||
logger.error('Error in Redis queue processors:', error)
|
||||
})
|
||||
}
|
||||
|
||||
private async processFallbackJobs(processor: (job: QueueJob) => Promise<void>) {
|
||||
const processFallbackContinuously = async () => {
|
||||
private async processInMemoryJobs(processor: (job: QueueJob) => Promise<void>) {
|
||||
const processInMemoryContinuously = async () => {
|
||||
while (true) {
|
||||
if (this.fallbackProcessing >= this.config.maxConcurrent) {
|
||||
if (this.inMemoryProcessing >= this.config.maxConcurrent) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
continue
|
||||
}
|
||||
|
||||
const job = this.fallbackQueue.shift()
|
||||
const job = this.inMemoryQueue.shift()
|
||||
if (!job) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500)) // Wait for new jobs
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
continue
|
||||
}
|
||||
|
||||
this.fallbackProcessing++
|
||||
this.inMemoryProcessing++
|
||||
|
||||
this.executeJob(job, processor).finally(() => {
|
||||
this.fallbackProcessing--
|
||||
this.inMemoryProcessing--
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Start multiple concurrent processors for fallback queue
|
||||
const processors = Array(this.config.maxConcurrent)
|
||||
.fill(null)
|
||||
.map(() => processFallbackContinuously())
|
||||
.map(() => processInMemoryContinuously())
|
||||
|
||||
// Don't await - let processors run in background
|
||||
Promise.allSettled(processors).catch((error) => {
|
||||
logger.error('Error in fallback queue processors:', error)
|
||||
logger.error('Error in in-memory queue processors:', error)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -200,20 +167,18 @@ export class DocumentProcessingQueue {
|
||||
logger.error(`Job ${job.id} failed (attempt ${job.attempts}):`, error)
|
||||
|
||||
if (job.attempts < job.maxAttempts) {
|
||||
// Retry logic with exponential backoff
|
||||
const delay = this.config.retryDelay * 2 ** (job.attempts - 1)
|
||||
|
||||
setTimeout(async () => {
|
||||
if (this.isRedisAvailable()) {
|
||||
try {
|
||||
const redis = getRedisClient()!
|
||||
await redis.lpush('document-queue', JSON.stringify(job))
|
||||
} catch (retryError) {
|
||||
logger.warn('Failed to requeue job to Redis, using fallback:', retryError)
|
||||
this.fallbackQueue.push(job)
|
||||
if (this.storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (!redis) {
|
||||
logger.error('Redis unavailable for retry, job lost:', job.id)
|
||||
return
|
||||
}
|
||||
await redis.lpush('document-queue', JSON.stringify(job))
|
||||
} else {
|
||||
this.fallbackQueue.push(job)
|
||||
this.inMemoryQueue.push(job)
|
||||
}
|
||||
}, delay)
|
||||
|
||||
@@ -224,41 +189,39 @@ export class DocumentProcessingQueue {
|
||||
}
|
||||
}
|
||||
|
||||
async getQueueStats(): Promise<{ pending: number; processing: number; redisAvailable: boolean }> {
|
||||
async getQueueStats(): Promise<{
|
||||
pending: number
|
||||
processing: number
|
||||
storageMethod: StorageMethod
|
||||
}> {
|
||||
let pending = 0
|
||||
const redisAvailable = this.isRedisAvailable()
|
||||
|
||||
if (redisAvailable) {
|
||||
try {
|
||||
const redis = getRedisClient()!
|
||||
if (this.storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
pending = await redis.llen('document-queue')
|
||||
} catch (error) {
|
||||
logger.warn('Failed to get Redis queue stats:', error)
|
||||
pending = this.fallbackQueue.length
|
||||
}
|
||||
} else {
|
||||
pending = this.fallbackQueue.length
|
||||
pending = this.inMemoryQueue.length
|
||||
}
|
||||
|
||||
return {
|
||||
pending,
|
||||
processing: redisAvailable ? this.processing.size : this.fallbackProcessing,
|
||||
redisAvailable,
|
||||
processing: this.storageMethod === 'redis' ? this.processing.size : this.inMemoryProcessing,
|
||||
storageMethod: this.storageMethod,
|
||||
}
|
||||
}
|
||||
|
||||
async clearQueue(): Promise<void> {
|
||||
if (this.isRedisAvailable()) {
|
||||
try {
|
||||
const redis = getRedisClient()!
|
||||
if (this.storageMethod === 'redis') {
|
||||
const redis = getRedisClient()
|
||||
if (redis) {
|
||||
await redis.del('document-queue')
|
||||
logger.info('Redis queue cleared')
|
||||
} catch (error) {
|
||||
logger.error('Failed to clear Redis queue:', error)
|
||||
}
|
||||
}
|
||||
|
||||
this.fallbackQueue.length = 0
|
||||
logger.info('Fallback queue cleared')
|
||||
this.inMemoryQueue.length = 0
|
||||
logger.info('In-memory queue cleared')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { document, embedding, knowledgeBase, knowledgeBaseTagDefinitions } from
|
||||
import { tasks } from '@trigger.dev/sdk'
|
||||
import { and, asc, desc, eq, inArray, isNull, sql } from 'drizzle-orm'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { getRedisClient } from '@/lib/core/config/redis'
|
||||
import { getStorageMethod, isRedisStorage } from '@/lib/core/storage'
|
||||
import { getSlotsForFieldType, type TAG_SLOT_CONFIG } from '@/lib/knowledge/constants'
|
||||
import { processDocument } from '@/lib/knowledge/documents/document-processor'
|
||||
import { DocumentProcessingQueue } from '@/lib/knowledge/documents/queue'
|
||||
@@ -63,8 +63,7 @@ let documentQueue: DocumentProcessingQueue | null = null
|
||||
|
||||
export function getDocumentQueue(): DocumentProcessingQueue {
|
||||
if (!documentQueue) {
|
||||
const redisClient = getRedisClient()
|
||||
const config = redisClient ? REDIS_PROCESSING_CONFIG : PROCESSING_CONFIG
|
||||
const config = isRedisStorage() ? REDIS_PROCESSING_CONFIG : PROCESSING_CONFIG
|
||||
documentQueue = new DocumentProcessingQueue({
|
||||
maxConcurrent: config.maxConcurrentDocuments,
|
||||
retryDelay: env.KB_CONFIG_MIN_TIMEOUT || 1000,
|
||||
@@ -75,8 +74,7 @@ export function getDocumentQueue(): DocumentProcessingQueue {
|
||||
}
|
||||
|
||||
export function getProcessingConfig() {
|
||||
const redisClient = getRedisClient()
|
||||
return redisClient ? REDIS_PROCESSING_CONFIG : PROCESSING_CONFIG
|
||||
return isRedisStorage() ? REDIS_PROCESSING_CONFIG : PROCESSING_CONFIG
|
||||
}
|
||||
|
||||
export interface DocumentData {
|
||||
@@ -240,174 +238,43 @@ export async function processDocumentsWithQueue(
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 2: Redis queue
|
||||
// Priority 2: Queue-based processing (Redis or in-memory based on storage method)
|
||||
const queue = getDocumentQueue()
|
||||
const redisClient = getRedisClient()
|
||||
const storageMethod = getStorageMethod()
|
||||
|
||||
if (redisClient) {
|
||||
try {
|
||||
logger.info(`[${requestId}] Using Redis queue for ${createdDocuments.length} documents`)
|
||||
|
||||
const jobPromises = createdDocuments.map((doc) =>
|
||||
queue.addJob<DocumentJobData>('process-document', {
|
||||
knowledgeBaseId,
|
||||
documentId: doc.documentId,
|
||||
docData: {
|
||||
filename: doc.filename,
|
||||
fileUrl: doc.fileUrl,
|
||||
fileSize: doc.fileSize,
|
||||
mimeType: doc.mimeType,
|
||||
},
|
||||
processingOptions,
|
||||
requestId,
|
||||
})
|
||||
)
|
||||
|
||||
await Promise.all(jobPromises)
|
||||
|
||||
// Start Redis background processing
|
||||
queue
|
||||
.processJobs(async (job) => {
|
||||
const data = job.data as DocumentJobData
|
||||
const { knowledgeBaseId, documentId, docData, processingOptions } = data
|
||||
await processDocumentAsync(knowledgeBaseId, documentId, docData, processingOptions)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`[${requestId}] Error in Redis queue processing:`, error)
|
||||
})
|
||||
|
||||
logger.info(`[${requestId}] All documents queued for Redis processing`)
|
||||
return
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] Redis queue failed, falling back to in-memory processing:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 3: In-memory processing
|
||||
logger.info(
|
||||
`[${requestId}] Using fallback in-memory processing (neither Trigger.dev nor Redis available)`
|
||||
`[${requestId}] Using ${storageMethod} queue for ${createdDocuments.length} documents`
|
||||
)
|
||||
await processDocumentsWithConcurrencyControl(
|
||||
createdDocuments,
|
||||
knowledgeBaseId,
|
||||
processingOptions,
|
||||
requestId
|
||||
|
||||
const jobPromises = createdDocuments.map((doc) =>
|
||||
queue.addJob<DocumentJobData>('process-document', {
|
||||
knowledgeBaseId,
|
||||
documentId: doc.documentId,
|
||||
docData: {
|
||||
filename: doc.filename,
|
||||
fileUrl: doc.fileUrl,
|
||||
fileSize: doc.fileSize,
|
||||
mimeType: doc.mimeType,
|
||||
},
|
||||
processingOptions,
|
||||
requestId,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Original concurrency control processing (fallback when Redis not available)
|
||||
*/
|
||||
async function processDocumentsWithConcurrencyControl(
|
||||
createdDocuments: DocumentData[],
|
||||
knowledgeBaseId: string,
|
||||
processingOptions: ProcessingOptions,
|
||||
requestId: string
|
||||
): Promise<void> {
|
||||
const totalDocuments = createdDocuments.length
|
||||
const batches = []
|
||||
await Promise.all(jobPromises)
|
||||
|
||||
for (let i = 0; i < totalDocuments; i += PROCESSING_CONFIG.batchSize) {
|
||||
batches.push(createdDocuments.slice(i, i + PROCESSING_CONFIG.batchSize))
|
||||
}
|
||||
|
||||
logger.info(`[${requestId}] Processing ${totalDocuments} documents in ${batches.length} batches`)
|
||||
|
||||
for (const [batchIndex, batch] of batches.entries()) {
|
||||
logger.info(
|
||||
`[${requestId}] Starting batch ${batchIndex + 1}/${batches.length} with ${batch.length} documents`
|
||||
)
|
||||
|
||||
await processBatchWithConcurrency(batch, knowledgeBaseId, processingOptions, requestId)
|
||||
|
||||
if (batchIndex < batches.length - 1) {
|
||||
const config = getProcessingConfig()
|
||||
if (config.delayBetweenBatches > 0) {
|
||||
await new Promise((resolve) => setTimeout(resolve, config.delayBetweenBatches))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`[${requestId}] Completed processing initiation for all ${totalDocuments} documents`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a batch of documents with concurrency control using semaphore
|
||||
*/
|
||||
async function processBatchWithConcurrency(
|
||||
batch: DocumentData[],
|
||||
knowledgeBaseId: string,
|
||||
processingOptions: ProcessingOptions,
|
||||
requestId: string
|
||||
): Promise<void> {
|
||||
const config = getProcessingConfig()
|
||||
const semaphore = new Array(config.maxConcurrentDocuments).fill(0)
|
||||
const processingPromises = batch.map(async (doc, index) => {
|
||||
if (index > 0 && config.delayBetweenDocuments > 0) {
|
||||
await new Promise((resolve) => setTimeout(resolve, index * config.delayBetweenDocuments))
|
||||
}
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
const checkSlot = () => {
|
||||
const availableIndex = semaphore.findIndex((slot) => slot === 0)
|
||||
if (availableIndex !== -1) {
|
||||
semaphore[availableIndex] = 1
|
||||
resolve()
|
||||
} else {
|
||||
setTimeout(checkSlot, 100)
|
||||
}
|
||||
}
|
||||
checkSlot()
|
||||
queue
|
||||
.processJobs(async (job) => {
|
||||
const data = job.data as DocumentJobData
|
||||
const { knowledgeBaseId, documentId, docData, processingOptions } = data
|
||||
await processDocumentAsync(knowledgeBaseId, documentId, docData, processingOptions)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`[${requestId}] Error in queue processing:`, error)
|
||||
})
|
||||
|
||||
try {
|
||||
logger.info(`[${requestId}] Starting processing for document: ${doc.filename}`)
|
||||
|
||||
await processDocumentAsync(
|
||||
knowledgeBaseId,
|
||||
doc.documentId,
|
||||
{
|
||||
filename: doc.filename,
|
||||
fileUrl: doc.fileUrl,
|
||||
fileSize: doc.fileSize,
|
||||
mimeType: doc.mimeType,
|
||||
},
|
||||
processingOptions
|
||||
)
|
||||
|
||||
logger.info(`[${requestId}] Successfully initiated processing for document: ${doc.filename}`)
|
||||
} catch (error: unknown) {
|
||||
logger.error(`[${requestId}] Failed to process document: ${doc.filename}`, {
|
||||
documentId: doc.documentId,
|
||||
filename: doc.filename,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
})
|
||||
|
||||
try {
|
||||
await db
|
||||
.update(document)
|
||||
.set({
|
||||
processingStatus: 'failed',
|
||||
processingError:
|
||||
error instanceof Error ? error.message : 'Failed to initiate processing',
|
||||
processingCompletedAt: new Date(),
|
||||
})
|
||||
.where(eq(document.id, doc.documentId))
|
||||
} catch (dbError: unknown) {
|
||||
logger.error(
|
||||
`[${requestId}] Failed to update document status for failed document: ${doc.documentId}`,
|
||||
dbError
|
||||
)
|
||||
}
|
||||
} finally {
|
||||
const slotIndex = semaphore.findIndex((slot) => slot === 1)
|
||||
if (slotIndex !== -1) {
|
||||
semaphore[slotIndex] = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.allSettled(processingPromises)
|
||||
logger.info(`[${requestId}] All documents queued for processing`)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1011,10 +1011,21 @@ export function prepareToolExecution(
|
||||
toolParams: Record<string, any>
|
||||
executionParams: Record<string, any>
|
||||
} {
|
||||
// Filter out empty/null/undefined values from user params
|
||||
// so that cleared fields don't override LLM-generated values
|
||||
const filteredUserParams: Record<string, any> = {}
|
||||
if (tool.params) {
|
||||
for (const [key, value] of Object.entries(tool.params)) {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
filteredUserParams[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User-provided params take precedence over LLM-generated params
|
||||
const toolParams = {
|
||||
...llmArgs,
|
||||
...tool.params,
|
||||
...filteredUserParams,
|
||||
}
|
||||
|
||||
// Add system parameters for execution
|
||||
|
||||
@@ -5,9 +5,15 @@ import { persist } from 'zustand/middleware'
|
||||
* Width constraints for the log details panel.
|
||||
*/
|
||||
export const MIN_LOG_DETAILS_WIDTH = 340
|
||||
export const MAX_LOG_DETAILS_WIDTH = 700
|
||||
export const DEFAULT_LOG_DETAILS_WIDTH = 340
|
||||
|
||||
/**
|
||||
* Returns the maximum log details panel width (50vw).
|
||||
* Falls back to a reasonable default for SSR.
|
||||
*/
|
||||
export const getMaxLogDetailsWidth = () =>
|
||||
typeof window !== 'undefined' ? window.innerWidth * 0.5 : 800
|
||||
|
||||
/**
|
||||
* Log details UI state persisted across sessions.
|
||||
*/
|
||||
@@ -27,7 +33,8 @@ export const useLogDetailsUIStore = create<LogDetailsUIState>()(
|
||||
* @param width - Desired width in pixels for the panel.
|
||||
*/
|
||||
setPanelWidth: (width) => {
|
||||
const clampedWidth = Math.max(MIN_LOG_DETAILS_WIDTH, Math.min(width, MAX_LOG_DETAILS_WIDTH))
|
||||
const maxWidth = getMaxLogDetailsWidth()
|
||||
const clampedWidth = Math.max(MIN_LOG_DETAILS_WIDTH, Math.min(width, maxWidth))
|
||||
set({ panelWidth: clampedWidth })
|
||||
},
|
||||
isResizing: false,
|
||||
|
||||
@@ -177,6 +177,44 @@ describe('Tool Parameters Utils', () => {
|
||||
expect(merged.message).toBe('Hello world')
|
||||
expect(merged.timeout).toBe(10000)
|
||||
})
|
||||
|
||||
it.concurrent('should skip empty strings so LLM values are used', () => {
|
||||
const userProvided = {
|
||||
apiKey: 'user-key',
|
||||
channel: '', // User cleared this field
|
||||
message: '', // User cleared this field too
|
||||
}
|
||||
const llmGenerated = {
|
||||
message: 'Hello world',
|
||||
channel: '#random',
|
||||
timeout: 10000,
|
||||
}
|
||||
|
||||
const merged = mergeToolParameters(userProvided, llmGenerated)
|
||||
|
||||
expect(merged.apiKey).toBe('user-key') // Non-empty user value preserved
|
||||
expect(merged.channel).toBe('#random') // LLM value used because user value was empty
|
||||
expect(merged.message).toBe('Hello world') // LLM value used because user value was empty
|
||||
expect(merged.timeout).toBe(10000)
|
||||
})
|
||||
|
||||
it.concurrent('should skip null and undefined values', () => {
|
||||
const userProvided = {
|
||||
apiKey: 'user-key',
|
||||
channel: null,
|
||||
message: undefined,
|
||||
}
|
||||
const llmGenerated = {
|
||||
message: 'Hello world',
|
||||
channel: '#random',
|
||||
}
|
||||
|
||||
const merged = mergeToolParameters(userProvided, llmGenerated)
|
||||
|
||||
expect(merged.apiKey).toBe('user-key')
|
||||
expect(merged.channel).toBe('#random') // LLM value used
|
||||
expect(merged.message).toBe('Hello world') // LLM value used
|
||||
})
|
||||
})
|
||||
|
||||
describe('validateToolParameters', () => {
|
||||
|
||||
@@ -572,16 +572,27 @@ export function createExecutionToolSchema(toolConfig: ToolConfig): ToolSchema {
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges user-provided parameters with LLM-generated parameters
|
||||
* Merges user-provided parameters with LLM-generated parameters.
|
||||
* User-provided parameters take precedence, but empty strings are skipped
|
||||
* so that LLM-generated values are used when user clears a field.
|
||||
*/
|
||||
export function mergeToolParameters(
|
||||
userProvidedParams: Record<string, unknown>,
|
||||
llmGeneratedParams: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
// User-provided parameters take precedence
|
||||
// Filter out empty strings from user-provided params
|
||||
// so that cleared fields don't override LLM values
|
||||
const filteredUserParams: Record<string, unknown> = {}
|
||||
for (const [key, value] of Object.entries(userProvidedParams)) {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
filteredUserParams[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// User-provided parameters take precedence (after filtering empty values)
|
||||
return {
|
||||
...llmGeneratedParams,
|
||||
...userProvidedParams,
|
||||
...filteredUserParams,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
159
bun.lock
159
bun.lock
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 0,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "simstudio",
|
||||
@@ -334,9 +333,9 @@
|
||||
|
||||
"@aws-sdk/client-rds-data": ["@aws-sdk/client-rds-data@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/credential-provider-node": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-68NH61MvS48CVPfzBNCPdCG4KnNjM+Uj/3DSw7rT9PJvdML9ARS4M2Uqco9POPw+Aj20KBumsEUd6FMVcYBXAA=="],
|
||||
|
||||
"@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.943.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/credential-provider-node": "3.943.0", "@aws-sdk/middleware-bucket-endpoint": "3.936.0", "@aws-sdk/middleware-expect-continue": "3.936.0", "@aws-sdk/middleware-flexible-checksums": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-location-constraint": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-sdk-s3": "3.943.0", "@aws-sdk/middleware-ssec": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.943.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-blob-browser": "^4.2.6", "@smithy/hash-node": "^4.2.5", "@smithy/hash-stream-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-UOX8/1mmNaRmEkxoIVP2+gxd5joPJqz+fygRqlIXON1cETLGoctinMwQs7qU8g8hghm76TU2G6ZV6sLH8cySMw=="],
|
||||
"@aws-sdk/client-s3": ["@aws-sdk/client-s3@3.948.0", "", { "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-node": "3.948.0", "@aws-sdk/middleware-bucket-endpoint": "3.936.0", "@aws-sdk/middleware-expect-continue": "3.936.0", "@aws-sdk/middleware-flexible-checksums": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-location-constraint": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-sdk-s3": "3.947.0", "@aws-sdk/middleware-ssec": "3.936.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/eventstream-serde-browser": "^4.2.5", "@smithy/eventstream-serde-config-resolver": "^4.3.5", "@smithy/eventstream-serde-node": "^4.2.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-blob-browser": "^4.2.6", "@smithy/hash-node": "^4.2.5", "@smithy/hash-stream-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/md5-js": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "@smithy/util-waiter": "^4.2.5", "tslib": "^2.6.2" } }, "sha512-uvEjds8aYA9SzhBS8RKDtsDUhNV9VhqKiHTcmvhM7gJO92q0WTn8/QeFTdNyLc6RxpiDyz+uBxS7PcdNiZzqfA=="],
|
||||
|
||||
"@aws-sdk/client-sesv2": ["@aws-sdk/client-sesv2@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/credential-provider-node": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.943.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Zlyw/y5CbhhRK+ZdN/aMNPA8BYo427ddxkTG5yI/JasO05i7thPkhyqsUjyfsV6Z1tHfwFlLeicW57aLW8fAVw=="],
|
||||
"@aws-sdk/client-sesv2": ["@aws-sdk/client-sesv2@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-node": "3.948.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/signature-v4-multi-region": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-7Sl8bRFFLAEQdlvTlaSNFlUHjD+B3N+gbhpS+vH/IlETSmn3fMm4b0Bvve8CWs8jUCctx8nDwXh+0lOWgNDQXw=="],
|
||||
|
||||
"@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.940.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.940.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.940.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.940.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A=="],
|
||||
|
||||
@@ -368,7 +367,7 @@
|
||||
|
||||
"@aws-sdk/middleware-expect-continue": ["@aws-sdk/middleware-expect-continue@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA=="],
|
||||
|
||||
"@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.943.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-J2oYbAQXTFEezs5m2Vij6H3w71K1hZfCtb85AsR/2Ovp/FjABMnK+Es1g1edRx6KuMTc9HkL/iGU4e+ek+qCZw=="],
|
||||
"@aws-sdk/middleware-flexible-checksums": ["@aws-sdk/middleware-flexible-checksums@3.947.0", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/is-array-buffer": "^4.2.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kXXxS2raNESNO+zR0L4YInVjhcGGNI2Mx0AE1ThRhDkAt2se3a+rGf9equ9YvOqA1m8Jl/GSI8cXYvSxXmS9Ag=="],
|
||||
|
||||
"@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw=="],
|
||||
|
||||
@@ -378,7 +377,7 @@
|
||||
|
||||
"@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.0", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA=="],
|
||||
|
||||
"@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kd2mALfthU+RS9NsPS+qvznFcPnVgVx9mgmStWCPn5Qc5BTnx4UAtm+HPA+XZs+zxOopp+zmAfE4qxDHRVONBA=="],
|
||||
"@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-arn-parser": "3.893.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-stream": "^4.5.6", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-DS2tm5YBKhPW2PthrRBDr6eufChbwXe0NjtTZcYDfUCXf0OR+W6cIqyKguwHMJ+IyYdey30AfVw9/Lb5KB8U8A=="],
|
||||
|
||||
"@aws-sdk/middleware-ssec": ["@aws-sdk/middleware-ssec@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA=="],
|
||||
|
||||
@@ -388,9 +387,9 @@
|
||||
|
||||
"@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.936.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@smithy/config-resolver": "^4.4.3", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw=="],
|
||||
|
||||
"@aws-sdk/s3-request-presigner": ["@aws-sdk/s3-request-presigner@3.943.0", "", { "dependencies": { "@aws-sdk/signature-v4-multi-region": "3.943.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-format-url": "3.936.0", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-r79MlUb7jeydV0caSz/emoyttzDdxgSkS/8ZU3lawkoTTnWCt+1nB4VA2xzOAPzP2dSdwNVpuAdY7uD1t2f0wA=="],
|
||||
"@aws-sdk/s3-request-presigner": ["@aws-sdk/s3-request-presigner@3.948.0", "", { "dependencies": { "@aws-sdk/signature-v4-multi-region": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-format-url": "3.936.0", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-tlQhMDsDWwUDUzzlo8XYGpmMfjGDmXgbysv1+h1v2xJe0A+ogv/nJ6KFVP94uf1j4ePmCN/gDdxEp2PWZMBPOQ=="],
|
||||
|
||||
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.943.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-KKvmxNQ/FZbM6ml6nKd8ltDulsUojsXnMJNgf1VHTcJEbADC/6mVWOq0+e9D0WP1qixUBEuMjlS2HqD5KoqwEg=="],
|
||||
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-UaYmzoxf9q3mabIA2hc4T6x5YSFUG2BpNjAZ207EA1bnQMiK+d6vZvb83t7dIWL/U1de1sGV19c1C81Jf14rrA=="],
|
||||
|
||||
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.940.0", "", { "dependencies": { "@aws-sdk/core": "3.940.0", "@aws-sdk/nested-clients": "3.940.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg=="],
|
||||
|
||||
@@ -512,7 +511,7 @@
|
||||
|
||||
"@browserbasehq/sdk": ["@browserbasehq/sdk@2.6.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-83iXP5D7xMm8Wyn66TUaUrgoByCmAJuoMoZQI3sGg3JAiMlTfnCIMqyVBoNSaItaPIkaCnrsj6LiusmXV2X9YA=="],
|
||||
|
||||
"@browserbasehq/stagehand": ["@browserbasehq/stagehand@2.5.4", "", { "dependencies": { "@anthropic-ai/sdk": "0.39.0", "@browserbasehq/sdk": "^2.4.0", "@google/genai": "^1.22.0", "@modelcontextprotocol/sdk": "^1.17.2", "ai": "^4.3.9", "devtools-protocol": "^0.0.1464554", "fetch-cookie": "^3.1.0", "openai": "^4.87.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "playwright": "^1.52.0", "ws": "^8.18.0", "zod-to-json-schema": "^3.23.5" }, "optionalDependencies": { "@ai-sdk/anthropic": "^1.2.6", "@ai-sdk/azure": "^1.3.19", "@ai-sdk/cerebras": "^0.2.6", "@ai-sdk/deepseek": "^0.2.13", "@ai-sdk/google": "^1.2.6", "@ai-sdk/groq": "^1.2.4", "@ai-sdk/mistral": "^1.2.7", "@ai-sdk/openai": "^1.0.14", "@ai-sdk/perplexity": "^1.1.7", "@ai-sdk/togetherai": "^0.2.6", "@ai-sdk/xai": "^1.2.15", "ollama-ai-provider": "^1.2.0" }, "peerDependencies": { "deepmerge": "^4.3.1", "dotenv": "^16.4.5", "zod": ">=3.25.0 <3.25.68" }, "bin": { "evals": "dist/evals/cli.js" } }, "sha512-uUPOa+9i0JuWnczEwwP+Vc4Qfz98maxgKfQZVOGPmFQde9DSPTtfw9/ujB3+tnXy0SGkPl6K4lJInBljdxTdZQ=="],
|
||||
"@browserbasehq/stagehand": ["@browserbasehq/stagehand@2.5.6", "", { "dependencies": { "@anthropic-ai/sdk": "0.39.0", "@browserbasehq/sdk": "^2.4.0", "@google/genai": "^1.22.0", "@modelcontextprotocol/sdk": "^1.17.2", "ai": "^4.3.9", "devtools-protocol": "^0.0.1464554", "fetch-cookie": "^3.1.0", "openai": "^4.87.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "playwright": "^1.52.0", "ws": "^8.18.0", "zod-to-json-schema": "^3.23.5" }, "optionalDependencies": { "@ai-sdk/anthropic": "^1.2.6", "@ai-sdk/azure": "^1.3.19", "@ai-sdk/cerebras": "^0.2.6", "@ai-sdk/deepseek": "^0.2.13", "@ai-sdk/google": "^1.2.6", "@ai-sdk/groq": "^1.2.4", "@ai-sdk/mistral": "^1.2.7", "@ai-sdk/openai": "^1.0.14", "@ai-sdk/perplexity": "^1.1.7", "@ai-sdk/togetherai": "^0.2.6", "@ai-sdk/xai": "^1.2.15", "ollama-ai-provider": "^1.2.0" }, "peerDependencies": { "deepmerge": "^4.3.1", "dotenv": "^16.4.5", "zod": ">=3.25.0 <3.25.68" }, "bin": { "evals": "dist/evals/cli.js" } }, "sha512-VscOPDo/Go8+sHMYLrxcMrUW9sIOHgqCu0Iz9sYH+d/OQqkHJzsyd43oDwgNPCMRYxsZFLApcvczk0zz2l5A8Q=="],
|
||||
|
||||
"@bufbuild/protobuf": ["@bufbuild/protobuf@2.10.1", "", {}, "sha512-ckS3+vyJb5qGpEYv/s1OebUHDi/xSNtfgw1wqKZo7MR9F2z+qXr0q5XagafAG/9O0QPVIUfST0smluYSTpYFkg=="],
|
||||
|
||||
@@ -614,7 +613,7 @@
|
||||
|
||||
"@google-cloud/precise-date": ["@google-cloud/precise-date@4.0.0", "", {}, "sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA=="],
|
||||
|
||||
"@google/genai": ["@google/genai@1.31.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.20.1" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-rK0RKXxNkbK35eDl+G651SxtxwHNEOogjyeZJUJe+Ed4yxu3xy5ufCiU0+QLT7xo4M9Spey8OAYfD8LPRlYBKw=="],
|
||||
"@google/genai": ["@google/genai@1.32.0", "", { "dependencies": { "google-auth-library": "^10.3.0", "ws": "^8.18.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.24.0" }, "optionalPeers": ["@modelcontextprotocol/sdk"] }, "sha512-46vaEaHAThIBlqWFTti1fo3xYU6DwCOwnIIotLhYUbNha90wk5cZL79zdf+NoAfKVsx4DPmjCtXvbQNNVPl5ZQ=="],
|
||||
|
||||
"@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="],
|
||||
|
||||
@@ -716,29 +715,29 @@
|
||||
|
||||
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.20.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-6rqTdFt67AAAzln3NOKsXRmv5ZzPkgbfaebKBqUbts7vK1GZudqnrun5a8d3M/h955cam9RHZ6Jb4Y1XhnmFPg=="],
|
||||
|
||||
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.2", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-QgA5AySqB27cGTXBFmnpifAi7HxoGUeezwo6p9dI03MuDB6Pp33zgclqVb6oVK3j6I9Vesg0+oojW2XxB59SGg=="],
|
||||
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.0", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w=="],
|
||||
|
||||
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.83", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.83", "@napi-rs/canvas-darwin-arm64": "0.1.83", "@napi-rs/canvas-darwin-x64": "0.1.83", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.83", "@napi-rs/canvas-linux-arm64-gnu": "0.1.83", "@napi-rs/canvas-linux-arm64-musl": "0.1.83", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.83", "@napi-rs/canvas-linux-x64-gnu": "0.1.83", "@napi-rs/canvas-linux-x64-musl": "0.1.83", "@napi-rs/canvas-win32-x64-msvc": "0.1.83" } }, "sha512-f9GVB9VNc9vn/nroc9epXRNkVpvNPZh69+qzLJIm9DfruxFqX0/jsXG46OGWAJgkO4mN0HvFHjRROMXKVmPszg=="],
|
||||
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.84", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.84", "@napi-rs/canvas-darwin-arm64": "0.1.84", "@napi-rs/canvas-darwin-x64": "0.1.84", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.84", "@napi-rs/canvas-linux-arm64-gnu": "0.1.84", "@napi-rs/canvas-linux-arm64-musl": "0.1.84", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.84", "@napi-rs/canvas-linux-x64-gnu": "0.1.84", "@napi-rs/canvas-linux-x64-musl": "0.1.84", "@napi-rs/canvas-win32-x64-msvc": "0.1.84" } }, "sha512-88FTNFs4uuiFKP0tUrPsEXhpe9dg7za9ILZJE08pGdUveMIDeana1zwfVkqRHJDPJFAmGY3dXmJ99dzsy57YnA=="],
|
||||
|
||||
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.83", "", { "os": "android", "cpu": "arm64" }, "sha512-TbKM2fh9zXjqFIU8bgMfzG7rkrIYdLKMafgPhFoPwKrpWk1glGbWP7LEu8Y/WrMDqTGFdRqUmuX89yQEzZbkiw=="],
|
||||
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.84", "", { "os": "android", "cpu": "arm64" }, "sha512-pdvuqvj3qtwVryqgpAGornJLV6Ezpk39V6wT4JCnRVGy8I3Tk1au8qOalFGrx/r0Ig87hWslysPpHBxVpBMIww=="],
|
||||
|
||||
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.83", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gp8IDVUloPUmkepHly4xRUOfUJSFNvA4jR7ZRF5nk3YcGzegSFGeICiT4PnYyPgSKEhYAFe1Y2XNy0Mp6Tu8mQ=="],
|
||||
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.84", "", { "os": "darwin", "cpu": "arm64" }, "sha512-A8IND3Hnv0R6abc6qCcCaOCujTLMmGxtucMTZ5vbQUrEN/scxi378MyTLtyWg+MRr6bwQJ6v/orqMS9datIcww=="],
|
||||
|
||||
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.83", "", { "os": "darwin", "cpu": "x64" }, "sha512-r4ZJxiP9OgUbdGZhPDEXD3hQ0aIPcVaywtcTXvamYxTU/SWKAbKVhFNTtpRe1J30oQ25gWyxTkUKSBgUkNzdnw=="],
|
||||
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.84", "", { "os": "darwin", "cpu": "x64" }, "sha512-AUW45lJhYWwnA74LaNeqhvqYKK/2hNnBBBl03KRdqeCD4tKneUSrxUqIv8d22CBweOvrAASyKN3W87WO2zEr/A=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.83", "", { "os": "linux", "cpu": "arm" }, "sha512-Uc6aSB05qH1r+9GUDxIE6F5ZF7L0nTFyyzq8ublWUZhw8fEGK8iy931ff1ByGFT04+xHJad1kBcL4R1ZEV8z7Q=="],
|
||||
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.84", "", { "os": "linux", "cpu": "arm" }, "sha512-8zs5ZqOrdgs4FioTxSBrkl/wHZB56bJNBqaIsfPL4ZkEQCinOkrFF7xIcXiHiKp93J3wUtbIzeVrhTIaWwqk+A=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.83", "", { "os": "linux", "cpu": "arm64" }, "sha512-eEeaJA7V5KOFq7W0GtoRVbd3ak8UZpK+XLkCgUiFGtlunNw+ZZW9Cr/92MXflGe7o3SqqMUg+f975LPxO/vsOQ=="],
|
||||
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.84", "", { "os": "linux", "cpu": "arm64" }, "sha512-i204vtowOglJUpbAFWU5mqsJgH0lVpNk/Ml4mQtB4Lndd86oF+Otr6Mr5KQnZHqYGhlSIKiU2SYnUbhO28zGQA=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.83", "", { "os": "linux", "cpu": "arm64" }, "sha512-cAvonp5XpbatVGegF9lMQNchs3z5RH6EtamRVnQvtoRtwbzOMcdzwuLBqDBQxQF79MFbuZNkWj3YRJjZCjHVzw=="],
|
||||
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.84", "", { "os": "linux", "cpu": "arm64" }, "sha512-VyZq0EEw+OILnWk7G3ZgLLPaz1ERaPP++jLjeyLMbFOF+Tr4zHzWKiKDsEV/cT7btLPZbVoR3VX+T9/QubnURQ=="],
|
||||
|
||||
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.83", "", { "os": "linux", "cpu": "none" }, "sha512-WFUPQ9qZy31vmLxIJ3MfmHw+R2g/mLCgk8zmh7maJW8snV3vLPA7pZfIS65Dc61EVDp1vaBskwQ2RqPPzwkaew=="],
|
||||
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.84", "", { "os": "linux", "cpu": "none" }, "sha512-PSMTh8DiThvLRsbtc/a065I/ceZk17EXAATv9uNvHgkgo7wdEfTh2C3aveNkBMGByVO3tvnvD5v/YFtZL07cIg=="],
|
||||
|
||||
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.83", "", { "os": "linux", "cpu": "x64" }, "sha512-X9YwIjsuy50WwOyYeNhEHjKHO8rrfH9M4U8vNqLuGmqsZdKua/GrUhdQGdjq7lTgdY3g4+Ta5jF8MzAa7UAs/g=="],
|
||||
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.84", "", { "os": "linux", "cpu": "x64" }, "sha512-N1GY3noO1oqgEo3rYQIwY44kfM11vA0lDbN0orTOHfCSUZTUyiYCY0nZ197QMahZBm1aR/vYgsWpV74MMMDuNA=="],
|
||||
|
||||
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.83", "", { "os": "linux", "cpu": "x64" }, "sha512-Vv2pLWQS8EnlSM1bstJ7vVhKA+mL4+my4sKUIn/bgIxB5O90dqiDhQjUDLP+5xn9ZMestRWDt3tdQEkGAmzq/A=="],
|
||||
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.84", "", { "os": "linux", "cpu": "x64" }, "sha512-vUZmua6ADqTWyHyei81aXIt9wp0yjeNwTH0KdhdeoBb6azHmFR8uKTukZMXfLCC3bnsW0t4lW7K78KNMknmtjg=="],
|
||||
|
||||
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.83", "", { "os": "win32", "cpu": "x64" }, "sha512-K1TtjbScfRNYhq8dengLLufXGbtEtWdUXPV505uLFPovyGHzDUGXLFP/zUJzj6xWXwgUjHNLgEPIt7mye0zr6Q=="],
|
||||
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.84", "", { "os": "win32", "cpu": "x64" }, "sha512-YSs8ncurc1xzegUMNnQUTYrdrAuaXdPMOa+iYYyAxydOtg0ppV386hyYMsy00Yip1NlTgLCseRG4sHSnjQx6og=="],
|
||||
|
||||
"@next/env": ["@next/env@16.0.7", "", {}, "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw=="],
|
||||
|
||||
@@ -758,7 +757,7 @@
|
||||
|
||||
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.7", "", { "os": "win32", "cpu": "x64" }, "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug=="],
|
||||
|
||||
"@noble/ciphers": ["@noble/ciphers@2.0.1", "", {}, "sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g=="],
|
||||
"@noble/ciphers": ["@noble/ciphers@2.1.1", "", {}, "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw=="],
|
||||
|
||||
"@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
|
||||
|
||||
@@ -882,7 +881,7 @@
|
||||
|
||||
"@posthog/core": ["@posthog/core@1.2.2", "", {}, "sha512-f16Ozx6LIigRG+HsJdt+7kgSxZTHeX5f1JlCGKI1lXcvlZgfsCR338FuMI2QRYXGl+jg/vYFzGOTQBxl90lnBg=="],
|
||||
|
||||
"@prisma/config": ["@prisma/config@6.19.0", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.18.4", "empathic": "2.0.0" } }, "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg=="],
|
||||
"@prisma/config": ["@prisma/config@6.19.1", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.18.4", "empathic": "2.0.0" } }, "sha512-bUL/aYkGXLwxVGhJmQMtslLT7KPEfUqmRa919fKI4wQFX4bIFUKiY8Jmio/2waAjjPYrtuDHa7EsNCnJTXxiOw=="],
|
||||
|
||||
"@protobuf-ts/runtime": ["@protobuf-ts/runtime@2.11.1", "", {}, "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ=="],
|
||||
|
||||
@@ -1414,7 +1413,7 @@
|
||||
|
||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
|
||||
"@types/node": ["@types/node@22.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ=="],
|
||||
"@types/node": ["@types/node@22.19.2", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw=="],
|
||||
|
||||
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
|
||||
|
||||
@@ -1528,7 +1527,7 @@
|
||||
|
||||
"asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="],
|
||||
|
||||
"asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="],
|
||||
"asn1js": ["asn1js@3.0.7", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ=="],
|
||||
|
||||
"assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
|
||||
|
||||
@@ -1556,7 +1555,7 @@
|
||||
|
||||
"base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="],
|
||||
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.3", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA=="],
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.6", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg=="],
|
||||
|
||||
"basic-auth": ["basic-auth@2.0.1", "", { "dependencies": { "safe-buffer": "5.1.2" } }, "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg=="],
|
||||
|
||||
@@ -1622,7 +1621,7 @@
|
||||
|
||||
"camelize": ["camelize@1.0.1", "", {}, "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ=="],
|
||||
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001759", "", {}, "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw=="],
|
||||
"caniuse-lite": ["caniuse-lite@1.0.30001760", "", {}, "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw=="],
|
||||
|
||||
"caseless": ["caseless@0.12.0", "", {}, "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="],
|
||||
|
||||
@@ -1870,7 +1869,7 @@
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"e2b": ["e2b@2.8.3", "", { "dependencies": { "@bufbuild/protobuf": "^2.6.2", "@connectrpc/connect": "2.0.0-rc.3", "@connectrpc/connect-web": "2.0.0-rc.3", "chalk": "^5.3.0", "compare-versions": "^6.1.0", "dockerfile-ast": "^0.7.1", "glob": "^11.1.0", "openapi-fetch": "^0.14.1", "platform": "^1.3.6", "tar": "^7.5.2" } }, "sha512-P0hA5UceZ6HVfL9VDqQ0VG+IXZTy1K+FHek3xFkg7vSgcBm6wV9KG/YcvaoEdgiF+n1KS2TsIhunLs22jbrLyQ=="],
|
||||
"e2b": ["e2b@2.8.4", "", { "dependencies": { "@bufbuild/protobuf": "^2.6.2", "@connectrpc/connect": "2.0.0-rc.3", "@connectrpc/connect-web": "2.0.0-rc.3", "chalk": "^5.3.0", "compare-versions": "^6.1.0", "dockerfile-ast": "^0.7.1", "glob": "^11.1.0", "openapi-fetch": "^0.14.1", "platform": "^1.3.6", "tar": "^7.5.2" } }, "sha512-InHLjwWYM3eWfr/YYP1NnbjZ6ZojydzfFnY1JMX2oDM5dxO6EPriqIw2ObFJPCwRsrpZelnHeMe19HeJJmVBvg=="],
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
|
||||
@@ -1880,7 +1879,7 @@
|
||||
|
||||
"effect": ["effect@3.18.4", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.266", "", {}, "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg=="],
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
|
||||
@@ -1968,7 +1967,7 @@
|
||||
|
||||
"execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
|
||||
|
||||
"expect-type": ["expect-type@1.2.2", "", {}, "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA=="],
|
||||
"expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
|
||||
|
||||
"express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
|
||||
|
||||
@@ -1984,7 +1983,7 @@
|
||||
|
||||
"fast-content-type-parse": ["fast-content-type-parse@2.0.1", "", {}, "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q=="],
|
||||
|
||||
"fast-copy": ["fast-copy@4.0.0", "", {}, "sha512-/oA0gx1xyXE9R2YlV4FXwZJXngFdm9Du0zN8FhY38jnLkhp1u35h6bCyKgRhlsA6C9I+1vfXE4KISdt7xc6M9w=="],
|
||||
"fast-copy": ["fast-copy@4.0.1", "", {}, "sha512-+uUOQlhsaswsizHFmEFAQhB3lSiQ+lisxl50N6ZP0wywlZeWsIESxSi9ftPEps8UGfiBzyYP7x27zA674WUvXw=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
@@ -2036,7 +2035,7 @@
|
||||
|
||||
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
|
||||
|
||||
"framer-motion": ["framer-motion@12.23.25", "", { "dependencies": { "motion-dom": "^12.23.23", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-gUHGl2e4VG66jOcH0JHhuJQr6ZNwrET9g31ZG0xdXzT0CznP7fHX4P8Bcvuc4MiUB90ysNnWX2ukHRIggkl6hQ=="],
|
||||
"framer-motion": ["framer-motion@12.23.26", "", { "dependencies": { "motion-dom": "^12.23.23", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA=="],
|
||||
|
||||
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||
|
||||
@@ -2150,7 +2149,7 @@
|
||||
|
||||
"human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
|
||||
|
||||
"humanize-duration": ["humanize-duration@3.33.1", "", {}, "sha512-hwzSCymnRdFx9YdRkQQ0OYequXiVAV6ZGQA2uzocwB0F4309Ke6pO8dg0P8LHhRQJyVjGteRTAA/zNfEcpXn8A=="],
|
||||
"humanize-duration": ["humanize-duration@3.33.2", "", {}, "sha512-K7Ny/ULO1hDm2nnhvAY+SJV1skxFb61fd073SG1IWJl+D44ULrruCuTyjHKjBVVcSuTlnY99DKtgEG39CM5QOQ=="],
|
||||
|
||||
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
|
||||
|
||||
@@ -2356,7 +2355,7 @@
|
||||
|
||||
"loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="],
|
||||
|
||||
"lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
|
||||
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="],
|
||||
|
||||
@@ -2542,7 +2541,7 @@
|
||||
|
||||
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
||||
|
||||
"named-placeholders": ["named-placeholders@1.1.3", "", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="],
|
||||
"named-placeholders": ["named-placeholders@1.1.4", "", { "dependencies": { "lru.min": "^1.1.0" } }, "sha512-/qfG0Kk/bLJIvej4FcPQ2KYUJP8iQdU1CTxysNb/U2wUNb+/4K485yeio8iNoiwfqJnsTInXoRPTza0dZWHVJQ=="],
|
||||
|
||||
"nan": ["nan@2.24.0", "", {}, "sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg=="],
|
||||
|
||||
@@ -2596,7 +2595,7 @@
|
||||
|
||||
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
|
||||
|
||||
"nwsapi": ["nwsapi@2.2.22", "", {}, "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ=="],
|
||||
"nwsapi": ["nwsapi@2.2.23", "", {}, "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ=="],
|
||||
|
||||
"nypm": ["nypm@0.6.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "pathe": "^2.0.3", "pkg-types": "^2.0.0", "tinyexec": "^0.3.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg=="],
|
||||
|
||||
@@ -2846,7 +2845,7 @@
|
||||
|
||||
"reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="],
|
||||
|
||||
"regex": ["regex@6.0.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA=="],
|
||||
"regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="],
|
||||
|
||||
"regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="],
|
||||
|
||||
@@ -3244,7 +3243,7 @@
|
||||
|
||||
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
|
||||
|
||||
"vite": ["vite@7.2.6", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ=="],
|
||||
"vite": ["vite@7.2.7", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ=="],
|
||||
|
||||
"vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
|
||||
|
||||
@@ -3354,25 +3353,29 @@
|
||||
|
||||
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/core": ["@aws-sdk/core@3.943.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-8CBy2hI9ABF7RBVQuY1bgf/ue+WPmM/hl0adrXFlhnhkaQP0tFY5zhiy1Y+n7V+5f3/ORoHBmCCQmcHDDYJqJQ=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.943.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.943.0", "@aws-sdk/credential-provider-http": "3.943.0", "@aws-sdk/credential-provider-ini": "3.943.0", "@aws-sdk/credential-provider-process": "3.943.0", "@aws-sdk/credential-provider-sso": "3.943.0", "@aws-sdk/credential-provider-web-identity": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-14eddaH/gjCWoLSAELVrFOQNyswUYwWphIt+PdsJ/FqVfP4ay2HsiZVEIYbQtmrKHaoLJhiZKwBQRjcqJDZG0w=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.948.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.948.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.948.0", "@aws-sdk/credential-provider-web-identity": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ep5vRLnrRdcsP17Ef31sNN4g8Nqk/4JBydcUJuFRbGuyQtrZZrVT81UeH2xhz6d0BK6ejafDB9+ZpBjXuWT5/Q=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-956n4kVEwFNXndXfhSAN5wO+KRgqiWEEY+ECwLvxmmO8uQ0NWOa8l6l65nTtyuiWzMX81c9BvlyNR5EgUeeUvA=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.948.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.943.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-gn+ILprVRrgAgTIBk2TDsJLRClzIOdStQFeFTcN0qpL8Z4GBCqMFhw7O7X+MM55Stt5s4jAauQ/VvoqmCADnQg=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/core": ["@aws-sdk/core@3.943.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-8CBy2hI9ABF7RBVQuY1bgf/ue+WPmM/hl0adrXFlhnhkaQP0tFY5zhiy1Y+n7V+5f3/ORoHBmCCQmcHDDYJqJQ=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.943.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.943.0", "@aws-sdk/credential-provider-http": "3.943.0", "@aws-sdk/credential-provider-ini": "3.943.0", "@aws-sdk/credential-provider-process": "3.943.0", "@aws-sdk/credential-provider-sso": "3.943.0", "@aws-sdk/credential-provider-web-identity": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-14eddaH/gjCWoLSAELVrFOQNyswUYwWphIt+PdsJ/FqVfP4ay2HsiZVEIYbQtmrKHaoLJhiZKwBQRjcqJDZG0w=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.5", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-956n4kVEwFNXndXfhSAN5wO+KRgqiWEEY+ECwLvxmmO8uQ0NWOa8l6l65nTtyuiWzMX81c9BvlyNR5EgUeeUvA=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.948.0", "", { "dependencies": { "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-ini": "3.948.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.948.0", "@aws-sdk/credential-provider-web-identity": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-ep5vRLnrRdcsP17Ef31sNN4g8Nqk/4JBydcUJuFRbGuyQtrZZrVT81UeH2xhz6d0BK6ejafDB9+ZpBjXuWT5/Q=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.943.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-gn+ILprVRrgAgTIBk2TDsJLRClzIOdStQFeFTcN0qpL8Z4GBCqMFhw7O7X+MM55Stt5s4jAauQ/VvoqmCADnQg=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.948.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ=="],
|
||||
|
||||
"@aws-sdk/middleware-flexible-checksums/@aws-sdk/core": ["@aws-sdk/core@3.943.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-8CBy2hI9ABF7RBVQuY1bgf/ue+WPmM/hl0adrXFlhnhkaQP0tFY5zhiy1Y+n7V+5f3/ORoHBmCCQmcHDDYJqJQ=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@smithy/core": "^3.18.7", "@smithy/protocol-http": "^5.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA=="],
|
||||
|
||||
"@aws-sdk/middleware-sdk-s3/@aws-sdk/core": ["@aws-sdk/core@3.943.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-8CBy2hI9ABF7RBVQuY1bgf/ue+WPmM/hl0adrXFlhnhkaQP0tFY5zhiy1Y+n7V+5f3/ORoHBmCCQmcHDDYJqJQ=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.947.0", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/node-config-provider": "^4.3.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ=="],
|
||||
|
||||
"@aws-sdk/middleware-flexible-checksums/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
|
||||
|
||||
"@aws-sdk/middleware-sdk-s3/@aws-sdk/core": ["@aws-sdk/core@3.947.0", "", { "dependencies": { "@aws-sdk/types": "3.936.0", "@aws-sdk/xml-builder": "3.930.0", "@smithy/core": "^3.18.7", "@smithy/node-config-provider": "^4.3.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/signature-v4": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-middleware": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw=="],
|
||||
|
||||
"@aws-sdk/xml-builder/fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
|
||||
|
||||
@@ -3384,8 +3387,6 @@
|
||||
|
||||
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@better-auth/sso/jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
|
||||
@@ -3718,6 +3719,8 @@
|
||||
|
||||
"log-update/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||
|
||||
"lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
|
||||
"mammoth/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
|
||||
|
||||
"mammoth/xmlbuilder": ["xmlbuilder@10.1.1", "", {}, "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg=="],
|
||||
@@ -3796,13 +3799,13 @@
|
||||
|
||||
"sim/tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="],
|
||||
|
||||
"sim/tailwindcss": ["tailwindcss@3.4.18", "", { "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" } }, "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ=="],
|
||||
"sim/tailwindcss": ["tailwindcss@3.4.19", "", { "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" } }, "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ=="],
|
||||
|
||||
"simstudio/@types/node": ["@types/node@20.19.25", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="],
|
||||
"simstudio/@types/node": ["@types/node@20.19.26", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg=="],
|
||||
|
||||
"simstudio/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"simstudio-ts-sdk/@types/node": ["@types/node@20.19.25", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="],
|
||||
"simstudio-ts-sdk/@types/node": ["@types/node@20.19.26", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg=="],
|
||||
|
||||
"slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
||||
|
||||
@@ -3858,31 +3861,29 @@
|
||||
|
||||
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WnS5w9fK9CTuoZRVSIHLOMcI63oODg9qd1vXMYb7QGLGlfwUm4aG3hdu7i9XvYrpkQfE3dzwWLtXF4ZBuL1Tew=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-SA8bUcYDEACdhnhLpZNnWusBpdmj4Vl67Vxp3Zke7SvoWSYbuxa+tiDiC+c92Z4Yq6xNOuLPW912ZPb9/NsSkA=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/credential-provider-env": "3.943.0", "@aws-sdk/credential-provider-http": "3.943.0", "@aws-sdk/credential-provider-login": "3.943.0", "@aws-sdk/credential-provider-process": "3.943.0", "@aws-sdk/credential-provider-sso": "3.943.0", "@aws-sdk/credential-provider-web-identity": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-BcLDb8l4oVW+NkuqXMlO7TnM6lBOWW318ylf4FRED/ply5eaGxkQYqdGvHSqGSN5Rb3vr5Ek0xpzSjeYD7C8Kw=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-login": "3.948.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.948.0", "@aws-sdk/credential-provider-web-identity": "3.948.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Cl//Qh88e8HBL7yYkJNpF5eq76IO6rq8GsatKcfVBm7RFVxCqYEPSSBtkHdbtNwQdRQqAMXc6E/lEB/CZUDxnA=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-GIY/vUkthL33AdjOJ8r9vOosKf/3X+X7LIiACzGxvZZrtoOiRq0LADppdiKIB48vTL63VvW+eRIOFAxE6UDekw=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.943.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.943.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/token-providers": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-1c5G11syUrru3D9OO6Uk+ul5e2lX1adb+7zQNyluNaLPXP6Dina6Sy6DFGRLu7tM8+M7luYmbS3w63rpYpaL+A=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.948.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.948.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/token-providers": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gqLhX1L+zb/ZDnnYbILQqJ46j735StfWV5PbDjxRzBKS7GzsiYoaf6MyHseEopmWrez5zl5l6aWzig7UpzSeQQ=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VtyGKHxICSb4kKGuaqotxso8JVM8RjCS3UYdIMOxUt9TaFE/CZIfZKtjTr+IJ7M0P7t36wuSUb/jRLyNmGzUUA=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MvYQlXVoJyfF3/SmnNzOVEtANRAiJIObEUYYyjTqKZTmcRIVVky0tPuG26XnB8LmTYgtESwJIZJj/Eyyc9WURQ=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WnS5w9fK9CTuoZRVSIHLOMcI63oODg9qd1vXMYb7QGLGlfwUm4aG3hdu7i9XvYrpkQfE3dzwWLtXF4ZBuL1Tew=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-SA8bUcYDEACdhnhLpZNnWusBpdmj4Vl67Vxp3Zke7SvoWSYbuxa+tiDiC+c92Z4Yq6xNOuLPW912ZPb9/NsSkA=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/node-http-handler": "^4.4.5", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/util-stream": "^4.5.6", "tslib": "^2.6.2" } }, "sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/credential-provider-env": "3.943.0", "@aws-sdk/credential-provider-http": "3.943.0", "@aws-sdk/credential-provider-login": "3.943.0", "@aws-sdk/credential-provider-process": "3.943.0", "@aws-sdk/credential-provider-sso": "3.943.0", "@aws-sdk/credential-provider-web-identity": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-BcLDb8l4oVW+NkuqXMlO7TnM6lBOWW318ylf4FRED/ply5eaGxkQYqdGvHSqGSN5Rb3vr5Ek0xpzSjeYD7C8Kw=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/credential-provider-env": "3.947.0", "@aws-sdk/credential-provider-http": "3.947.0", "@aws-sdk/credential-provider-login": "3.948.0", "@aws-sdk/credential-provider-process": "3.947.0", "@aws-sdk/credential-provider-sso": "3.948.0", "@aws-sdk/credential-provider-web-identity": "3.948.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/credential-provider-imds": "^4.2.5", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-Cl//Qh88e8HBL7yYkJNpF5eq76IO6rq8GsatKcfVBm7RFVxCqYEPSSBtkHdbtNwQdRQqAMXc6E/lEB/CZUDxnA=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-GIY/vUkthL33AdjOJ8r9vOosKf/3X+X7LIiACzGxvZZrtoOiRq0LADppdiKIB48vTL63VvW+eRIOFAxE6UDekw=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.947.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.943.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.943.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/token-providers": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-1c5G11syUrru3D9OO6Uk+ul5e2lX1adb+7zQNyluNaLPXP6Dina6Sy6DFGRLu7tM8+M7luYmbS3w63rpYpaL+A=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.948.0", "", { "dependencies": { "@aws-sdk/client-sso": "3.948.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/token-providers": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gqLhX1L+zb/ZDnnYbILQqJ46j735StfWV5PbDjxRzBKS7GzsiYoaf6MyHseEopmWrez5zl5l6aWzig7UpzSeQQ=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-VtyGKHxICSb4kKGuaqotxso8JVM8RjCS3UYdIMOxUt9TaFE/CZIfZKtjTr+IJ7M0P7t36wuSUb/jRLyNmGzUUA=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-MvYQlXVoJyfF3/SmnNzOVEtANRAiJIObEUYYyjTqKZTmcRIVVky0tPuG26XnB8LmTYgtESwJIZJj/Eyyc9WURQ=="],
|
||||
|
||||
"@browserbasehq/sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||
|
||||
@@ -4226,25 +4227,25 @@
|
||||
|
||||
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9iCOVkiRW+evxiJE94RqosCwRrzptAVPhRhGWv4osfYDhjNAvUMyrnZl3T1bjqCoKNcETRKEZIU3dqYHnUkcwQ=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gcKO2b6eeTuZGp3Vvgr/9OxajMrD3W+FZ2FCyJox363ZgMoYJsyNid1vuZrEuAGkx0jvveLXfwiVS0UXyPkgtw=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kOTO2B8Ks2qX73CyKY8PAajtf5n39aMe2spoiOF5EkgSzGV7hZ/HONRDyADlyxwfsX39Q2F2SpPUaXzon32IGw=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iWjchXy8bIAVBUsKnbfKYXRwhLgRg3EqCQ5FTr3JbR+QR75rZm4ZOYXlvHGztVTmtAZ+PQVA1Y4zO7v7N87C0A=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-cRKyIzwfkS+XztXIFPoWORuaxlIswP+a83BJzelX4S1gUZ7FcXB4+lj9Jxjn8SbQhR4TPU3Owbpu+S7pd6IRbQ=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-V487/kM4Teq5dcr1t5K6eoUKuqlGr9FRWL3MIMukMERJXHZvio6kox60FZ/YtciRHRI75u14YUqm2Dzddcu3+A=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-9iCOVkiRW+evxiJE94RqosCwRrzptAVPhRhGWv4osfYDhjNAvUMyrnZl3T1bjqCoKNcETRKEZIU3dqYHnUkcwQ=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/protocol-http": "^5.3.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-gcKO2b6eeTuZGp3Vvgr/9OxajMrD3W+FZ2FCyJox363ZgMoYJsyNid1vuZrEuAGkx0jvveLXfwiVS0UXyPkgtw=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-kOTO2B8Ks2qX73CyKY8PAajtf5n39aMe2spoiOF5EkgSzGV7hZ/HONRDyADlyxwfsX39Q2F2SpPUaXzon32IGw=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/client-sso": ["@aws-sdk/client-sso@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-iWjchXy8bIAVBUsKnbfKYXRwhLgRg3EqCQ5FTr3JbR+QR75rZm4ZOYXlvHGztVTmtAZ+PQVA1Y4zO7v7N87C0A=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.943.0", "", { "dependencies": { "@aws-sdk/core": "3.943.0", "@aws-sdk/nested-clients": "3.943.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-cRKyIzwfkS+XztXIFPoWORuaxlIswP+a83BJzelX4S1gUZ7FcXB4+lj9Jxjn8SbQhR4TPU3Owbpu+S7pd6IRbQ=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.948.0", "", { "dependencies": { "@aws-sdk/core": "3.947.0", "@aws-sdk/nested-clients": "3.948.0", "@aws-sdk/types": "3.936.0", "@smithy/property-provider": "^4.2.5", "@smithy/shared-ini-file-loader": "^4.4.0", "@smithy/types": "^4.9.0", "tslib": "^2.6.2" } }, "sha512-V487/kM4Teq5dcr1t5K6eoUKuqlGr9FRWL3MIMukMERJXHZvio6kox60FZ/YtciRHRI75u14YUqm2Dzddcu3+A=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="],
|
||||
|
||||
"@browserbasehq/sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||
|
||||
@@ -4334,9 +4335,9 @@
|
||||
|
||||
"test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw=="],
|
||||
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="],
|
||||
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.943.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.943.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.936.0", "@aws-sdk/middleware-user-agent": "3.943.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.943.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.5", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.12", "@smithy/middleware-retry": "^4.4.12", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.8", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.11", "@smithy/util-defaults-mode-node": "^4.2.14", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw=="],
|
||||
"@aws-sdk/client-sesv2/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.948.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.947.0", "@aws-sdk/middleware-host-header": "3.936.0", "@aws-sdk/middleware-logger": "3.936.0", "@aws-sdk/middleware-recursion-detection": "3.948.0", "@aws-sdk/middleware-user-agent": "3.947.0", "@aws-sdk/region-config-resolver": "3.936.0", "@aws-sdk/types": "3.936.0", "@aws-sdk/util-endpoints": "3.936.0", "@aws-sdk/util-user-agent-browser": "3.936.0", "@aws-sdk/util-user-agent-node": "3.947.0", "@smithy/config-resolver": "^4.4.3", "@smithy/core": "^3.18.7", "@smithy/fetch-http-handler": "^5.3.6", "@smithy/hash-node": "^4.2.5", "@smithy/invalid-dependency": "^4.2.5", "@smithy/middleware-content-length": "^4.2.5", "@smithy/middleware-endpoint": "^4.3.14", "@smithy/middleware-retry": "^4.4.14", "@smithy/middleware-serde": "^4.2.6", "@smithy/middleware-stack": "^4.2.5", "@smithy/node-config-provider": "^4.3.5", "@smithy/node-http-handler": "^4.4.5", "@smithy/protocol-http": "^5.3.5", "@smithy/smithy-client": "^4.9.10", "@smithy/types": "^4.9.0", "@smithy/url-parser": "^4.2.5", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", "@smithy/util-defaults-mode-browser": "^4.3.13", "@smithy/util-defaults-mode-node": "^4.2.16", "@smithy/util-endpoints": "^3.2.5", "@smithy/util-middleware": "^4.2.5", "@smithy/util-retry": "^4.2.5", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw=="],
|
||||
|
||||
"@trigger.dev/core/socket.io/engine.io/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
|
||||
|
||||
|
||||
Reference in New Issue
Block a user