diff --git a/.gitignore b/.gitignore index e2d4bcf5889..6f833f1e4dd 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,12 @@ docs/.contentlayer docs/.content-collections # database instantiation -**/postgres_data/ \ No newline at end of file +**/postgres_data/ + +# file uploads +uploads/ + +# collector configuration +collector-config.yaml +docker-compose.collector.yml +start-collector.sh diff --git a/sim/app/api/chat/subdomains/validate/route.test.ts b/sim/app/api/chat/subdomains/validate/route.test.ts index b5f2107220a..b5318ab9945 100644 --- a/sim/app/api/chat/subdomains/validate/route.test.ts +++ b/sim/app/api/chat/subdomains/validate/route.test.ts @@ -162,6 +162,29 @@ describe('Subdomain Validation API Route', () => { subdomain: 'available-subdomain', }) }) + + it('should return available=false when subdomain is reserved', async () => { + vi.doMock('@/lib/auth', () => ({ + getSession: vi.fn().mockResolvedValue({ + user: { id: 'user-id' }, + }), + })) + + const req = new NextRequest('http://localhost:3000/api/chat/subdomains/validate?subdomain=telemetry') + + const { GET } = await import('./route') + + const response = await GET(req) + const data = await response.json() + + expect(response.status).toBe(400) + expect(data).toHaveProperty('available', false) + expect(data).toHaveProperty('error', 'This subdomain is reserved') + expect(mockNextResponseJson).toHaveBeenCalledWith( + { available: false, error: 'This subdomain is reserved' }, + { status: 400 } + ) + }) it('should return available=false when subdomain is already in use', async () => { vi.doMock('@/lib/auth', () => ({ diff --git a/sim/app/api/chat/subdomains/validate/route.ts b/sim/app/api/chat/subdomains/validate/route.ts index 5fb929c027b..77e4b14bf82 100644 --- a/sim/app/api/chat/subdomains/validate/route.ts +++ b/sim/app/api/chat/subdomains/validate/route.ts @@ -34,6 +34,18 @@ export async function GET(request: Request) { { status: 400 } ) } + + // Protect reserved subdomains + const reservedSubdomains = ['telemetry', 'docs', 'api', 'admin', 'www', 'app', 'auth', 'blog', 'help', 'support']; + if (reservedSubdomains.includes(subdomain)) { + return NextResponse.json( + { + available: false, + error: 'This subdomain is reserved' + }, + { status: 400 } + ) + } // Query database to see if subdomain already exists const existingDeployment = await db diff --git a/sim/app/api/telemetry/route.ts b/sim/app/api/telemetry/route.ts new file mode 100644 index 00000000000..dba8ec62a83 --- /dev/null +++ b/sim/app/api/telemetry/route.ts @@ -0,0 +1,209 @@ +import { NextRequest, NextResponse } from 'next/server' +import { createLogger } from '@/lib/logs/console-logger' + +const logger = createLogger('TelemetryAPI') + +const ALLOWED_CATEGORIES = [ + 'page_view', + 'feature_usage', + 'performance', + 'error', + 'workflow', + 'consent', +] + +const DEFAULT_TIMEOUT = 5000 // 5 seconds timeout + +/** + * Validates telemetry data to ensure it doesn't contain sensitive information + */ +function validateTelemetryData(data: any): boolean { + if (!data || typeof data !== 'object') { + return false + } + + if (!data.category || !data.action) { + return false + } + + if (!ALLOWED_CATEGORIES.includes(data.category)) { + return false + } + + const jsonStr = JSON.stringify(data).toLowerCase() + const sensitivePatterns = [ + /password/, + /token/, + /secret/, + /key/, + /auth/, + /credential/, + /private/, + ] + + return !sensitivePatterns.some(pattern => pattern.test(jsonStr)) +} + +/** + * Safely converts a value to string, handling undefined and null values + */ +function safeStringValue(value: any): string { + if (value === undefined || value === null) { + return '' + } + + try { + return String(value) + } catch (e) { + return '' + } +} + +/** + * Creates a safe attribute object for OpenTelemetry + */ +function createSafeAttributes(data: Record): Array<{key: string, value: {stringValue: string}}> { + if (!data || typeof data !== 'object') { + return [] + } + + const attributes: Array<{key: string, value: {stringValue: string}}> = [] + + Object.entries(data).forEach(([key, value]) => { + if (value !== undefined && value !== null && key) { + attributes.push({ + key, + value: { stringValue: safeStringValue(value) } + }) + } + }) + + return attributes +} + +/** + * Forwards telemetry data to OpenTelemetry collector + */ +async function forwardToCollector(data: any): Promise { + if (!data || typeof data !== 'object') { + logger.error('Invalid telemetry data format') + return false + } + + const endpoint = process.env.TELEMETRY_ENDPOINT || 'https://telemetry.simstudio.ai/v1/traces' + const timeout = parseInt(process.env.TELEMETRY_TIMEOUT || '') || DEFAULT_TIMEOUT + + try { + const timestamp = Date.now() * 1000000 + + const safeAttrs = createSafeAttributes(data) + + const serviceAttrs = [ + { key: 'service.name', value: { stringValue: 'sim-studio' } }, + { key: 'service.version', value: { stringValue: process.env.NEXT_PUBLIC_APP_VERSION || '0.1.0' } }, + { key: 'deployment.environment', value: { stringValue: process.env.NODE_ENV || 'production' } } + ] + + const spanName = data.category && data.action ? `${data.category}.${data.action}` : 'telemetry.event' + + const payload = { + resourceSpans: [{ + resource: { + attributes: serviceAttrs + }, + instrumentationLibrarySpans: [{ + spans: [{ + name: spanName, + kind: 1, + startTimeUnixNano: timestamp, + endTimeUnixNano: timestamp + 1000000, + attributes: safeAttrs + }] + }] + }] + } + + // Safe debug log of the payload structure without sensitive data + logger.debug('Preparing to send telemetry payload', { + endpoint, + hasAttributes: safeAttrs.length > 0, + attributeCount: safeAttrs.length + }) + + // Create explicit AbortController for timeout + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), timeout) + + try { + const options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload), + signal: controller.signal + } + + const response = await fetch(endpoint, options) + clearTimeout(timeoutId) + + if (!response.ok) { + logger.error('Telemetry collector returned error', { + status: response.status, + statusText: response.statusText + }) + return false + } + + return true + } catch (fetchError) { + clearTimeout(timeoutId) + if (fetchError instanceof Error && fetchError.name === 'AbortError') { + logger.error('Telemetry request timed out', { endpoint }) + } else { + logger.error('Failed to send telemetry to collector', fetchError) + } + return false + } + } catch (error) { + logger.error('Error preparing telemetry payload', error) + return false + } +} + +/** + * Endpoint that receives telemetry events and forwards them to OpenTelemetry collector + */ +export async function POST(req: NextRequest) { + try { + let eventData + try { + eventData = await req.json() + } catch (parseError) { + return NextResponse.json( + { error: 'Invalid JSON in request body' }, + { status: 400 } + ) + } + + if (!validateTelemetryData(eventData)) { + return NextResponse.json( + { error: 'Invalid telemetry data format or contains sensitive information' }, + { status: 400 } + ) + } + + const forwarded = await forwardToCollector(eventData) + + return NextResponse.json({ + success: true, + forwarded + }) + } catch (error) { + logger.error('Error processing telemetry event', error) + return NextResponse.json( + { error: 'Failed to process telemetry event' }, + { status: 500 } + ) + } +} \ No newline at end of file diff --git a/sim/app/api/settings/route.ts b/sim/app/api/user/settings/route.ts similarity index 53% rename from sim/app/api/settings/route.ts rename to sim/app/api/user/settings/route.ts index cc263c7e14f..5e42701f5cc 100644 --- a/sim/app/api/settings/route.ts +++ b/sim/app/api/user/settings/route.ts @@ -5,22 +5,87 @@ import { z } from 'zod' import { createLogger } from '@/lib/logs/console-logger' import { db } from '@/db' import { settings } from '@/db/schema' +import { getSession } from '@/lib/auth' -const logger = createLogger('SettingsAPI') +const logger = createLogger('UserSettingsAPI') const SettingsSchema = z.object({ - userId: z.string(), - isAutoConnectEnabled: z.boolean().default(true), + theme: z.enum(['system', 'light', 'dark']).optional(), + debugMode: z.boolean().optional(), + autoConnect: z.boolean().optional(), + autoFillEnvVars: z.boolean().optional(), + telemetryEnabled: z.boolean().optional(), + telemetryNotifiedUser: z.boolean().optional(), }) -export async function POST(request: Request) { +export async function GET() { + const requestId = crypto.randomUUID().slice(0, 8) + + try { + const session = await getSession() + + if (!session?.user?.id) { + logger.warn(`[${requestId}] Unauthorized settings access attempt`) + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + + const userId = session.user.id + const result = await db.select().from(settings).where(eq(settings.userId, userId)).limit(1) + + if (!result.length) { + return NextResponse.json( + { + data: { + // Return default values + theme: 'system', + debugMode: false, + autoConnect: true, + autoFillEnvVars: true, + telemetryEnabled: true, + telemetryNotifiedUser: false, + }, + }, + { status: 200 } + ) + } + + const userSettings = result[0] + + return NextResponse.json( + { + data: { + theme: userSettings.theme, + debugMode: userSettings.debugMode, + autoConnect: userSettings.autoConnect, + autoFillEnvVars: userSettings.autoFillEnvVars, + telemetryEnabled: userSettings.telemetryEnabled, + telemetryNotifiedUser: userSettings.telemetryNotifiedUser, + }, + }, + { status: 200 } + ) + } catch (error: any) { + logger.error(`[${requestId}] Settings fetch error`, error) + return NextResponse.json({ error: error.message }, { status: 500 }) + } +} + +export async function PATCH(request: Request) { const requestId = crypto.randomUUID().slice(0, 8) try { + const session = await getSession() + + if (!session?.user?.id) { + logger.warn(`[${requestId}] Unauthorized settings update attempt`) + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + + const userId = session.user.id const body = await request.json() try { - const { userId, isAutoConnectEnabled } = SettingsSchema.parse(body) + const validatedData = SettingsSchema.parse(body) // Store the settings await db @@ -28,13 +93,13 @@ export async function POST(request: Request) { .values({ id: nanoid(), userId, - general: { isAutoConnectEnabled }, + ...validatedData, updatedAt: new Date(), }) .onConflictDoUpdate({ target: [settings.userId], set: { - general: { isAutoConnectEnabled }, + ...validatedData, updatedAt: new Date(), }, }) @@ -56,46 +121,4 @@ export async function POST(request: Request) { logger.error(`[${requestId}] Settings update error`, error) return NextResponse.json({ error: error.message }, { status: 500 }) } -} - -export async function GET(request: Request) { - const requestId = crypto.randomUUID().slice(0, 8) - - try { - const { searchParams } = new URL(request.url) - const userId = searchParams.get('userId') - - if (!userId) { - logger.warn(`[${requestId}] Missing userId parameter`) - return NextResponse.json({ error: 'userId is required' }, { status: 400 }) - } - - const result = await db.select().from(settings).where(eq(settings.userId, userId)).limit(1) - - if (!result.length) { - return NextResponse.json( - { - data: { - isAutoConnectEnabled: true, // Return default values - }, - }, - { status: 200 } - ) - } - - const generalSettings = result[0].general as { - isAutoConnectEnabled: boolean - } - return NextResponse.json( - { - data: { - isAutoConnectEnabled: generalSettings.isAutoConnectEnabled, - }, - }, - { status: 200 } - ) - } catch (error: any) { - logger.error(`[${requestId}] Settings fetch error`, error) - return NextResponse.json({ error: error.message }, { status: 500 }) - } -} +} \ No newline at end of file diff --git a/sim/app/layout.tsx b/sim/app/layout.tsx index dd8b10a0d82..859fadf7e9c 100644 --- a/sim/app/layout.tsx +++ b/sim/app/layout.tsx @@ -1,8 +1,8 @@ import type { Metadata, Viewport } from 'next' -import { SpeedInsights } from '@vercel/speed-insights/next' import { createLogger } from '@/lib/logs/console-logger' import './globals.css' import { ZoomPrevention } from './zoom-prevention' +import { TelemetryConsentDialog } from '@/app/telemetry-consent-dialog' const logger = createLogger('RootLayout') @@ -20,9 +20,7 @@ const BROWSER_EXTENSION_ATTRIBUTES = [ if (typeof window !== 'undefined') { const originalError = console.error console.error = (...args) => { - // Check if it's a hydration error if (args[0].includes('Hydration')) { - // Check if the error is related to browser extensions const isExtensionError = BROWSER_EXTENSION_ATTRIBUTES.some((attr) => args.some((arg) => typeof arg === 'string' && arg.includes(attr)) ) @@ -151,7 +149,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) - + {children} diff --git a/sim/app/telemetry-consent-dialog.tsx b/sim/app/telemetry-consent-dialog.tsx new file mode 100644 index 00000000000..85b9560c0c5 --- /dev/null +++ b/sim/app/telemetry-consent-dialog.tsx @@ -0,0 +1,167 @@ +'use client' + +import { useState, useEffect, useRef } from 'react' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle +} from '@/components/ui/alert-dialog' +import { Button } from '@/components/ui/button' +import { useGeneralStore } from '@/stores/settings/general/store' +import { createLogger } from '@/lib/logs/console-logger' + +declare global { + interface Window { + __SIM_TELEMETRY_ENABLED?: boolean + __SIM_TRACK_EVENT?: (eventName: string, properties?: Record) => void + } +} + +const logger = createLogger('TelemetryConsentDialog') + +const trackEvent = (eventName: string, properties?: Record) => { + if (typeof window !== 'undefined' && window.__SIM_TELEMETRY_ENABLED) { + try { + if (window.__SIM_TRACK_EVENT) { + window.__SIM_TRACK_EVENT(eventName, properties) + } + } catch (error) { + logger.error(`Failed to track event ${eventName}:`, error) + } + } +} + +export function TelemetryConsentDialog() { + const [open, setOpen] = useState(false) + const [settingsLoaded, setSettingsLoaded] = useState(false) + const telemetryEnabled = useGeneralStore(state => state.telemetryEnabled) + const telemetryNotifiedUser = useGeneralStore(state => state.telemetryNotifiedUser) + const setTelemetryEnabled = useGeneralStore(state => state.setTelemetryEnabled) + const setTelemetryNotifiedUser = useGeneralStore(state => state.setTelemetryNotifiedUser) + const loadSettings = useGeneralStore(state => state.loadSettings) + + const hasShownDialogThisSession = useRef(false) + + useEffect(() => { + let isMounted = true + const fetchSettings = async () => { + try { + await loadSettings(true) + if (isMounted) { + setSettingsLoaded(true) + } + } catch (error) { + logger.error('Failed to load settings:', error) + if (isMounted) { + setSettingsLoaded(true) + } + } + } + + fetchSettings() + + return () => { + isMounted = false + } + }, [loadSettings]) + + useEffect(() => { + if (!settingsLoaded) return + + logger.debug('Settings loaded state:', { + telemetryNotifiedUser, + telemetryEnabled, + hasShownInSession: hasShownDialogThisSession.current + }) + + // Only show dialog if: + // 1. Settings are fully loaded from the database + // 2. User has not been notified yet (according to database) + // 3. Telemetry is currently enabled (default) + // 4. Dialog hasn't been shown in this session already (extra protection) + if (settingsLoaded && !telemetryNotifiedUser && telemetryEnabled && !hasShownDialogThisSession.current) { + setOpen(true) + hasShownDialogThisSession.current = true + } + }, [settingsLoaded, telemetryNotifiedUser, telemetryEnabled]) + + const handleAccept = () => { + trackEvent('telemetry_consent_accepted', { + source: 'consent_dialog', + defaultEnabled: true + }) + + setTelemetryNotifiedUser(true) + setOpen(false) + } + + const handleDecline = () => { + trackEvent('telemetry_consent_declined', { + source: 'consent_dialog', + defaultEnabled: false + }) + + setTelemetryEnabled(false) + setTelemetryNotifiedUser(true) + setOpen(false) + } + + return ( + + + + Telemetry + + +
+
+ To help us improve Sim Studio, we collect anonymous usage + data by default. This helps us understand which features are + most useful and identify areas for improvement. +
+ +
+
We only collect:
+
    +
  • Feature usage statistics
  • +
  • Error reports (without personal info)
  • +
  • Performance metrics
  • +
+
+ +
+
We never collect:
+
    +
  • Personal information
  • +
  • Workflow content or outputs
  • +
  • API keys or tokens
  • +
  • IP addresses or location data
  • +
+
+ +
+ You can change this setting anytime in{' '} + Settings → Privacy. +
+
+ + + + + + + + + +
+
+ ) +} \ No newline at end of file diff --git a/sim/app/w/components/sidebar/components/settings-modal/components/general/general.tsx b/sim/app/w/components/sidebar/components/settings-modal/components/general/general.tsx index 2f2cbf5da7c..fbfea88f76a 100644 --- a/sim/app/w/components/sidebar/components/settings-modal/components/general/general.tsx +++ b/sim/app/w/components/sidebar/components/settings-modal/components/general/general.tsx @@ -1,5 +1,6 @@ import { useRouter } from 'next/navigation' -import { Info } from 'lucide-react' +import { Info, AlertTriangle } from 'lucide-react' +import { useEffect, useState } from 'react' import { AlertDialog, AlertDialogAction, @@ -20,10 +21,12 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select' +import { Skeleton } from '@/components/ui/skeleton' import { Switch } from '@/components/ui/switch' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import { useGeneralStore } from '@/stores/settings/general/store' +import { Alert, AlertDescription } from '@/components/ui/alert' import { resetAllStores } from '@/stores' +import { useGeneralStore } from '@/stores/settings/general/store' const TOOLTIPS = { debugMode: 'Enable visual debugging information during execution.', @@ -34,123 +37,200 @@ const TOOLTIPS = { export function General() { const router = useRouter() - const isAutoConnectEnabled = useGeneralStore((state) => state.isAutoConnectEnabled) - const toggleAutoConnect = useGeneralStore((state) => state.toggleAutoConnect) - const isDebugModeEnabled = useGeneralStore((state) => state.isDebugModeEnabled) - const toggleDebugMode = useGeneralStore((state) => state.toggleDebugMode) - const isAutoFillEnvVarsEnabled = useGeneralStore((state) => state.isAutoFillEnvVarsEnabled) - const toggleAutoFillEnvVars = useGeneralStore((state) => state.toggleAutoFillEnvVars) - const theme = useGeneralStore((state) => state.theme) - const setTheme = useGeneralStore((state) => state.setTheme) + const [retryCount, setRetryCount] = useState(0) + + const isLoading = useGeneralStore(state => state.isLoading) + const error = useGeneralStore(state => state.error) + const theme = useGeneralStore(state => state.theme) + const isAutoConnectEnabled = useGeneralStore(state => state.isAutoConnectEnabled) + const isDebugModeEnabled = useGeneralStore(state => state.isDebugModeEnabled) + const isAutoFillEnvVarsEnabled = useGeneralStore(state => state.isAutoFillEnvVarsEnabled) + + const setTheme = useGeneralStore(state => state.setTheme) + const toggleAutoConnect = useGeneralStore(state => state.toggleAutoConnect) + const toggleDebugMode = useGeneralStore(state => state.toggleDebugMode) + const toggleAutoFillEnvVars = useGeneralStore(state => state.toggleAutoFillEnvVars) + const loadSettings = useGeneralStore(state => state.loadSettings) + + useEffect(() => { + const loadData = async () => { + await loadSettings(retryCount > 0) + } + loadData() + }, [loadSettings, retryCount]) + + const handleThemeChange = (value: 'system' | 'light' | 'dark') => { + setTheme(value) + } + + const handleDebugModeChange = (checked: boolean) => { + if (checked !== isDebugModeEnabled) { + toggleDebugMode() + } + } + + const handleAutoConnectChange = (checked: boolean) => { + if (checked !== isAutoConnectEnabled) { + toggleAutoConnect() + } + } + + const handleAutoFillEnvVarsChange = (checked: boolean) => { + if (checked !== isAutoFillEnvVarsEnabled) { + toggleAutoFillEnvVars() + } + } const handleResetData = () => { resetAllStores() router.push('/w/1') // Redirect to home page after reset } + const handleRetry = () => { + setRetryCount(prev => prev + 1) + } + return (
+ {error && ( + + + + Failed to load settings: {error} + + + + )} +

General Settings

-
-
- -
- -
-
-
- - - - - - -

{TOOLTIPS.debugMode}

-
-
-
- -
-
-
- - - - - - -

{TOOLTIPS.autoConnect}

-
-
-
- -
-
-
- - - - - - -

{TOOLTIPS.autoFillEnvVars}

-
-
-
- -
+ {isLoading ? ( + <> + + + + + + ) : ( + <> +
+
+ +
+ +
+
+
+ + + + + + +

{TOOLTIPS.debugMode}

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

{TOOLTIPS.autoConnect}

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

{TOOLTIPS.autoFillEnvVars}

+
+
+
+ +
+ + )}
@@ -166,6 +246,7 @@ export function General() { size="sm" className="text-gray-500 p-1 h-7" aria-label="Learn more about resetting all data" + disabled={isLoading} > @@ -177,7 +258,7 @@ export function General() {
- @@ -205,3 +286,12 @@ export function General() { ) } + +const SettingRowSkeleton = () => ( +
+
+ +
+ +
+) diff --git a/sim/app/w/components/sidebar/components/settings-modal/components/privacy/privacy.tsx b/sim/app/w/components/sidebar/components/settings-modal/components/privacy/privacy.tsx new file mode 100644 index 00000000000..77ca1cd3555 --- /dev/null +++ b/sim/app/w/components/sidebar/components/settings-modal/components/privacy/privacy.tsx @@ -0,0 +1,107 @@ +'use client' + +import { useEffect } from 'react' +import { Info } from 'lucide-react' +import { Switch } from '@/components/ui/switch' +import { Label } from '@/components/ui/label' +import { Button } from '@/components/ui/button' +import { Skeleton } from '@/components/ui/skeleton' +import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' +import { useGeneralStore } from '@/stores/settings/general/store' + +const TOOLTIPS = { + telemetry: 'We collect anonymous data about feature usage, performance, and errors to improve the application.', +} + +export function Privacy() { + const isLoading = useGeneralStore(state => state.isLoading) + const telemetryEnabled = useGeneralStore(state => state.telemetryEnabled) + const setTelemetryEnabled = useGeneralStore(state => state.setTelemetryEnabled) + const setTelemetryNotifiedUser = useGeneralStore(state => state.setTelemetryNotifiedUser) + const loadSettings = useGeneralStore(state => state.loadSettings) + + useEffect(() => { + loadSettings() + }, [loadSettings]) + + const handleTelemetryToggle = (checked: boolean) => { + setTelemetryEnabled(checked) + + if (checked) { + setTelemetryNotifiedUser(true) + + if (typeof window !== 'undefined') { + fetch('/api/telemetry', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + category: 'consent', + action: 'enable_from_settings', + timestamp: new Date().toISOString(), + }), + }).catch(() => { + // Silently fail - this is just telemetry + }) + } + } + } + + return ( +
+
+

Privacy Settings

+
+ {isLoading ? ( + + ) : ( +
+
+ + + + + + +

{TOOLTIPS.telemetry}

+
+
+
+ +
+ )} +
+
+ +
+

+ We use OpenTelemetry to collect anonymous usage data to improve Sim Studio. + All data is collected in accordance with our privacy policy, and you can opt-out at any time. + This setting applies to your account on all devices. +

+
+
+ ) +} + +const SettingRowSkeleton = () => ( +
+
+ +
+ +
+ ) \ No newline at end of file diff --git a/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx b/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx index 3a90ab3194c..b36bcc2bb6f 100644 --- a/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx +++ b/sim/app/w/components/sidebar/components/settings-modal/components/settings-navigation/settings-navigation.tsx @@ -1,17 +1,17 @@ -import { Key, KeyRound, KeySquare, Settings, UserCircle, CreditCard, Users } from 'lucide-react' +import { Key, KeyRound, KeySquare, Settings, UserCircle, CreditCard, Users, Shield } from 'lucide-react' import { cn } from '@/lib/utils' import { isDev } from '@/lib/environment' interface SettingsNavigationProps { activeSection: string onSectionChange: ( - section: 'general' | 'environment' | 'account' | 'credentials' | 'apikeys' | 'subscription' | 'team' + section: 'general' | 'environment' | 'account' | 'credentials' | 'apikeys' | 'subscription' | 'team' | 'privacy' ) => void isTeam?: boolean } type NavigationItem = { - id: 'general' | 'environment' | 'account' | 'credentials' | 'apikeys' | 'subscription' | 'team' + id: 'general' | 'environment' | 'account' | 'credentials' | 'apikeys' | 'subscription' | 'team' | 'privacy' label: string icon: React.ComponentType<{ className?: string }> hideInDev?: boolean @@ -44,6 +44,11 @@ const allNavigationItems: NavigationItem[] = [ label: 'API Keys', icon: KeySquare, }, + { + id: 'privacy', + label: 'Privacy', + icon: Shield, + }, { id: 'subscription', label: 'Subscription', diff --git a/sim/app/w/components/sidebar/components/settings-modal/components/subscription/subscription.tsx b/sim/app/w/components/sidebar/components/settings-modal/components/subscription/subscription.tsx index 3defe960826..9b36254bdc9 100644 --- a/sim/app/w/components/sidebar/components/settings-modal/components/subscription/subscription.tsx +++ b/sim/app/w/components/sidebar/components/settings-modal/components/subscription/subscription.tsx @@ -1,5 +1,5 @@ -import { useState, useEffect } from 'react' -import { client, useSession, useActiveOrganization } from '@/lib/auth-client' +import { useState, useEffect, useMemo } from 'react' +import { client, useSession, useActiveOrganization, useSubscription } from '@/lib/auth-client' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { AlertCircle } from 'lucide-react' import { Button } from '@/components/ui/button' @@ -27,29 +27,58 @@ const logger = createLogger('Subscription') interface SubscriptionProps { onOpenChange: (open: boolean) => void + cachedIsPro?: boolean + cachedIsTeam?: boolean + cachedUsageData?: any + cachedSubscriptionData?: any + isLoading?: boolean } -const useSubscriptionData = (userId: string | null | undefined, activeOrgId: string | null | undefined) => { - const [isPro, setIsPro] = useState(false) - const [isTeam, setIsTeam] = useState(false) +const useSubscriptionData = ( + userId: string | null | undefined, + activeOrgId: string | null | undefined, + cachedIsPro?: boolean, + cachedIsTeam?: boolean, + cachedUsageData?: any, + cachedSubscriptionData?: any, + isParentLoading?: boolean +) => { + const [isPro, setIsPro] = useState(cachedIsPro || false) + const [isTeam, setIsTeam] = useState(cachedIsTeam || false) const [usageData, setUsageData] = useState<{ - percentUsed: number; - isWarning: boolean; - isExceeded: boolean; - currentUsage: number; - limit: number; - }>({ + percentUsed: number + isWarning: boolean + isExceeded: boolean + currentUsage: number + limit: number + }>(cachedUsageData || { percentUsed: 0, isWarning: false, isExceeded: false, currentUsage: 0, limit: 0 }) - const [subscriptionData, setSubscriptionData] = useState(null) - const [loading, setLoading] = useState(true) + const [subscriptionData, setSubscriptionData] = useState(cachedSubscriptionData || null) + const [loading, setLoading] = useState(isParentLoading !== undefined ? isParentLoading : true) const [error, setError] = useState(null) + const subscription = useSubscription() useEffect(() => { + if ( + isParentLoading !== undefined || + (cachedIsPro !== undefined && + cachedIsTeam !== undefined && + cachedUsageData && + cachedSubscriptionData) + ) { + if (cachedIsPro !== undefined) setIsPro(cachedIsPro) + if (cachedIsTeam !== undefined) setIsTeam(cachedIsTeam) + if (cachedUsageData) setUsageData(cachedUsageData) + if (cachedSubscriptionData) setSubscriptionData(cachedSubscriptionData) + if (isParentLoading !== undefined) setLoading(isParentLoading) + return + } + async function loadSubscriptionData() { if (!userId) return @@ -92,15 +121,18 @@ const useSubscriptionData = (userId: string | null | undefined, activeOrgId: str logger.info('Checking organization subscription first', { orgId: activeOrgId }) // Get the organization's subscription - const { data: orgSubscriptions, error: orgSubError } = await client.subscription.list({ + const result = await subscription.list({ query: { referenceId: activeOrgId } }) + const orgSubscriptions = result.data + const orgSubError = 'error' in result ? result.error : null + if (orgSubError) { logger.error('Error fetching organization subscription details', orgSubError) - } else { + } else if (orgSubscriptions) { // Find active team subscription for the organization - activeSubscription = orgSubscriptions?.find( + activeSubscription = orgSubscriptions.find( sub => sub.status === 'active' && sub.plan === 'team' ) @@ -116,13 +148,16 @@ const useSubscriptionData = (userId: string | null | undefined, activeOrgId: str // If no org team subscription was found, check for personal subscription if (!activeSubscription) { // Fetch detailed subscription data for the user - const { data: userSubscriptions, error: userSubError } = await client.subscription.list() + const result = await subscription.list() + + const userSubscriptions = result.data + const userSubError = 'error' in result ? result.error : null if (userSubError) { logger.error('Error fetching user subscription details', userSubError) - } else { + } else if (userSubscriptions) { // Find active subscription for the user - activeSubscription = userSubscriptions?.find( + activeSubscription = userSubscriptions.find( sub => sub.status === 'active' ) } @@ -148,14 +183,22 @@ const useSubscriptionData = (userId: string | null | undefined, activeOrgId: str } loadSubscriptionData() - }, [userId, activeOrgId]) + }, [userId, activeOrgId, subscription, cachedIsPro, cachedIsTeam, cachedUsageData, cachedSubscriptionData, isParentLoading]) return { isPro, isTeam, usageData, subscriptionData, loading, error } } -export function Subscription({ onOpenChange }: SubscriptionProps) { +export function Subscription({ + onOpenChange, + cachedIsPro, + cachedIsTeam, + cachedUsageData, + cachedSubscriptionData, + isLoading +}: SubscriptionProps) { const { data: session } = useSession() const { data: activeOrg } = useActiveOrganization() + const subscription = useSubscription() const { isPro, @@ -164,7 +207,15 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { subscriptionData, loading, error: subscriptionError - } = useSubscriptionData(session?.user?.id, activeOrg?.id) + } = useSubscriptionData( + session?.user?.id, + activeOrg?.id, + cachedIsPro, + cachedIsTeam, + cachedUsageData, + cachedSubscriptionData, + isLoading + ) const [isCanceling, setIsCanceling] = useState(false) const [error, setError] = useState(null) @@ -190,15 +241,15 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { setError(null) try { - const { error } = await client.subscription.upgrade({ + const result = await subscription.upgrade({ plan: plan, successUrl: window.location.href, cancelUrl: window.location.href, }) - if (error) { - setError(error.message || `There was an error upgrading to the ${plan} plan`) - logger.error('Subscription upgrade error:', error) + if ('error' in result && result.error) { + setError(result.error.message || `There was an error upgrading to the ${plan} plan`) + logger.error('Subscription upgrade error:', result.error) } } catch (error: any) { logger.error('Subscription upgrade exception:', error) @@ -218,13 +269,13 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { setError(null) try { - const { error } = await client.subscription.cancel({ + const result = await subscription.cancel({ returnUrl: window.location.href, }) - if (error) { - setError(error.message || 'There was an error canceling your subscription') - logger.error('Subscription cancellation error:', error) + if ('error' in result && result.error) { + setError(result.error.message || 'There was an error canceling your subscription') + logger.error('Subscription cancellation error:', result.error) } } catch (error: any) { logger.error('Subscription cancellation exception:', error) @@ -248,17 +299,18 @@ export function Subscription({ onOpenChange }: SubscriptionProps) { setError(null) try { - const { error } = await client.subscription.upgrade({ + const result = await subscription.upgrade({ plan: 'team', + seats, successUrl: window.location.href, cancelUrl: window.location.href, - seats: seats }) - if (error) { - setError(error.message || 'There was an error upgrading to the team plan') - logger.error('Team subscription upgrade error:', error) + if ('error' in result && result.error) { + setError(result.error.message || 'There was an error upgrading to the team plan') + logger.error('Team subscription upgrade error:', result.error) } else { + // Close the dialog after successful upgrade setIsTeamDialogOpen(false) } } catch (error: any) { diff --git a/sim/app/w/components/sidebar/components/settings-modal/settings-modal.tsx b/sim/app/w/components/sidebar/components/settings-modal/settings-modal.tsx index 4d5cb740d5d..e42a1d308be 100644 --- a/sim/app/w/components/sidebar/components/settings-modal/settings-modal.tsx +++ b/sim/app/w/components/sidebar/components/settings-modal/settings-modal.tsx @@ -1,16 +1,18 @@ 'use client' -import { useEffect, useState } from 'react' +import { useEffect, useState, useMemo, useRef } from 'react' import { X } from 'lucide-react' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { cn } from '@/lib/utils' -import { client } from '@/lib/auth-client' +import { client, useSubscription } from '@/lib/auth-client' +import { useGeneralStore } from '@/stores/settings/general/store' import { Account } from './components/account/account' import { ApiKeys } from './components/api-keys/api-keys' import { Credentials } from './components/credentials/credentials' import { EnvironmentVariables } from './components/environment/environment' import { General } from './components/general/general' +import { Privacy } from './components/privacy/privacy' import { Subscription } from './components/subscription/subscription' import { SettingsNavigation } from './components/settings-navigation/settings-navigation' import { TeamManagement } from './components/team-management/team-management' @@ -23,52 +25,92 @@ interface SettingsModalProps { onOpenChange: (open: boolean) => void } -type SettingsSection = 'general' | 'environment' | 'account' | 'credentials' | 'apikeys' | 'subscription' | 'team' +type SettingsSection = 'general' | 'environment' | 'account' | 'credentials' | 'apikeys' | 'subscription' | 'team' | 'privacy' export function SettingsModal({ open, onOpenChange }: SettingsModalProps) { const [activeSection, setActiveSection] = useState('general') + const [isPro, setIsPro] = useState(false) const [isTeam, setIsTeam] = useState(false) + const [subscriptionData, setSubscriptionData] = useState(null) + const [usageData, setUsageData] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const loadSettings = useGeneralStore(state => state.loadSettings) + const subscription = useMemo(() => useSubscription(), []) + const hasLoadedInitialData = useRef(false) - // Listen for the custom event to open the settings modal with a specific tab useEffect(() => { - const handleOpenSettings = (event: CustomEvent<{ tab: SettingsSection }>) => { - setActiveSection(event.detail.tab) - onOpenChange(true) - } - - // Add event listener - window.addEventListener('open-settings', handleOpenSettings as EventListener) - - // Clean up - return () => { - window.removeEventListener('open-settings', handleOpenSettings as EventListener) - } - }, [onOpenChange]) - - // Check if user is on team plan - useEffect(() => { - async function checkTeamPlan() { + async function loadAllSettings() { + if (!open) return + + if (hasLoadedInitialData.current) return + + setIsLoading(true) + try { - const response = await fetch('/api/user/subscription') - if (response.ok) { - const data = await response.json() - setIsTeam(data.isTeam) + await loadSettings() + + const proStatusResponse = await fetch('/api/user/subscription') + + if (proStatusResponse.ok) { + const subData = await proStatusResponse.json() + setIsPro(subData.isPro) + setIsTeam(subData.isTeam) - if (!data.isTeam && activeSection === 'team') { + if (!subData.isTeam && activeSection === 'team') { setActiveSection('general') } } + + const usageResponse = await fetch('/api/user/usage') + if (usageResponse.ok) { + const usageData = await usageResponse.json() + setUsageData(usageData) + } + + try { + const result = await subscription.list() + + if (result.data && result.data.length > 0) { + const activeSubscription = result.data.find( + sub => sub.status === 'active' && (sub.plan === 'team' || sub.plan === 'pro') + ) + + if (activeSubscription) { + setSubscriptionData(activeSubscription) + } + } + } catch (error) { + logger.error('Error fetching subscription information', error) + } + + hasLoadedInitialData.current = true } catch (error) { - logger.error('Error checking team plan:', error) + logger.error('Error loading settings data:', error) + } finally { + setIsLoading(false) } } if (open) { - checkTeamPlan() + loadAllSettings() + } else { + hasLoadedInitialData.current = false + } + }, [open, loadSettings, subscription, activeSection]) + + useEffect(() => { + const handleOpenSettings = (event: CustomEvent<{ tab: SettingsSection }>) => { + setActiveSection(event.detail.tab) + onOpenChange(true) } - }, [open, activeSection]) - // Check if subscriptions are enabled + window.addEventListener('open-settings', handleOpenSettings as EventListener) + + return () => { + window.removeEventListener('open-settings', handleOpenSettings as EventListener) + } + }, [onOpenChange]) + const isSubscriptionEnabled = !!client.subscription return ( @@ -116,9 +158,19 @@ export function SettingsModal({ open, onOpenChange }: SettingsModalProps) {
+
+ +
{isSubscriptionEnabled && (
- +
)} {isTeam && ( diff --git a/sim/db/migrations/0033_solid_stellaris.sql b/sim/db/migrations/0033_solid_stellaris.sql new file mode 100644 index 00000000000..9fbebc581c8 --- /dev/null +++ b/sim/db/migrations/0033_solid_stellaris.sql @@ -0,0 +1,7 @@ +ALTER TABLE "settings" ALTER COLUMN "general" SET DEFAULT '{}';--> statement-breakpoint +ALTER TABLE "settings" ADD COLUMN "theme" text DEFAULT 'system' NOT NULL;--> statement-breakpoint +ALTER TABLE "settings" ADD COLUMN "debug_mode" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "settings" ADD COLUMN "auto_connect" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "settings" ADD COLUMN "auto_fill_env_vars" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "settings" ADD COLUMN "telemetry_enabled" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "settings" ADD COLUMN "telemetry_notified_user" boolean DEFAULT false NOT NULL; \ No newline at end of file diff --git a/sim/db/migrations/meta/0033_snapshot.json b/sim/db/migrations/meta/0033_snapshot.json new file mode 100644 index 00000000000..b80825d8cba --- /dev/null +++ b/sim/db/migrations/meta/0033_snapshot.json @@ -0,0 +1,1780 @@ +{ + "id": "63b24919-044d-4c5b-aa42-934f90466ea4", + "prevId": "d366f442-d591-47f0-af39-8e6c5370e58c", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_key": { + "name": "api_key", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "api_key_user_id_user_id_fk": { + "name": "api_key_user_id_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_key_key_unique": { + "name": "api_key_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat": { + "name": "chat", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subdomain": { + "name": "subdomain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "customizations": { + "name": "customizations", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "output_configs": { + "name": "output_configs", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "subdomain_idx": { + "name": "subdomain_idx", + "columns": [ + { + "expression": "subdomain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_workflow_id_workflow_id_fk": { + "name": "chat_workflow_id_workflow_id_fk", + "tableFrom": "chat", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_user_id_user_id_fk": { + "name": "chat_user_id_user_id_fk", + "tableFrom": "chat", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_tools": { + "name": "custom_tools", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schema": { + "name": "schema", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "custom_tools_user_id_user_id_fk": { + "name": "custom_tools_user_id_user_id_fk", + "tableFrom": "custom_tools", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environment_user_id_user_id_fk": { + "name": "environment_user_id_user_id_fk", + "tableFrom": "environment", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environment_user_id_unique": { + "name": "environment_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.marketplace": { + "name": "marketplace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author_name": { + "name": "author_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "views": { + "name": "views", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "marketplace_workflow_id_workflow_id_fk": { + "name": "marketplace_workflow_id_workflow_id_fk", + "tableFrom": "marketplace", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "marketplace_author_id_user_id_fk": { + "name": "marketplace_author_id_user_id_fk", + "tableFrom": "marketplace", + "tableTo": "user", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_active_organization_id_organization_id_fk": { + "name": "session_active_organization_id_organization_id_fk", + "tableFrom": "session", + "tableTo": "organization", + "columnsFrom": [ + "active_organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'system'" + }, + "debug_mode": { + "name": "debug_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_connect": { + "name": "auto_connect", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auto_fill_env_vars": { + "name": "auto_fill_env_vars", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "telemetry_notified_user": { + "name": "telemetry_notified_user", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "general": { + "name": "general", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "settings_user_id_user_id_fk": { + "name": "settings_user_id_user_id_fk", + "tableFrom": "settings", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "settings_user_id_unique": { + "name": "settings_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subscription": { + "name": "subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_subscription_id": { + "name": "stripe_subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "period_start": { + "name": "period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "period_end": { + "name": "period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "seats": { + "name": "seats", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trial_start": { + "name": "trial_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trial_end": { + "name": "trial_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_stats": { + "name": "user_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_manual_executions": { + "name": "total_manual_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_api_calls": { + "name": "total_api_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_webhook_triggers": { + "name": "total_webhook_triggers", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_scheduled_executions": { + "name": "total_scheduled_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tokens_used": { + "name": "total_tokens_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_active": { + "name": "last_active", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_stats_user_id_user_id_fk": { + "name": "user_stats_user_id_user_id_fk", + "tableFrom": "user_stats", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_stats_user_id_unique": { + "name": "user_stats_user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.waitlist": { + "name": "waitlist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "waitlist_email_unique": { + "name": "waitlist_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook": { + "name": "webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_config": { + "name": "provider_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "path_idx": { + "name": "path_idx", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_workflow_id_workflow_id_fk": { + "name": "webhook_workflow_id_workflow_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#3972F6'" + }, + "last_synced": { + "name": "last_synced", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_deployed": { + "name": "is_deployed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deployed_state": { + "name": "deployed_state", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "deployed_at": { + "name": "deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "collaborators": { + "name": "collaborators", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "marketplace_data": { + "name": "marketplace_data", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_user_id_user_id_fk": { + "name": "workflow_user_id_user_id_fk", + "tableFrom": "workflow", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_logs": { + "name": "workflow_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "duration": { + "name": "duration", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_logs_workflow_id_workflow_id_fk": { + "name": "workflow_logs_workflow_id_workflow_id_fk", + "tableFrom": "workflow_logs", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_schedule": { + "name": "workflow_schedule", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_ran_at": { + "name": "last_ran_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trigger_type": { + "name": "trigger_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'UTC'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_schedule_workflow_id_workflow_id_fk": { + "name": "workflow_schedule_workflow_id_workflow_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workflow_schedule_workflow_id_unique": { + "name": "workflow_schedule_workflow_id_unique", + "nullsNotDistinct": false, + "columns": [ + "workflow_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/sim/db/migrations/meta/_journal.json b/sim/db/migrations/meta/_journal.json index b5340f6fe43..fa9a6afe3f6 100644 --- a/sim/db/migrations/meta/_journal.json +++ b/sim/db/migrations/meta/_journal.json @@ -232,6 +232,13 @@ "when": 1745973220228, "tag": "0032_rare_nico_minoru", "breakpoints": true + }, + { + "idx": 33, + "version": "7", + "when": 1746037443324, + "tag": "0033_solid_stellaris", + "breakpoints": true } ] } \ No newline at end of file diff --git a/sim/db/schema.ts b/sim/db/schema.ts index e0cc66f6d0e..a96da2185e9 100644 --- a/sim/db/schema.ts +++ b/sim/db/schema.ts @@ -19,7 +19,7 @@ export const user = pgTable('user', { createdAt: timestamp('created_at').notNull(), updatedAt: timestamp('updated_at').notNull(), stripeCustomerId: text('stripe_customer_id') -}); +}) export const session = pgTable('session', { id: text('id').primaryKey(), @@ -126,7 +126,20 @@ export const settings = pgTable('settings', { .notNull() .references(() => user.id, { onDelete: 'cascade' }) .unique(), // One settings record per user - general: json('general').notNull(), + + // General settings + theme: text('theme').notNull().default('system'), + debugMode: boolean('debug_mode').notNull().default(false), + autoConnect: boolean('auto_connect').notNull().default(true), + autoFillEnvVars: boolean('auto_fill_env_vars').notNull().default(true), + + // Privacy settings + telemetryEnabled: boolean('telemetry_enabled').notNull().default(true), + telemetryNotifiedUser: boolean('telemetry_notified_user').notNull().default(false), + + // Keep general for future flexible settings + general: json('general').notNull().default('{}'), + updatedAt: timestamp('updated_at').notNull().defaultNow(), }) @@ -238,7 +251,7 @@ export const subscription = pgTable("subscription", { seats: integer('seats'), trialStart: timestamp('trial_start'), trialEnd: timestamp('trial_end') -}); +}) export const chat = pgTable('chat', { id: text('id').primaryKey(), @@ -281,7 +294,7 @@ export const organization = pgTable("organization", { metadata: jsonb('metadata'), createdAt: timestamp('created_at').defaultNow().notNull(), updatedAt: timestamp('updated_at').defaultNow().notNull(), -}); +}) export const member = pgTable("member", { id: text('id').primaryKey(), @@ -289,7 +302,7 @@ export const member = pgTable("member", { organizationId: text('organization_id').notNull().references(() => organization.id, { onDelete: 'cascade' }), role: text('role').notNull(), createdAt: timestamp('created_at').defaultNow().notNull() -}); +}) export const invitation = pgTable("invitation", { id: text('id').primaryKey(), @@ -300,4 +313,4 @@ export const invitation = pgTable("invitation", { status: text('status').notNull(), expiresAt: timestamp('expires_at').notNull(), createdAt: timestamp('created_at').defaultNow().notNull() -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/sim/executor/index.ts b/sim/executor/index.ts index aa6a1ea133e..0d8a17f9b64 100644 --- a/sim/executor/index.ts +++ b/sim/executor/index.ts @@ -26,6 +26,25 @@ import { const logger = createLogger('Executor') +/** + * Tracks telemetry events for workflow execution if telemetry is enabled + */ +function trackWorkflowTelemetry(eventName: string, data: Record) { + if (typeof window !== 'undefined' && window.__SIM_TRACK_EVENT) { + // Add timestamp and sanitize the data to avoid circular references + const safeData = { + ...data, + timestamp: Date.now() + } + + // Track the event through the global telemetry function + window.__SIM_TRACK_EVENT(eventName, { + category: 'workflow', + ...safeData + }) + } +} + /** * Core execution engine that runs workflow blocks in topological order. * @@ -89,6 +108,14 @@ export class Executor { const startTime = new Date() let finalOutput: NormalizedBlockOutput = { response: {} } + // Track workflow execution start + trackWorkflowTelemetry('workflow_execution_started', { + workflowId, + blockCount: this.workflow.blocks.length, + connectionCount: this.workflow.connections.length, + startTime: startTime.toISOString() + }) + this.validateWorkflow() const context = this.createExecutionContext(workflowId, startTime) @@ -162,12 +189,23 @@ export class Executor { const endTime = new Date() context.metadata.endTime = endTime.toISOString() + const duration = endTime.getTime() - startTime.getTime() + + trackWorkflowTelemetry('workflow_execution_completed', { + workflowId, + duration, + blockCount: this.workflow.blocks.length, + executedBlockCount: context.executedBlocks.size, + startTime: startTime.toISOString(), + endTime: endTime.toISOString(), + success: true + }) return { success: true, output: finalOutput, metadata: { - duration: endTime.getTime() - startTime.getTime(), + duration: duration, startTime: context.metadata.startTime!, endTime: context.metadata.endTime!, workflowConnections: this.workflow.connections.map((conn) => ({ @@ -180,6 +218,15 @@ export class Executor { } catch (error: any) { logger.error('Workflow execution failed:', this.sanitizeError(error)) + // Track workflow execution failure + trackWorkflowTelemetry('workflow_execution_failed', { + workflowId, + duration: new Date().getTime() - startTime.getTime(), + error: this.extractErrorMessage(error), + executedBlockCount: context.executedBlocks.size, + blockLogs: context.blockLogs.length + }) + return { success: false, output: finalOutput, @@ -732,6 +779,16 @@ export class Executor { // Resolve inputs (which will look up references to other blocks including starter) const inputs = this.resolver.resolveInputs(block, context) + // Track block execution start + trackWorkflowTelemetry('block_execution_start', { + workflowId: context.workflowId, + blockId: block.id, + blockType: block.metadata?.id || 'unknown', + blockName: block.metadata?.name || 'Unnamed Block', + inputSize: Object.keys(inputs).length, + startTime: new Date().toISOString() + }) + // Find the appropriate handler const handler = this.blockHandlers.find((h) => h.canHandle(block)) if (!handler) { @@ -780,6 +837,15 @@ export class Executor { blockType: block.metadata?.id || 'unknown', }) + trackWorkflowTelemetry('block_execution', { + workflowId: context.workflowId, + blockId: block.id, + blockType: block.metadata?.id || 'unknown', + blockName: block.metadata?.name || 'Unnamed Block', + durationMs: Math.round(executionTime), + success: true + }) + return output } catch (error: any) { // Remove this block from active blocks if there's an error @@ -859,6 +925,16 @@ export class Executor { } } + trackWorkflowTelemetry('block_execution_error', { + workflowId: context.workflowId, + blockId: block.id, + blockType: block.metadata?.id || 'unknown', + blockName: block.metadata?.name || 'Unnamed Block', + durationMs: blockLog.durationMs, + errorType: error.name || 'Error', + errorMessage: this.extractErrorMessage(error) + }) + throw new Error(errorMessage) } } diff --git a/sim/instrumentation-client.ts b/sim/instrumentation-client.ts new file mode 100644 index 00000000000..d8dfb57ab4e --- /dev/null +++ b/sim/instrumentation-client.ts @@ -0,0 +1,238 @@ +/** + * Sim Studio Telemetry - Client-side Instrumentation + * + * This file initializes client-side telemetry when the app loads in the browser. + * It respects the user's telemetry preferences stored in localStorage. + * + */ + +if (typeof window !== 'undefined') { + const TELEMETRY_STATUS_KEY = 'simstudio-telemetry-status' + let telemetryEnabled = true + + try { + if (process.env.NEXT_TELEMETRY_DISABLED === '1') { + telemetryEnabled = false + } else { + const storedPreference = localStorage.getItem(TELEMETRY_STATUS_KEY) + if (storedPreference) { + const status = JSON.parse(storedPreference) + telemetryEnabled = status.enabled + } + } + } catch (e) { + telemetryEnabled = false + } + + /** + * Safe serialize function to ensure we don't include circular references or invalid data + */ + function safeSerialize(obj: any): any { + if (obj === null || obj === undefined) return null + if (typeof obj !== 'object') return obj + + if (Array.isArray(obj)) { + return obj.map(item => safeSerialize(item)) + } + + const result: Record = {} + + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + const value = obj[key] + if (value === undefined || value === null || typeof value === 'function' || typeof value === 'symbol') { + continue + } + + try { + result[key] = safeSerialize(value) + } catch (e) { + try { + result[key] = String(value) + } catch (e2) { + } + } + } + } + + return result + } + + (window as any).__SIM_TELEMETRY_ENABLED = telemetryEnabled; + (window as any).__SIM_TRACK_EVENT = (eventName: string, properties?: any) => { + if (!telemetryEnabled) return + + const safeProps = properties || {} + + const payload = { + category: 'feature_usage', + action: eventName || 'unknown_event', + timestamp: Date.now(), + ...safeSerialize(safeProps) + } + + fetch('/api/telemetry', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload), + }).catch(() => { + // Silently fail if sending metrics fails + }) + } + + if (telemetryEnabled) { + performance.mark('sim-studio-init') + + let telemetryConfig + try { + telemetryConfig = (window as any).__SIM_STUDIO_TELEMETRY_CONFIG || { + clientSide: { enabled: true }, + } + } catch (e) { + telemetryConfig = { clientSide: { enabled: true } } + } + + window.addEventListener('load', () => { + performance.mark('sim-studio-loaded') + performance.measure('page-load', 'sim-studio-init', 'sim-studio-loaded') + + if (typeof PerformanceObserver !== 'undefined') { + const lcpObserver = new PerformanceObserver((list) => { + const entries = list.getEntries() + + entries.forEach(entry => { + const value = entry.entryType === 'largest-contentful-paint' + ? (entry as any).startTime + : (entry as any).value || 0 + + // Ensure we have non-null values for all fields + const metric = { + name: entry.name || 'unknown', + value: value || 0, + entryType: entry.entryType || 'unknown' + } + + if (telemetryEnabled && telemetryConfig?.clientSide?.enabled) { + const safePayload = { + category: 'performance', + action: 'web_vital', + label: metric.name, + value: metric.value, + entryType: metric.entryType, + timestamp: Date.now() + } + + fetch('/api/telemetry', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(safePayload), + }).catch(() => { + // Silently fail if sending metrics fails + }) + } + }) + + lcpObserver.disconnect() + }) + + const clsObserver = new PerformanceObserver((list) => { + const entries = list.getEntries() + let clsValue = 0 + + entries.forEach(entry => { + clsValue += (entry as any).value || 0 + }) + + if (telemetryEnabled && telemetryConfig?.clientSide?.enabled) { + const safePayload = { + category: 'performance', + action: 'web_vital', + label: 'CLS', + value: clsValue || 0, + entryType: 'layout-shift', + timestamp: Date.now() + } + + fetch('/api/telemetry', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(safePayload), + }).catch(() => { + // Silently fail if sending metrics fails + }) + } + + clsObserver.disconnect() + }) + + const fidObserver = new PerformanceObserver((list) => { + const entries = list.getEntries() + + entries.forEach(entry => { + const processingStart = (entry as any).processingStart || 0 + const startTime = (entry as any).startTime || 0 + + const metric = { + name: entry.name || 'unknown', + value: processingStart - startTime, + entryType: entry.entryType || 'unknown' + } + + if (telemetryEnabled && telemetryConfig?.clientSide?.enabled) { + const safePayload = { + category: 'performance', + action: 'web_vital', + label: 'FID', + value: metric.value, + entryType: metric.entryType, + timestamp: Date.now() + } + + fetch('/api/telemetry', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(safePayload), + }).catch(() => { + // Silently fail if sending metrics fails + }) + } + }) + + fidObserver.disconnect() + }) + + lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true }) + clsObserver.observe({ type: 'layout-shift', buffered: true }) + fidObserver.observe({ type: 'first-input', buffered: true }) + } + }) + + window.addEventListener('error', (event) => { + if (telemetryEnabled && telemetryConfig?.clientSide?.enabled) { + const errorDetails = { + message: event.error?.message || 'Unknown error', + stack: event.error?.stack?.split('\n')[0] || '', + url: window.location.pathname, + timestamp: Date.now() + } + + const safePayload = { + category: 'error', + action: 'client_error', + label: errorDetails.message, + stack: errorDetails.stack, + url: errorDetails.url, + timestamp: errorDetails.timestamp + } + + fetch('/api/telemetry', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(safePayload), + }).catch(() => { + // Silently fail if sending error fails + }) + } + }) + } +} \ No newline at end of file diff --git a/sim/instrumentation.ts b/sim/instrumentation.ts new file mode 100644 index 00000000000..36448c2ca6c --- /dev/null +++ b/sim/instrumentation.ts @@ -0,0 +1,96 @@ +/** + * Sim Studio Telemetry - Server-side Instrumentation + * + * This file can be customized in forked repositories: + * - Set TELEMETRY_ENDPOINT env var to your collector + * - Modify exporter configuration as needed + * + * Please maintain ethical telemetry practices if modified. + */ + +// This file enables OpenTelemetry instrumentation for Next.js +// See: https://nextjs.org/docs/app/building-your-application/optimizing/open-telemetry +// Set experimental.instrumentationHook = true in next.config.ts to enable this + +import { createLogger } from '@/lib/logs/console-logger' + +const logger = createLogger('otel-instrumentation') + +const DEFAULT_TELEMETRY_CONFIG = { + endpoint: process.env.TELEMETRY_ENDPOINT || 'https://telemetry.simstudio.ai/v1/traces', + serviceName: 'sim-studio', + serviceVersion: process.env.NEXT_PUBLIC_APP_VERSION || '0.1.0', + serverSide: { enabled: true }, + batchSettings: { + maxQueueSize: 100, + maxExportBatchSize: 10, + scheduledDelayMillis: 5000, + exportTimeoutMillis: 30000, + }, +} + +export async function register() { + if (process.env.NEXT_RUNTIME === 'nodejs') { + try { + if (process.env.NEXT_TELEMETRY_DISABLED === '1') { + logger.info('OpenTelemetry telemetry disabled via environment variable') + return + } + + let telemetryConfig + try { + telemetryConfig = require('./telemetry.config.js') + } catch (e) { + telemetryConfig = DEFAULT_TELEMETRY_CONFIG + } + + if (telemetryConfig.serverSide?.enabled === false) { + logger.info('Server-side OpenTelemetry instrumentation is disabled in config') + return + } + + const { NodeSDK } = await import('@opentelemetry/sdk-node') + const { resourceFromAttributes } = await import('@opentelemetry/resources') + const { SemanticResourceAttributes } = await import('@opentelemetry/semantic-conventions') + const { BatchSpanProcessor } = await import('@opentelemetry/sdk-trace-node') + const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http') + + const exporter = new OTLPTraceExporter({ + url: telemetryConfig.endpoint, + }) + + const spanProcessor = new BatchSpanProcessor(exporter, { + maxQueueSize: telemetryConfig.batchSettings?.maxQueueSize || DEFAULT_TELEMETRY_CONFIG.batchSettings.maxQueueSize, + maxExportBatchSize: telemetryConfig.batchSettings?.maxExportBatchSize || DEFAULT_TELEMETRY_CONFIG.batchSettings.maxExportBatchSize, + scheduledDelayMillis: telemetryConfig.batchSettings?.scheduledDelayMillis || DEFAULT_TELEMETRY_CONFIG.batchSettings.scheduledDelayMillis, + exportTimeoutMillis: telemetryConfig.batchSettings?.exportTimeoutMillis || DEFAULT_TELEMETRY_CONFIG.batchSettings.exportTimeoutMillis, + }) + + const configResource = resourceFromAttributes({ + [SemanticResourceAttributes.SERVICE_NAME]: telemetryConfig.serviceName, + [SemanticResourceAttributes.SERVICE_VERSION]: telemetryConfig.serviceVersion, + [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV, + }) + + const sdk = new NodeSDK({ + resource: configResource, + spanProcessors: [spanProcessor], + }) + + sdk.start() + + const shutdownHandler = async () => { + await sdk.shutdown() + .then(() => logger.info('OpenTelemetry SDK shut down successfully')) + .catch(err => logger.error('Error shutting down OpenTelemetry SDK', err)) + } + + process.on('SIGTERM', shutdownHandler) + process.on('SIGINT', shutdownHandler) + + logger.info('OpenTelemetry instrumentation initialized for server-side telemetry') + } catch (error) { + logger.error('Failed to initialize OpenTelemetry instrumentation', error) + } + } +} \ No newline at end of file diff --git a/sim/lib/logs/execution-logger.ts b/sim/lib/logs/execution-logger.ts index 7fc6633b41a..3b033e1562f 100644 --- a/sim/lib/logs/execution-logger.ts +++ b/sim/lib/logs/execution-logger.ts @@ -21,7 +21,6 @@ export interface LogEntry { metadata?: ToolCallMetadata | Record } -// Define types for tool call tracking export interface ToolCallMetadata { toolCalls?: ToolCall[] cost?: { @@ -101,7 +100,6 @@ export async function persistExecutionLogs( // Check for agent block and tool calls let metadata: ToolCallMetadata | undefined = undefined - logger.debug('Block type:', log.blockType) // If this is an agent block if (log.blockType === 'agent' && log.output) { logger.debug('Processing agent block output for tool calls', { @@ -177,10 +175,6 @@ export async function persistExecutionLogs( // Case 1: Direct toolCalls array if (Array.isArray(log.output.toolCalls)) { - logger.debug('Found direct toolCalls array', { - count: log.output.toolCalls.length, - }) - // Log raw timing data for debugging log.output.toolCalls.forEach((tc: any, idx: number) => { logger.debug(`Tool call ${idx} raw timing data:`, { @@ -202,14 +196,6 @@ export async function persistExecutionLogs( blockEndTime ? new Date(blockEndTime) : undefined ) - // Log what we extracted - logger.debug(`Tool call timing extracted:`, { - name: toolCall.name, - extracted_duration: duration, - extracted_startTime: timing.startTime, - extracted_endTime: timing.endTime, - }) - return { name: toolCall.name, duration: duration, @@ -224,10 +210,6 @@ export async function persistExecutionLogs( } // Case 2: toolCalls with a list array (as seen in the screenshot) else if (log.output.toolCalls && Array.isArray(log.output.toolCalls.list)) { - logger.debug('Found toolCalls with list array', { - count: log.output.toolCalls.list.length, - }) - // Log raw timing data for debugging log.output.toolCalls.list.forEach((tc: any, idx: number) => { logger.debug(`Tool call list ${idx} raw timing data:`, { @@ -300,14 +282,6 @@ export async function persistExecutionLogs( blockEndTime ? new Date(blockEndTime) : undefined ) - // Log what we extracted - logger.debug(`Response tool call timing extracted:`, { - name: toolCall.name, - extracted_duration: duration, - extracted_startTime: timing.startTime, - extracted_endTime: timing.endTime, - }) - return { name: toolCall.name, duration: duration, @@ -696,47 +670,23 @@ function getToolCallTimings( // Force a minimum duration of 1000ms if none exists if (!enhancedToolCall.duration || enhancedToolCall.duration === 0) { enhancedToolCall.duration = Math.max(1000, toolDuration) - logger.debug(`Setting minimum duration for tool ${toolCall.name}`, { - duration: enhancedToolCall.duration, - }) } // Force reasonable startTime and endTime if missing if (!enhancedToolCall.startTime) { const startTimestamp = new Date(blockStart).getTime() + toolStartOffset enhancedToolCall.startTime = new Date(startTimestamp).toISOString() - logger.debug(`Setting startTime for tool ${toolCall.name}`, { - startTime: enhancedToolCall.startTime, - }) } if (!enhancedToolCall.endTime) { const endTimestamp = new Date(enhancedToolCall.startTime).getTime() + enhancedToolCall.duration enhancedToolCall.endTime = new Date(endTimestamp).toISOString() - logger.debug(`Setting endTime for tool ${toolCall.name}`, { - endTime: enhancedToolCall.endTime, - }) } return enhancedToolCall }) - logger.debug('Finished estimating tool call timings', { - originalTools: toolCalls.map((t) => ({ - name: t.name, - hadDuration: !!t.duration, - hadStartTime: !!t.startTime, - hadEndTime: !!t.endTime, - })), - enhancedTools: result.map((t) => ({ - name: t.name, - duration: t.duration, - startTime: t.startTime, - endTime: t.endTime, - })), - }) - return result } @@ -816,15 +766,6 @@ function extractTimingInfo( blockStartTime?: Date, blockEndTime?: Date ): { startTime?: Date; endTime?: Date } { - logger.debug('Extracting timing info from tool call', { - tool: toolCall.name, - hasStartTime: !!toolCall.startTime, - hasEndTime: !!toolCall.endTime, - hasTiming: !!toolCall.timing, - blockStartRef: blockStartTime?.toISOString(), - blockEndRef: blockEndTime?.toISOString(), - }) - let startTime: Date | undefined = undefined let endTime: Date | undefined = undefined @@ -849,21 +790,13 @@ function extractTimingInfo( endTime = new Date(toolCall.completedAt) } - // If we have start time but no end time, calculate end time from duration if (startTime && !endTime) { const duration = extractDuration(toolCall) if (duration > 0) { endTime = new Date(startTime.getTime() + duration) - logger.debug('Calculated end time from start time and duration', { - tool: toolCall.name, - startTime: startTime.toISOString(), - duration, - calculatedEndTime: endTime.toISOString(), - }) } } - // Log the final timing information logger.debug('Final extracted timing info', { tool: toolCall.name, startTime: startTime?.toISOString(), diff --git a/sim/lib/telemetry.ts b/sim/lib/telemetry.ts new file mode 100644 index 00000000000..f92af0d8206 --- /dev/null +++ b/sim/lib/telemetry.ts @@ -0,0 +1,259 @@ +/** + * Sim Studio Telemetry + * + * This file can be customized in forked repositories: + * - Set TELEMETRY_ENDPOINT in telemetry.config.js to your collector + * - Modify allowed event categories as needed + * - Edit disclosure text to match your privacy policy + * + * Please maintain ethical telemetry practices if modified. + */ + +import { createLogger } from '@/lib/logs/console-logger' +import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api' + +diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR) + +const logger = createLogger('telemetry') + +export type TelemetryEvent = { + name: string + properties?: Record +} + +export type TelemetryStatus = { + enabled: boolean + notifiedUser: boolean +} + +const TELEMETRY_STATUS_KEY = 'simstudio-telemetry-status' + +let telemetryConfig = { + endpoint: process.env.TELEMETRY_ENDPOINT || 'https://telemetry.simstudio.ai/v1/traces', + serviceName: 'sim-studio', + serviceVersion: process.env.NEXT_PUBLIC_APP_VERSION || '0.1.0', +} + +if (typeof window !== 'undefined' && (window as any).__SIM_STUDIO_TELEMETRY_CONFIG) { + telemetryConfig = { ...telemetryConfig, ...(window as any).__SIM_STUDIO_TELEMETRY_CONFIG } +} + +let telemetryInitialized = false + +/** + * Gets the current telemetry status from localStorage + */ +export function getTelemetryStatus(): TelemetryStatus { + if (typeof window === 'undefined') { + return { enabled: true, notifiedUser: false } + } + + try { + if (process.env.NEXT_TELEMETRY_DISABLED === '1') { + return { enabled: false, notifiedUser: true } + } + + const stored = localStorage.getItem(TELEMETRY_STATUS_KEY) + return stored ? JSON.parse(stored) : { enabled: true, notifiedUser: false } + } catch (error) { + logger.error('Failed to get telemetry status from localStorage', error) + return { enabled: true, notifiedUser: false } + } +} + +/** + * Sets the telemetry status in localStorage + */ +export function setTelemetryStatus(status: TelemetryStatus): void { + if (typeof window === 'undefined') { + return + } + + try { + localStorage.setItem(TELEMETRY_STATUS_KEY, JSON.stringify(status)) + + if (status.enabled && !telemetryInitialized) { + initializeClientTelemetry() + } + } catch (error) { + logger.error('Failed to set telemetry status in localStorage', error) + } +} + +/** + * Mark that the user has been notified about telemetry + */ +export function markUserNotified(): void { + const status = getTelemetryStatus() + setTelemetryStatus({ ...status, notifiedUser: true }) +} + +/** + * Disables telemetry + */ +export function disableTelemetry(): void { + const currentStatus = getTelemetryStatus() + if (currentStatus.enabled) { + trackEvent('consent', 'opt_out') + } + + setTelemetryStatus({ enabled: false, notifiedUser: true }) + logger.info('Telemetry disabled') +} + +/** + * Enables telemetry + */ +export function enableTelemetry(): void { + if (process.env.NEXT_TELEMETRY_DISABLED === '1') { + logger.info('Telemetry disabled by environment variable, cannot enable') + return + } + + const currentStatus = getTelemetryStatus() + if (!currentStatus.enabled) { + trackEvent('consent', 'opt_in') + } + + setTelemetryStatus({ enabled: true, notifiedUser: true }) + logger.info('Telemetry enabled') + + if (!telemetryInitialized) { + initializeClientTelemetry() + } +} + +/** + * Initialize client-side telemetry without OpenTelemetry SDK + * This approach uses direct event tracking instead of the OTel SDK + * to avoid TypeScript compatibility issues while still collecting useful data + */ +function initializeClientTelemetry(): void { + if (typeof window === 'undefined' || telemetryInitialized) { + return + } + + try { + const clientSideEnabled = (window as any).__SIM_STUDIO_TELEMETRY_CONFIG?.clientSide?.enabled !== false + + if (!clientSideEnabled) { + logger.info('Client-side telemetry disabled in configuration') + return + } + + if (process.env.NODE_ENV === 'production') { + trackEvent('page_view', window.location.pathname) + + if (typeof window.history !== 'undefined') { + const originalPushState = window.history.pushState + window.history.pushState = function(...args) { + const result = originalPushState.apply(this, args) + trackEvent('page_view', window.location.pathname) + return result + } + } + + if (typeof window.performance !== 'undefined') { + window.addEventListener('load', () => { + setTimeout(() => { + if (performance.getEntriesByType) { + const navigationTiming = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming + if (navigationTiming) { + trackEvent('performance', 'page_load', window.location.pathname, + navigationTiming.loadEventEnd - navigationTiming.startTime) + } + + const lcpEntries = performance.getEntriesByType('paint') + .filter(entry => entry.name === 'largest-contentful-paint') + if (lcpEntries.length > 0) { + trackEvent('performance', 'largest_contentful_paint', + window.location.pathname, lcpEntries[0].startTime) + } + } + }, 0) + }) + } + + document.addEventListener('click', (e) => { + let target = e.target as HTMLElement | null + let telemetryAction = null + + while (target && !telemetryAction) { + telemetryAction = target.getAttribute('data-telemetry') + if (!telemetryAction) { + target = target.parentElement + } + } + + if (telemetryAction) { + trackEvent('feature_usage', telemetryAction) + } + }, { passive: true }) + + document.addEventListener('submit', (e) => { + const form = e.target as HTMLFormElement + const telemetryAction = form.getAttribute('data-telemetry') + if (telemetryAction) { + trackEvent('feature_usage', telemetryAction) + } + }, { passive: true }) + + window.addEventListener('error', (event) => { + const errorDetails = { + message: event.error?.message || 'Unknown error', + stack: event.error?.stack?.split('\n')[0] || '', + url: window.location.pathname, + } + trackEvent('error', 'client_error', errorDetails.message) + }, { passive: true }) + + window.addEventListener('unhandledrejection', (event) => { + const errorDetails = { + message: event.reason?.message || String(event.reason) || 'Unhandled promise rejection', + url: window.location.pathname, + } + trackEvent('error', 'unhandled_rejection', errorDetails.message) + }, { passive: true }) + + logger.info('Enhanced client-side telemetry initialized') + telemetryInitialized = true + } + } catch (error) { + logger.error('Failed to initialize client-side telemetry', error) + } +} + +/** + * Track a telemetry event + */ +export async function trackEvent(category: string, action: string, label?: string, value?: number): Promise { + const status = getTelemetryStatus() + + if (!status.enabled) return + + try { + if (process.env.NODE_ENV === 'production') { + await fetch('/api/telemetry', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + category, + action, + label, + value, + timestamp: new Date().toISOString(), + service: telemetryConfig.serviceName, + version: telemetryConfig.serviceVersion, + userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined, + url: typeof window !== 'undefined' ? window.location.pathname : undefined, + }), + }) + } else { + if (category === 'consent') { + logger.debug('Telemetry consent change', { action }) + } + } + } catch (error) { + logger.error('Failed to track telemetry event', error) + } +} \ No newline at end of file diff --git a/sim/package-lock.json b/sim/package-lock.json index 29098d41f11..a6495a4366e 100644 --- a/sim/package-lock.json +++ b/sim/package-lock.json @@ -20,6 +20,17 @@ "@browserbasehq/stagehand": "^2.0.0", "@cerebras/cerebras_cloud_sdk": "^1.23.0", "@hookform/resolvers": "^4.1.3", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/exporter-collector": "^0.25.0", + "@opentelemetry/exporter-jaeger": "^2.0.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.200.0", + "@opentelemetry/instrumentation-document-load": "^0.45.0", + "@opentelemetry/instrumentation-user-interaction": "^0.45.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-node": "^0.200.0", + "@opentelemetry/sdk-trace-web": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.32.0", + "@opentelemetry/web": "^0.24.0", "@radix-ui/react-alert-dialog": "^1.1.5", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-collapsible": "^1.1.3", @@ -1817,6 +1828,37 @@ "node": ">=18.0.0" } }, + "node_modules/@grpc/grpc-js": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.3.tgz", + "integrity": "sha512-FTXHdOoPbZrBjlVLHuKbDZnsTxXv2BlHF57xw6LuThXacXvtkahEPED0CKMk6obZDf65Hv4k3z62eyPNpvinIg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@hexagon/base64": { "version": "1.1.28", "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz", @@ -1979,6 +2021,16 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/@levischuck/tiny-cbor": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz", @@ -2072,97 +2124,1540 @@ "node": ">=8.0.0" } }, - "node_modules/@peculiar/asn1-android": { - "version": "2.3.16", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.16.tgz", - "integrity": "sha512-a1viIv3bIahXNssrOIkXZIlI2ePpZaNmR30d4aBL99mu2rO+mT9D6zBsp7H6eROWGtmwv0Ionp5olJurIo09dw==", - "license": "MIT", + "node_modules/@opentelemetry/api-logs": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.200.0.tgz", + "integrity": "sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q==", + "license": "Apache-2.0", "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "asn1js": "^3.0.5", - "tslib": "^2.8.1" + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@peculiar/asn1-ecc": { - "version": "2.3.15", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.3.15.tgz", - "integrity": "sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==", - "license": "MIT", + "node_modules/@opentelemetry/api-metrics": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-metrics/-/api-metrics-0.25.0.tgz", + "integrity": "sha512-9T0c9NQAEGRujUC7HzPa2/qZ5px/UvB2sfSU5CAKFRrAlDl2gn25B0oUbDqSRHW/IG1X2rnQ3z2bBQkJyJvE4g==", + "deprecated": "Please use @opentelemetry/api >= 1.3.0", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.0.0.tgz", + "integrity": "sha512-IEkJGzK1A9v3/EHjXh3s2IiFc6L4jfK+lNgKVgUjeUJQRRhnVFMIO3TAvKwonm9O1HebCuoOt98v8bZW7oVQHA==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.25.0.tgz", + "integrity": "sha512-8OTWF4vfCENU112XB5ElLqf0eq/FhsY0SBvvY65vB3+fbZ2Oi+CPsRASrUZWGtC9MJ5rK2lBlY+/jI4a/NPPBg==", + "license": "Apache-2.0", "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "@peculiar/asn1-x509": "^2.3.15", - "asn1js": "^3.0.5", - "tslib": "^2.8.1" + "@opentelemetry/semantic-conventions": "0.25.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">=8.5.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" } }, - "node_modules/@peculiar/asn1-rsa": { - "version": "2.3.15", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.3.15.tgz", - "integrity": "sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==", - "license": "MIT", + "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.25.0.tgz", + "integrity": "sha512-V3N+MDBiv0TUlorbgiSqk6CvcP876CYUk/41Tg6s8OIyvniTwprE6vPvFQayuABiVkGlHOxv1Mlvp0w4qNdnVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@opentelemetry/exporter-collector": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-collector/-/exporter-collector-0.25.0.tgz", + "integrity": "sha512-xZYstLt4hz1aTloJaepWdjMMf9305MqwqbUWjcU/X9pOxvgFWRlchO6x/HQTw7ow0i/S+ShzC+greKnb+1WvLA==", + "deprecated": "Please use trace and metric specific exporters @opentelemetry/exporter-trace-otlp-http and @opentelemetry/exporter-metrics-otlp-http", + "license": "Apache-2.0", "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "@peculiar/asn1-x509": "^2.3.15", - "asn1js": "^3.0.5", - "tslib": "^2.8.1" + "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/core": "0.25.0", + "@opentelemetry/resources": "0.25.0", + "@opentelemetry/sdk-metrics-base": "0.25.0", + "@opentelemetry/sdk-trace-base": "0.25.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" } }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.3.15", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz", - "integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==", - "license": "MIT", + "node_modules/@opentelemetry/exporter-collector/node_modules/@opentelemetry/resources": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.25.0.tgz", + "integrity": "sha512-O46u53vDBlxCML8O9dIjsRcCC2VT5ri1upwhp02ITobgJ16aVD/iScCo1lPl/x2E7yq9uwzMINENiiYZRFb6XA==", + "license": "Apache-2.0", "dependencies": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" + "@opentelemetry/core": "0.25.0", + "@opentelemetry/semantic-conventions": "0.25.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" } }, - "node_modules/@peculiar/asn1-x509": { - "version": "2.3.15", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.15.tgz", - "integrity": "sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==", - "license": "MIT", + "node_modules/@opentelemetry/exporter-collector/node_modules/@opentelemetry/semantic-conventions": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.25.0.tgz", + "integrity": "sha512-V3N+MDBiv0TUlorbgiSqk6CvcP876CYUk/41Tg6s8OIyvniTwprE6vPvFQayuABiVkGlHOxv1Mlvp0w4qNdnVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-jaeger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-jaeger/-/exporter-jaeger-2.0.0.tgz", + "integrity": "sha512-vXUHL9Oy5gBY+CtrLQQm254ek5jGSImLTzp51ZVC5hVOTDf9dbkymMrGU/3MYDUC8MZzPqwKnAfMPpCcjdqV5A==", + "license": "Apache-2.0", "dependencies": { - "@peculiar/asn1-schema": "^2.3.15", - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" + "@opentelemetry/core": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0", + "jaeger-client": "^3.15.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@petamoriken/float16": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz", - "integrity": "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==", - "devOptional": true, - "license": "MIT" + "node_modules/@opentelemetry/exporter-jaeger/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, + "node_modules/@opentelemetry/exporter-jaeger/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, - "node_modules/@playwright/test": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", - "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "node_modules/@opentelemetry/exporter-logs-otlp-grpc": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.200.0.tgz", + "integrity": "sha512-+3MDfa5YQPGM3WXxW9kqGD85Q7s9wlEMVNhXXG7tYFLnIeaseUt9YtCeFhEDFzfEktacdFpOtXmJuNW8cHbU5A==", "license": "Apache-2.0", - "peer": true, "dependencies": { - "playwright": "1.52.0" + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/sdk-logs": "0.200.0" }, - "bin": { - "playwright": "cli.js" + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { - "node": ">=18" + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.200.0.tgz", + "integrity": "sha512-KfWw49htbGGp9s8N4KI8EQ9XuqKJ0VG+yVYVYFiCYSjEV32qpQ5qZ9UZBzOZ6xRb+E16SXOSCT3RkqBVSABZ+g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/sdk-logs": "0.200.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.200.0.tgz", + "integrity": "sha512-GmahpUU/55hxfH4TP77ChOfftADsCq/nuri73I/AVLe2s4NIglvTsaACkFVZAVmnXXyPS00Fk3x27WS3yO07zA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-logs": "0.200.0", + "@opentelemetry/sdk-trace-base": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.200.0.tgz", + "integrity": "sha512-uHawPRvKIrhqH09GloTuYeq2BjyieYHIpiklOvxm9zhrCL2eRsnI/6g9v2BZTVtGp8tEgIa7rCQ6Ltxw6NBgew==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-metrics": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.200.0.tgz", + "integrity": "sha512-5BiR6i8yHc9+qW7F6LqkuUnIzVNA7lt0qRxIKcKT+gq3eGUPHZ3DY29sfxI3tkvnwMgtnHDMNze5DdxW39HsAw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-metrics": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.200.0.tgz", + "integrity": "sha512-E+uPj0yyvz81U9pvLZp3oHtFrEzNSqKGVkIViTQY1rH3TOobeJPSpLnTVXACnCwkPR5XeTvPnK3pZ2Kni8AFMg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-metrics": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.200.0.tgz", + "integrity": "sha512-ZYdlU9r0USuuYppiDyU2VFRA0kFl855ylnb3N/2aOlXrbA4PMCznen7gmPbetGQu7pz8Jbaf4fwvrDnVdQQXSw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-metrics": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.200.0.tgz", + "integrity": "sha512-hmeZrUkFl1YMsgukSuHCFPYeF9df0hHoKeHUthRKFCxiURs+GwF1VuabuHmBMZnjTbsuvNjOB+JSs37Csem/5Q==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.200.0.tgz", + "integrity": "sha512-Goi//m/7ZHeUedxTGVmEzH19NgqJY+Bzr6zXo1Rni1+hwqaksEyJ44gdlEMREu6dzX1DlAaH/qSykSVzdrdafA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.200.0.tgz", + "integrity": "sha512-V9TDSD3PjK1OREw2iT9TUTzNYEVWJk4Nhodzhp9eiz4onDMYmPy3LaGbPv81yIR6dUb/hNp/SIhpiCHwFUq2Vg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.0.0.tgz", + "integrity": "sha512-icxaKZ+jZL/NHXX8Aru4HGsrdhK0MLcuRXkX5G5IRmCgoRLw+Br6I/nMVozX2xjGGwV7hw2g+4Slj8K7s4HbVg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.200.0.tgz", + "integrity": "sha512-pmPlzfJd+vvgaZd/reMsC8RWgTXn2WY1OWT5RT42m3aOn5532TozwXNDhg1vzqJ+jnvmkREcdLr27ebJEQt0Jg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.200.0", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "shimmer": "^1.2.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-document-load": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-document-load/-/instrumentation-document-load-0.45.0.tgz", + "integrity": "sha512-fRSfnLfI91vfbSM+ll/58mJkC7ECgYW414KTLI1qxAOeWG95+BSKJzIy+MyQUF3bqjZPgkyCrqwsOIzMOAD01A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.200.0", + "@opentelemetry/sdk-trace-web": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-document-load/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-user-interaction": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-user-interaction/-/instrumentation-user-interaction-0.45.0.tgz", + "integrity": "sha512-b5ezG+q1MJfG136uQeA9m5hmytRVanXWPw8lqDv/cwuHDnukF14YkU3GFaTGlahU9XnCfKwFPqpSBiUDt2aPcg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.200.0", + "@opentelemetry/sdk-trace-web": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0", + "zone.js": "^0.11.4 || ^0.13.0 || ^0.14.0 || ^0.15.0" + } + }, + "node_modules/@opentelemetry/instrumentation-user-interaction/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.200.0.tgz", + "integrity": "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-transformer": "0.200.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.200.0.tgz", + "integrity": "sha512-CK2S+bFgOZ66Bsu5hlDeOX6cvW5FVtVjFFbWuaJP0ELxJKBB6HlbLZQ2phqz/uLj1cWap5xJr/PsR3iGoB7Vqw==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.200.0.tgz", + "integrity": "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-logs": "0.200.0", + "@opentelemetry/sdk-metrics": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.0.0.tgz", + "integrity": "sha512-blx9S2EI49Ycuw6VZq+bkpaIoiJFhsDuvFGhBIoH3vJ5oYjJ2U0s3fAM5jYft99xVIAv6HqoPtlP9gpVA2IZtA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.0.0.tgz", + "integrity": "sha512-Mbm/LSFyAtQKP0AQah4AfGgsD+vsZcyreZoQ5okFBk33hU7AquU4TltgyL9dvaO8/Zkoud8/0gEvwfOZ5d7EPA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.0.tgz", + "integrity": "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.200.0.tgz", + "integrity": "sha512-VZG870063NLfObmQQNtCVcdXXLzI3vOjjrRENmU37HYiPFa0ZXpXVDsTD02Nh3AT3xYJzQaWKl2X2lQ2l7TWJA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.0.tgz", + "integrity": "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics-base": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics-base/-/sdk-metrics-base-0.25.0.tgz", + "integrity": "sha512-7fwPlAFB5Xw8mnVQfq0wqKNw3RXiAMad9T1bk5Sza9LK/L6hz8RTuHWCsFMsj+1OOSAaiPFuUMYrK1J75+2IAg==", + "deprecated": "Please use @opentelemetry/sdk-metrics", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/core": "0.25.0", + "@opentelemetry/resources": "0.25.0", + "lodash.merge": "^4.6.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" + } + }, + "node_modules/@opentelemetry/sdk-metrics-base/node_modules/@opentelemetry/resources": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.25.0.tgz", + "integrity": "sha512-O46u53vDBlxCML8O9dIjsRcCC2VT5ri1upwhp02ITobgJ16aVD/iScCo1lPl/x2E7yq9uwzMINENiiYZRFb6XA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "0.25.0", + "@opentelemetry/semantic-conventions": "0.25.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" + } + }, + "node_modules/@opentelemetry/sdk-metrics-base/node_modules/@opentelemetry/semantic-conventions": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.25.0.tgz", + "integrity": "sha512-V3N+MDBiv0TUlorbgiSqk6CvcP876CYUk/41Tg6s8OIyvniTwprE6vPvFQayuABiVkGlHOxv1Mlvp0w4qNdnVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.200.0.tgz", + "integrity": "sha512-S/YSy9GIswnhYoDor1RusNkmRughipvTCOQrlF1dzI70yQaf68qgf5WMnzUxdlCl3/et/pvaO75xfPfuEmCK5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/exporter-logs-otlp-grpc": "0.200.0", + "@opentelemetry/exporter-logs-otlp-http": "0.200.0", + "@opentelemetry/exporter-logs-otlp-proto": "0.200.0", + "@opentelemetry/exporter-metrics-otlp-grpc": "0.200.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", + "@opentelemetry/exporter-metrics-otlp-proto": "0.200.0", + "@opentelemetry/exporter-prometheus": "0.200.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.200.0", + "@opentelemetry/exporter-trace-otlp-http": "0.200.0", + "@opentelemetry/exporter-trace-otlp-proto": "0.200.0", + "@opentelemetry/exporter-zipkin": "2.0.0", + "@opentelemetry/instrumentation": "0.200.0", + "@opentelemetry/propagator-b3": "2.0.0", + "@opentelemetry/propagator-jaeger": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-logs": "0.200.0", + "@opentelemetry/sdk-metrics": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0", + "@opentelemetry/sdk-trace-node": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-0.25.0.tgz", + "integrity": "sha512-TInkLSF/ThM3GNVM+9tgnCVjyNLnRxvAkG585Fhu0HNwaEtCTUwI0r7AvMRIREOreeRWttBG6kvT0LOKdo8yjw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "0.25.0", + "@opentelemetry/resources": "0.25.0", + "@opentelemetry/semantic-conventions": "0.25.0", + "lodash.merge": "^4.6.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.25.0.tgz", + "integrity": "sha512-O46u53vDBlxCML8O9dIjsRcCC2VT5ri1upwhp02ITobgJ16aVD/iScCo1lPl/x2E7yq9uwzMINENiiYZRFb6XA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "0.25.0", + "@opentelemetry/semantic-conventions": "0.25.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.2" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/semantic-conventions": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.25.0.tgz", + "integrity": "sha512-V3N+MDBiv0TUlorbgiSqk6CvcP876CYUk/41Tg6s8OIyvniTwprE6vPvFQayuABiVkGlHOxv1Mlvp0w4qNdnVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.0.0.tgz", + "integrity": "sha512-omdilCZozUjQwY3uZRBwbaRMJ3p09l4t187Lsdf0dGMye9WKD4NGcpgZRvqhI1dwcH6og+YXQEtoO9Wx3ykilg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "2.0.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-web": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-web/-/sdk-trace-web-2.0.0.tgz", + "integrity": "sha512-2IeDP1k2fipeCH6OcTSg3HgaSvTTqgUNld5GIPGXWspynZSK85YjUDazEYpSVIyaMeQY6+ZHEaD5cwsRaq3dWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-web/node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-web/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.32.0.tgz", + "integrity": "sha512-s0OpmpQFSfMrmedAn9Lhg4KWJELHCU6uU9dtIJ28N8UGhf9Y55im5X8fEzwhwDwiSqN+ZPSNrDJF7ivf/AuRPQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/tracing": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/tracing/-/tracing-0.24.0.tgz", + "integrity": "sha512-sTLEs1SIon3xV8vLe53PzfbU0FahoxL9NPY/CYvA1mwGbMu4zHkHAjqy1Tc8JmqRrfa+XrHkmzeSM4hrvloBaA==", + "deprecated": "Package renamed to @opentelemetry/sdk-trace-base", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "0.24.0", + "@opentelemetry/resources": "0.24.0", + "@opentelemetry/semantic-conventions": "0.24.0", + "lodash.merge": "^4.6.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.1" + } + }, + "node_modules/@opentelemetry/tracing/node_modules/@opentelemetry/core": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.24.0.tgz", + "integrity": "sha512-KpsfxBbFTZT9zaB4Es/fFLbvSzVl9Io/8UUu/TYl4/HgqkmyVInNlWTgRiKyz9nsHzFpGP1kdZJj+YIut0IFsw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "0.24.0", + "semver": "^7.1.3" + }, + "engines": { + "node": ">=8.5.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.1" + } + }, + "node_modules/@opentelemetry/tracing/node_modules/@opentelemetry/resources": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.24.0.tgz", + "integrity": "sha512-uEr2m13IRkjQAjX6fsYqJ21aONCspRvuQunaCl8LbH1NS1Gj82TuRUHF6TM82ulBPK8pU+nrrqXKuky2cMcIzw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "0.24.0", + "@opentelemetry/semantic-conventions": "0.24.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.1" + } + }, + "node_modules/@opentelemetry/tracing/node_modules/@opentelemetry/semantic-conventions": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.24.0.tgz", + "integrity": "sha512-a/szuMQV0Quy0/M7kKdglcbRSoorleyyOwbTNNJ32O+RBN766wbQlMTvdimImTmwYWGr+NJOni1EcC242WlRcA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/tracing/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@opentelemetry/web": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/web/-/web-0.24.0.tgz", + "integrity": "sha512-yxAKj7bQ3czfif9MtYXaSJrgRcrLUNltslyhEE+Oh7Ojh9XQ0Q5RhPnE9cwHdR7yp1+HjbEHE+I91QIMKMlVWA==", + "deprecated": "Package renamed to @opentelemetry/sdk-trace-web", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "0.24.0", + "@opentelemetry/semantic-conventions": "0.24.0", + "@opentelemetry/tracing": "0.24.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.1" + } + }, + "node_modules/@opentelemetry/web/node_modules/@opentelemetry/core": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.24.0.tgz", + "integrity": "sha512-KpsfxBbFTZT9zaB4Es/fFLbvSzVl9Io/8UUu/TYl4/HgqkmyVInNlWTgRiKyz9nsHzFpGP1kdZJj+YIut0IFsw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "0.24.0", + "semver": "^7.1.3" + }, + "engines": { + "node": ">=8.5.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.1" + } + }, + "node_modules/@opentelemetry/web/node_modules/@opentelemetry/semantic-conventions": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.24.0.tgz", + "integrity": "sha512-a/szuMQV0Quy0/M7kKdglcbRSoorleyyOwbTNNJ32O+RBN766wbQlMTvdimImTmwYWGr+NJOni1EcC242WlRcA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/web/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@peculiar/asn1-android": { + "version": "2.3.16", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.3.16.tgz", + "integrity": "sha512-a1viIv3bIahXNssrOIkXZIlI2ePpZaNmR30d4aBL99mu2rO+mT9D6zBsp7H6eROWGtmwv0Ionp5olJurIo09dw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.15", + "asn1js": "^3.0.5", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.3.15.tgz", + "integrity": "sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.15", + "@peculiar/asn1-x509": "^2.3.15", + "asn1js": "^3.0.5", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.3.15.tgz", + "integrity": "sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.15", + "@peculiar/asn1-x509": "^2.3.15", + "asn1js": "^3.0.5", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz", + "integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==", + "license": "MIT", + "dependencies": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.15.tgz", + "integrity": "sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.3.15", + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@petamoriken/float16": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz", + "integrity": "sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@playwright/test": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", + "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "playwright": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", @@ -5427,6 +6922,12 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==", + "license": "MIT" + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -5704,6 +7205,27 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/agent-base": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", @@ -5751,6 +7273,14 @@ } } }, + "node_modules/ansi-color": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-color/-/ansi-color-0.2.1.tgz", + "integrity": "sha512-bF6xLaZBLpOQzgYUtYEhJx090nPSZk1BQ/q2oyBK9aMMcJHzx9uXGCjI2Y+LebsN4Jwoykr0V9whbPiogdyHoQ==", + "engines": { + "node": "*" + } + }, "node_modules/ansi-escapes": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", @@ -6123,6 +7653,20 @@ "dev": true, "license": "MIT" }, + "node_modules/bufrw": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.4.0.tgz", + "integrity": "sha512-sWm8iPbqvL9+5SiYxXH73UOkyEbGQg7kyHQmReF89WJHQJw2eV4P/yZ0E+b71cczJ4pPobVhXxgQcmfSTgGHxQ==", + "dependencies": { + "ansi-color": "^0.2.1", + "error": "^7.0.0", + "hexer": "^1.5.0", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.x" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -6370,6 +7914,12 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" + }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -6458,6 +8008,78 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -7518,6 +9140,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw==", + "dependencies": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -7635,7 +9266,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8053,6 +9683,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-east-asian-width": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", @@ -8387,6 +10026,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/hexer": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/hexer/-/hexer-1.5.0.tgz", + "integrity": "sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg==", + "dependencies": { + "ansi-color": "^0.2.1", + "minimist": "^1.1.0", + "process": "^0.10.0", + "xtend": "^4.0.0" + }, + "bin": { + "hexer": "cli.js" + }, + "engines": { + "node": ">= 0.10.x" + } + }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -8582,6 +10238,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.13.1.tgz", + "integrity": "sha512-k2V9wNm9B+ysuelDTHjI9d5KPc4l8zAZTGqj+pcynvWkypZd857ryzN8jNC7Pg2YZXNMJcHRPpaDyCBbNyVRpA==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -8903,6 +10571,31 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/jaeger-client": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/jaeger-client/-/jaeger-client-3.19.0.tgz", + "integrity": "sha512-M0c7cKHmdyEUtjemnJyx/y9uX16XHocL46yQvyqDlPdvAcwPDbHrIbKjQdBqtiE4apQ/9dmr+ZLJYYPGnurgpw==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0", + "opentracing": "^0.14.4", + "thriftrw": "^3.5.0", + "uuid": "^8.3.2", + "xorshift": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jaeger-client/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/javascript-natural-sort": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", @@ -9358,6 +11051,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, "node_modules/lodash.castarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", @@ -9388,7 +11087,6 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, "license": "MIT" }, "node_modules/log-symbols": { @@ -9510,6 +11208,12 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -10411,6 +12115,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, "node_modules/motion-dom": { "version": "12.8.0", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.8.0.tgz", @@ -10656,6 +12366,12 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -10846,6 +12562,15 @@ "node": ">= 6" } }, + "node_modules/opentracing": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.7.tgz", + "integrity": "sha512-vz9iS7MJ5+Bp1URw8Khvdyw1H/hGvzHWlKQ7eRrQojSCDL1/SrWfrY9QebLw97n2deyRtzHRC3MkQfVNUCo91Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, "node_modules/option": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz", @@ -11584,6 +13309,14 @@ "node": ">=6" } }, + "node_modules/process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -11616,6 +13349,30 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/protobufjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.0.tgz", + "integrity": "sha512-Z2E/kOY1QjoMlCytmexzYfDm/w5fKAiRwpSzGtdnXW1zC88Z2yXazHHrOtwCzn+7wSxyE8PYM4rvVcMphF9sOA==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -12587,6 +14344,29 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -12989,6 +14769,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "license": "BSD-2-Clause" + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -13374,6 +15160,11 @@ "node": ">=0.6.19" } }, + "node_modules/string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==" + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -14020,6 +15811,31 @@ "real-require": "^0.2.0" } }, + "node_modules/thriftrw": { + "version": "3.11.4", + "resolved": "https://registry.npmjs.org/thriftrw/-/thriftrw-3.11.4.tgz", + "integrity": "sha512-UcuBd3eanB3T10nXWRRMwfwoaC6VMk7qe3/5YIWP2Jtw+EbHqJ0p1/K3x8ixiR5dozKSSfcg1W+0e33G1Di3XA==", + "dependencies": { + "bufrw": "^1.2.1", + "error": "7.0.2", + "long": "^2.4.0" + }, + "bin": { + "thrift2json": "thrift2json.js" + }, + "engines": { + "node": ">= 0.10.x" + } + }, + "node_modules/thriftrw/node_modules/long": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.6" + } + }, "node_modules/throttleit": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", @@ -15089,6 +16905,30 @@ "dev": true, "license": "MIT" }, + "node_modules/xorshift": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz", + "integrity": "sha512-iYgNnGyeeJ4t6U11NpA/QiKy+PXn5Aa3Azg5qkwIFz1tBLllQrjjsk9yzD7IAK0naNU4JxdeDgqW9ov4u/hc4g==", + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -15108,6 +16948,74 @@ "node": ">= 14" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yoga-wasm-web": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", @@ -15132,6 +17040,13 @@ "zod": "^3.24.1" } }, + "node_modules/zone.js": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.0.tgz", + "integrity": "sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==", + "license": "MIT", + "peer": true + }, "node_modules/zustand": { "version": "4.5.6", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.6.tgz", diff --git a/sim/package.json b/sim/package.json index 07285171612..a90fa6efcb3 100644 --- a/sim/package.json +++ b/sim/package.json @@ -34,6 +34,17 @@ "@browserbasehq/stagehand": "^2.0.0", "@cerebras/cerebras_cloud_sdk": "^1.23.0", "@hookform/resolvers": "^4.1.3", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/exporter-collector": "^0.25.0", + "@opentelemetry/exporter-jaeger": "^2.0.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.200.0", + "@opentelemetry/instrumentation-document-load": "^0.45.0", + "@opentelemetry/instrumentation-user-interaction": "^0.45.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-node": "^0.200.0", + "@opentelemetry/sdk-trace-web": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.32.0", + "@opentelemetry/web": "^0.24.0", "@radix-ui/react-alert-dialog": "^1.1.5", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-collapsible": "^1.1.3", diff --git a/sim/stores/settings/general/store.ts b/sim/stores/settings/general/store.ts index c6ec7fadac5..59b31930818 100644 --- a/sim/stores/settings/general/store.ts +++ b/sim/stores/settings/general/store.ts @@ -1,24 +1,136 @@ import { create } from 'zustand' import { devtools, persist } from 'zustand/middleware' +import { createLogger } from '@/lib/logs/console-logger' import { GeneralStore } from './types' +const logger = createLogger('GeneralStore') + +const CACHE_TIMEOUT = 5000 +const MAX_ERROR_RETRIES = 2 + export const useGeneralStore = create()( devtools( persist( - (set) => ({ - isAutoConnectEnabled: true, - isDebugModeEnabled: false, - isAutoFillEnvVarsEnabled: true, - theme: 'system', - toggleAutoConnect: () => - set((state) => ({ - isAutoConnectEnabled: !state.isAutoConnectEnabled, - })), - toggleDebugMode: () => set((state) => ({ isDebugModeEnabled: !state.isDebugModeEnabled })), - toggleAutoFillEnvVars: () => - set((state) => ({ isAutoFillEnvVarsEnabled: !state.isAutoFillEnvVarsEnabled })), - setTheme: (theme: 'system' | 'light' | 'dark') => set({ theme }), - }), + (set, get) => { + let lastLoadTime = 0 + let errorRetryCount = 0 + + return { + isAutoConnectEnabled: true, + isDebugModeEnabled: false, + isAutoFillEnvVarsEnabled: true, + theme: 'system', + telemetryEnabled: true, + telemetryNotifiedUser: false, + isLoading: false, + error: null, + + // Basic Actions + toggleAutoConnect: () => { + const newValue = !get().isAutoConnectEnabled + set({ isAutoConnectEnabled: newValue }) + get().updateSetting('autoConnect', newValue) + }, + + toggleDebugMode: () => { + const newValue = !get().isDebugModeEnabled + set({ isDebugModeEnabled: newValue }) + get().updateSetting('debugMode', newValue) + }, + + toggleAutoFillEnvVars: () => { + const newValue = !get().isAutoFillEnvVarsEnabled + set({ isAutoFillEnvVarsEnabled: newValue }) + get().updateSetting('autoFillEnvVars', newValue) + }, + + setTheme: (theme) => { + set({ theme }) + get().updateSetting('theme', theme) + }, + + setTelemetryEnabled: (enabled) => { + set({ telemetryEnabled: enabled }) + get().updateSetting('telemetryEnabled', enabled) + }, + + setTelemetryNotifiedUser: (notified) => { + set({ telemetryNotifiedUser: notified }) + get().updateSetting('telemetryNotifiedUser', notified) + }, + + // API Actions + loadSettings: async (force = false) => { + // Skip loading if settings were recently loaded (within 5 seconds) + const now = Date.now() + if (!force && now - lastLoadTime < CACHE_TIMEOUT) { + logger.debug('Skipping settings load - recently loaded') + return + } + + try { + set({ isLoading: true, error: null }) + + const response = await fetch('/api/user/settings') + + if (!response.ok) { + throw new Error('Failed to fetch settings') + } + + const { data } = await response.json() + + set({ + isAutoConnectEnabled: data.autoConnect, + isDebugModeEnabled: data.debugMode, + isAutoFillEnvVarsEnabled: data.autoFillEnvVars, + theme: data.theme, + telemetryEnabled: data.telemetryEnabled, + telemetryNotifiedUser: data.telemetryNotifiedUser, + isLoading: false + }) + + lastLoadTime = now + errorRetryCount = 0 + } catch (error) { + logger.error('Error loading settings:', error) + set({ + error: error instanceof Error ? error.message : 'Unknown error', + isLoading: false + }) + } + }, + + updateSetting: async (key, value) => { + try { + const response = await fetch('/api/user/settings', { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ [key]: value }), + }) + + if (!response.ok) { + throw new Error(`Failed to update setting: ${key}`) + } + + set({ error: null }) + + lastLoadTime = Date.now() + errorRetryCount = 0 + } catch (error) { + logger.error(`Error updating setting ${key}:`, error) + set({ error: error instanceof Error ? error.message : 'Unknown error' }) + + if (errorRetryCount < MAX_ERROR_RETRIES) { + errorRetryCount++ + logger.debug(`Retry attempt ${errorRetryCount} after error`) + get().loadSettings(true) + } else { + logger.warn(`Max retries (${MAX_ERROR_RETRIES}) exceeded, skipping automatic loadSettings`) + } + } + } + } + }, { name: 'general-settings', } diff --git a/sim/stores/settings/general/types.ts b/sim/stores/settings/general/types.ts index a1d6b874c71..665f7eab8e6 100644 --- a/sim/stores/settings/general/types.ts +++ b/sim/stores/settings/general/types.ts @@ -3,6 +3,10 @@ export interface General { isDebugModeEnabled: boolean isAutoFillEnvVarsEnabled: boolean theme: 'system' | 'light' | 'dark' + telemetryEnabled: boolean + telemetryNotifiedUser: boolean + isLoading: boolean + error: string | null } export interface GeneralActions { @@ -10,6 +14,19 @@ export interface GeneralActions { toggleDebugMode: () => void toggleAutoFillEnvVars: () => void setTheme: (theme: 'system' | 'light' | 'dark') => void + setTelemetryEnabled: (enabled: boolean) => void + setTelemetryNotifiedUser: (notified: boolean) => void + loadSettings: (force?: boolean) => Promise + updateSetting: (key: K, value: UserSettings[K]) => Promise } export type GeneralStore = General & GeneralActions + +export type UserSettings = { + theme: 'system' | 'light' | 'dark' + debugMode: boolean + autoConnect: boolean + autoFillEnvVars: boolean + telemetryEnabled: boolean + telemetryNotifiedUser: boolean +} diff --git a/sim/telemetry.config.js b/sim/telemetry.config.js new file mode 100644 index 00000000000..1cb389731a0 --- /dev/null +++ b/sim/telemetry.config.js @@ -0,0 +1,86 @@ +/** + * Sim Studio Telemetry Configuration + * + * PRIVACY NOTICE: + * - Telemetry is enabled by default to help us improve the product + * - You can disable telemetry via: + * 1. Settings UI > Privacy tab > Toggle off "Allow anonymous telemetry" + * 2. Setting NEXT_TELEMETRY_DISABLED=1 environment variable + * + * This file allows you to configure telemetry collection for your + * Sim Studio instance. If you've forked the repository, you can modify + * this file to send telemetry to your own collector. + * + * We only collect anonymous usage data to improve the product: + * - Feature usage statistics + * - Error rates + * - Performance metrics + * + * We NEVER collect: + * - Personal information + * - Workflow content or outputs + * - API keys or tokens + * - IP addresses or geolocation data + */ + +module.exports = { + /** + * Endpoint URL where telemetry data is sent + * Change this if you want to send telemetry to your own collector + */ + endpoint: process.env.TELEMETRY_ENDPOINT || 'https://telemetry.simstudio.ai/v1/traces', + + /** + * Service name used to identify this instance + * You can change this + */ + serviceName: 'sim-studio', + + /** + * Version of the service, defaults to the app version + */ + serviceVersion: process.env.NEXT_PUBLIC_APP_VERSION || '0.1.0', + + /** + * Batch settings for sending telemetry + * - maxQueueSize: Max number of spans to buffer + * - maxExportBatchSize: Max number of spans to send in a single batch + * - scheduledDelayMillis: Delay between batches (ms) + * - exportTimeoutMillis: Timeout for exporting data (ms) + */ + batchSettings: { + maxQueueSize: 100, + maxExportBatchSize: 10, + scheduledDelayMillis: 5000, + exportTimeoutMillis: 30000, + }, + + /** + * Categories of events that can be collected + * This is used for validation when events are sent + */ + allowedCategories: [ + 'page_view', + 'feature_usage', + 'performance', + 'error', + 'workflow', + 'consent', + ], + + /** + * Client-side instrumentation settings + * Set enabled: false to disable client-side telemetry entirely + */ + clientSide: { + enabled: true, + }, + + /** + * Server-side instrumentation settings + * Set enabled: false to disable server-side telemetry entirely + */ + serverSide: { + enabled: true, + }, +}; \ No newline at end of file