Merge pull request #688 from simstudioai/staging

v0.2.14: fix + improvement
This commit is contained in:
Vikhyath Mondreti
2025-07-14 18:44:37 -07:00
committed by GitHub
56 changed files with 278 additions and 200 deletions
+7 -1
View File
@@ -1,7 +1,8 @@
@import "tailwindcss";
@import "fumadocs-ui/css/neutral.css";
@import "fumadocs-ui/css/preset.css";
:root {
@theme {
--color-fd-primary: #802fff; /* Purple from control-bar component */
}
@@ -15,4 +16,9 @@
color: var(--color-fd-primary);
}
/* Tailwind v4 content sources */
@source '../app/**/*.{js,ts,jsx,tsx,mdx}';
@source '../components/**/*.{js,ts,jsx,tsx,mdx}';
@source '../content/**/*.{js,ts,jsx,tsx,mdx}';
@source '../mdx-components.tsx';
@source '../node_modules/fumadocs-ui/dist/**/*.js';
@@ -4,6 +4,7 @@ import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getSession } from '@/lib/auth'
import { createLogger } from '@/lib/logs/console-logger'
import { getUserId } from '@/app/api/auth/oauth/utils'
import { db } from '@/db'
import { document } from '@/db/schema'
import { checkKnowledgeBaseAccess, processDocumentAsync } from '../../utils'
@@ -269,13 +270,29 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
const { id: knowledgeBaseId } = await params
try {
const session = await getSession()
if (!session?.user?.id) {
logger.warn(`[${requestId}] Unauthorized document creation attempt`)
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
const body = await req.json()
const { workflowId } = body
logger.info(`[${requestId}] Knowledge base document creation request`, {
knowledgeBaseId,
workflowId,
hasWorkflowId: !!workflowId,
bodyKeys: Object.keys(body),
})
const userId = await getUserId(requestId, workflowId)
if (!userId) {
const errorMessage = workflowId ? 'Workflow not found' : 'Unauthorized'
const statusCode = workflowId ? 404 : 401
logger.warn(`[${requestId}] Authentication failed: ${errorMessage}`, {
workflowId,
hasWorkflowId: !!workflowId,
})
return NextResponse.json({ error: errorMessage }, { status: statusCode })
}
const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, session.user.id)
const accessCheck = await checkKnowledgeBaseAccess(knowledgeBaseId, userId)
if (!accessCheck.hasAccess) {
if ('notFound' in accessCheck && accessCheck.notFound) {
@@ -283,13 +300,11 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
return NextResponse.json({ error: 'Knowledge base not found' }, { status: 404 })
}
logger.warn(
`[${requestId}] User ${session.user.id} attempted to create document in unauthorized knowledge base ${knowledgeBaseId}`
`[${requestId}] User ${userId} attempted to create document in unauthorized knowledge base ${knowledgeBaseId}`
)
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const body = await req.json()
// Check if this is a bulk operation
if (body.bulk === true) {
// Handle bulk processing (replaces process-documents endpoint)
+20 -2
View File
@@ -1,6 +1,6 @@
'use client'
import { useEffect, useState } from 'react'
import { Suspense, useEffect, useState } from 'react'
import { CheckCircle, Heart, Info, Loader2, XCircle } from 'lucide-react'
import { useSearchParams } from 'next/navigation'
import { Button } from '@/components/ui/button'
@@ -20,7 +20,7 @@ interface UnsubscribeData {
}
}
export default function UnsubscribePage() {
function UnsubscribeContent() {
const searchParams = useSearchParams()
const [loading, setLoading] = useState(true)
const [data, setData] = useState<UnsubscribeData | null>(null)
@@ -380,3 +380,21 @@ export default function UnsubscribePage() {
</div>
)
}
export default function UnsubscribePage() {
return (
<Suspense
fallback={
<div className='flex min-h-screen items-center justify-center bg-background'>
<Card className='w-full max-w-md border shadow-sm'>
<CardContent className='flex items-center justify-center p-8'>
<Loader2 className='h-8 w-8 animate-spin text-muted-foreground' />
</CardContent>
</Card>
</div>
}
>
<UnsubscribeContent />
</Suspense>
)
}
@@ -181,7 +181,7 @@ export function useSubBlockValue<T = any>(
triggerWorkflowUpdate = false,
options?: UseSubBlockValueOptions
): readonly [T | null, (value: T) => void] {
const { debounceMs = 150, isStreaming = false, onStreamingEnd } = options || {}
const { isStreaming = false, onStreamingEnd } = options || {}
const { collaborativeSetSubblockValue } = useCollaborativeWorkflow()
@@ -202,8 +202,7 @@ export function useSubBlockValue<T = any>(
// Previous model reference for detecting model changes
const prevModelRef = useRef<string | null>(null)
// Debouncing refs
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null)
// Streaming refs
const lastEmittedValueRef = useRef<T | null>(null)
const streamingValueRef = useRef<T | null>(null)
const wasStreamingRef = useRef<boolean>(false)
@@ -232,15 +231,6 @@ export function useSubBlockValue<T = any>(
// Compute the modelValue based on block type
const modelValue = isProviderBasedBlock ? (modelSubBlockValue as string) : null
// Cleanup timer on unmount
useEffect(() => {
return () => {
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current)
}
}
}, [])
// Emit the value to socket/DB
const emitValue = useCallback(
(value: T) => {
@@ -299,26 +289,12 @@ export function useSubBlockValue<T = any>(
storeApiKeyValue(blockId, blockType, modelValue, newValue, storeValue)
}
// Clear any existing debounce timer
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current)
debounceTimerRef.current = null
}
// If streaming, just store the value without emitting
if (isStreaming) {
streamingValueRef.current = valueCopy
} else {
// Detect large changes for extended debounce
const isLargeChange = detectLargeChange(lastEmittedValueRef.current, valueCopy)
const effectiveDebounceMs = isLargeChange ? debounceMs * 2 : debounceMs
// Debounce the socket emission
debounceTimerRef.current = setTimeout(() => {
if (valueRef.current !== null && valueRef.current !== lastEmittedValueRef.current) {
emitValue(valueCopy)
}
}, effectiveDebounceMs)
// Emit immediately - let the operation queue handle debouncing and deduplication
emitValue(valueCopy)
}
if (triggerWorkflowUpdate) {
@@ -335,7 +311,6 @@ export function useSubBlockValue<T = any>(
triggerWorkflowUpdate,
modelValue,
isStreaming,
debounceMs,
emitValue,
]
)
@@ -412,26 +387,3 @@ export function useSubBlockValue<T = any>(
// Return appropriate tuple based on whether options were provided
return [storeValue !== undefined ? storeValue : initialValue, setValue] as const
}
// Helper function to detect large changes
function detectLargeChange(oldValue: any, newValue: any): boolean {
// Handle null/undefined
if (oldValue == null && newValue == null) return false
if (oldValue == null || newValue == null) return true
// For strings, check if it's a large paste or deletion
if (typeof oldValue === 'string' && typeof newValue === 'string') {
const sizeDiff = Math.abs(newValue.length - oldValue.length)
// Consider it a large change if more than 50 characters changed at once
return sizeDiff > 50
}
// For arrays, check length difference
if (Array.isArray(oldValue) && Array.isArray(newValue)) {
const sizeDiff = Math.abs(newValue.length - oldValue.length)
return sizeDiff > 5
}
// For other types, always treat as small change
return false
}
@@ -500,7 +500,7 @@ const WorkflowContent = React.memo(() => {
let autoConnectEdge
if (isAutoConnectEnabled && type !== 'starter') {
const closestBlock = findClosestOutput(centerPosition)
console.log('🎯 Closest block found:', closestBlock)
logger.info('🎯 Closest block found:', closestBlock)
if (closestBlock) {
// Get appropriate source handle
const sourceHandle = determineSourceHandle(closestBlock)
@@ -513,7 +513,7 @@ const WorkflowContent = React.memo(() => {
targetHandle: 'target',
type: 'workflowEdge',
}
console.log('✅ Auto-connect edge created:', autoConnectEdge)
logger.info('✅ Auto-connect edge created:', autoConnectEdge)
}
}
+2 -2
View File
@@ -1,8 +1,8 @@
import { stripeClient } from '@better-auth/stripe/client'
import { emailOTPClient, genericOAuthClient, organizationClient } from 'better-auth/client/plugins'
import { createAuthClient } from 'better-auth/react'
import { env } from './env'
import { isDev, isProd } from './environment'
import { env } from '@/lib/env'
import { isDev, isProd } from '@/lib/environment'
export function getBaseURL() {
let baseURL
+1 -1
View File
@@ -19,13 +19,13 @@ import {
renderOTPEmail,
renderPasswordResetEmail,
} from '@/components/emails/render-email'
import { getBaseURL } from '@/lib/auth-client'
import { env, isTruthy } from '@/lib/env'
import { isProd } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { getEmailDomain } from '@/lib/urls/utils'
import { db } from '@/db'
import * as schema from '@/db/schema'
import { getBaseURL } from './auth-client'
const logger = createLogger('Auth')
@@ -1,9 +1,9 @@
import { eq } from 'drizzle-orm'
import { getUserUsageLimit } from '@/lib/billing/core/usage'
import { isProd } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { userStats } from '@/db/schema'
import { getUserUsageLimit } from '../core/usage'
const logger = createLogger('UsageMonitor')
+7 -4
View File
@@ -1,11 +1,14 @@
import { and, eq } from 'drizzle-orm'
import {
resetOrganizationBillingPeriod,
resetUserBillingPeriod,
} from '@/lib/billing/core/billing-periods'
import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
import { getUserUsageData } from '@/lib/billing/core/usage'
import { requireStripeClient } from '@/lib/billing/stripe-client'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { member, organization, subscription, user, userStats } from '@/db/schema'
import { requireStripeClient } from '../stripe-client'
import { resetOrganizationBillingPeriod, resetUserBillingPeriod } from './billing-periods'
import { getHighestPrioritySubscription } from './subscription'
import { getUserUsageData } from './usage'
const logger = createLogger('Billing')
@@ -1,9 +1,9 @@
import { and, eq } from 'drizzle-orm'
import { getPlanPricing } from '@/lib/billing/core/billing'
import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { member, organization, user, userStats } from '@/db/schema'
import { getPlanPricing } from './billing'
import { getHighestPrioritySubscription } from './subscription'
const logger = createLogger('OrganizationBilling')
+7 -7
View File
@@ -1,16 +1,16 @@
import { and, eq, inArray } from 'drizzle-orm'
import { isProd } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { member, subscription, userStats } from '@/db/schema'
import { client } from '../../auth-client'
import { client } from '@/lib/auth-client'
import {
calculateDefaultUsageLimit,
checkEnterprisePlan,
checkProPlan,
checkTeamPlan,
} from '../subscriptions/utils'
import type { UserSubscriptionState } from '../types'
} from '@/lib/billing/subscriptions/utils'
import type { UserSubscriptionState } from '@/lib/billing/types'
import { isProd } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { member, subscription, userStats } from '@/db/schema'
const logger = createLogger('SubscriptionCore')
+3 -3
View File
@@ -1,10 +1,10 @@
import { and, eq } from 'drizzle-orm'
import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
import { calculateDefaultUsageLimit, canEditUsageLimit } from '@/lib/billing/subscriptions/utils'
import type { BillingData, UsageData, UsageLimitInfo } from '@/lib/billing/types'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { member, user, userStats } from '@/db/schema'
import { calculateDefaultUsageLimit, canEditUsageLimit } from '../subscriptions/utils'
import type { BillingData, UsageData, UsageLimitInfo } from '../types'
import { getHighestPrioritySubscription } from './subscription'
const logger = createLogger('UsageManagement')
@@ -1,8 +1,8 @@
import { and, count, eq } from 'drizzle-orm'
import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { invitation, member, organization, subscription, user, userStats } from '@/db/schema'
import { getHighestPrioritySubscription } from '../core/subscription'
const logger = createLogger('SeatManagement')
+1 -1
View File
@@ -1,4 +1,4 @@
import type { SerializedWorkflow } from '../serializer/types'
import type { SerializedWorkflow } from '@/serializer/types'
/**
* Shared utility for calculating block paths and accessible connections.
+2 -2
View File
@@ -1,10 +1,10 @@
import fs from 'fs/promises'
import path from 'path'
import { TextChunker } from '@/lib/documents/chunker'
import type { DocChunk, DocsChunkerOptions, HeaderInfo } from '@/lib/documents/types'
import { isDev } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { generateEmbeddings } from '@/app/api/knowledge/utils'
import { TextChunker } from './chunker'
import type { DocChunk, DocsChunkerOptions, HeaderInfo } from './types'
interface Frontmatter {
title?: string
+1 -1
View File
@@ -1,11 +1,11 @@
import { type Chunk, TextChunker } from '@/lib/documents/chunker'
import { retryWithExponentialBackoff } from '@/lib/documents/utils'
import { env } from '@/lib/env'
import { parseBuffer, parseFile } from '@/lib/file-parsers'
import { createLogger } from '@/lib/logs/console-logger'
import { getPresignedUrlWithConfig, getStorageProvider, uploadFile } from '@/lib/uploads'
import { BLOB_KB_CONFIG, S3_KB_CONFIG } from '@/lib/uploads/setup'
import { mistralParserTool } from '@/tools/mistral/parser'
import { retryWithExponentialBackoff } from './utils'
const logger = createLogger('DocumentProcessor')
+3 -3
View File
@@ -1,8 +1,8 @@
import { Resend } from 'resend'
import { generateUnsubscribeToken, isUnsubscribed } from '@/lib/email/unsubscribe'
import { env } from '@/lib/env'
import { createLogger } from '@/lib/logs/console-logger'
import { env } from '../env'
import { getEmailDomain } from '../urls/utils'
import { generateUnsubscribeToken, isUnsubscribed } from './unsubscribe'
import { getEmailDomain } from '@/lib/urls/utils'
const logger = createLogger('Mailer')
+2 -2
View File
@@ -1,10 +1,10 @@
import { describe, expect, it, vi } from 'vitest'
import type { EmailType } from './mailer'
import {
generateUnsubscribeToken,
isTransactionalEmail,
verifyUnsubscribeToken,
} from './unsubscribe'
} from '@/lib/email/unsubscribe'
import type { EmailType } from './mailer'
vi.mock('../env', () => ({
env: {
+2 -2
View File
@@ -1,10 +1,10 @@
import { createHash, randomBytes } from 'crypto'
import { eq } from 'drizzle-orm'
import type { EmailType } from '@/lib/email/mailer'
import { env } from '@/lib/env'
import { createLogger } from '@/lib/logs/console-logger'
import { db } from '@/db'
import { settings, user } from '@/db/schema'
import { env } from '../env'
import type { EmailType } from './mailer'
const logger = createLogger('Unsubscribe')
+1 -1
View File
@@ -1,4 +1,4 @@
import { validateAndNormalizeEmail } from './utils'
import { validateAndNormalizeEmail } from '@/lib/email/utils'
describe('validateAndNormalizeEmail', () => {
describe('valid emails', () => {
+1 -1
View File
@@ -1,8 +1,8 @@
import { createReadStream, existsSync } from 'fs'
import { Readable } from 'stream'
import csvParser from 'csv-parser'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import type { FileParseResult, FileParser } from './types'
const logger = createLogger('CsvParser')
+1 -1
View File
@@ -1,7 +1,7 @@
import { readFile } from 'fs/promises'
import mammoth from 'mammoth'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import type { FileParseResult, FileParser } from './types'
const logger = createLogger('DocxParser')
+1 -1
View File
@@ -5,7 +5,7 @@ import path from 'path'
* @vitest-environment node
*/
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { FileParseResult, FileParser } from './types'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
// Mock file system modules
const mockExistsSync = vi.fn().mockReturnValue(true)
+2 -2
View File
@@ -1,9 +1,9 @@
import { existsSync } from 'fs'
import { readFile } from 'fs/promises'
import path from 'path'
import { RawPdfParser } from '@/lib/file-parsers/raw-pdf-parser'
import type { FileParseResult, FileParser, SupportedFileType } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import { RawPdfParser } from './raw-pdf-parser'
import type { FileParseResult, FileParser, SupportedFileType } from './types'
const logger = createLogger('FileParser')
+1 -1
View File
@@ -1,6 +1,6 @@
import { readFile } from 'fs/promises'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import type { FileParseResult, FileParser } from './types'
const logger = createLogger('MdParser')
+1 -1
View File
@@ -1,8 +1,8 @@
import { readFile } from 'fs/promises'
// @ts-ignore
import * as pdfParseLib from 'pdf-parse/lib/pdf-parse.js'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import type { FileParseResult, FileParser } from './types'
const logger = createLogger('PdfParser')
+1 -1
View File
@@ -1,8 +1,8 @@
import { readFile } from 'fs/promises'
import { promisify } from 'util'
import zlib from 'zlib'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import type { FileParseResult, FileParser } from './types'
const logger = createLogger('RawPdfParser')
+1 -1
View File
@@ -1,6 +1,6 @@
import { readFile } from 'fs/promises'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import type { FileParseResult, FileParser } from './types'
const logger = createLogger('TxtParser')
+1 -1
View File
@@ -1,7 +1,7 @@
import { existsSync } from 'fs'
import * as XLSX from 'xlsx'
import type { FileParseResult, FileParser } from '@/lib/file-parsers/types'
import { createLogger } from '@/lib/logs/console-logger'
import type { FileParseResult, FileParser } from './types'
const logger = createLogger('XlsxParser')
+1 -1
View File
@@ -5,7 +5,7 @@
* It is separate from the user-facing logging system in logging.ts.
*/
import chalk from 'chalk'
import { env } from '../env'
import { env } from '@/lib/env'
/**
* LogLevel enum defines the severity levels for logging
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, test } from 'vitest'
import { EnhancedExecutionLogger } from './enhanced-execution-logger'
import { EnhancedExecutionLogger } from '@/lib/logs/enhanced-execution-logger'
describe('EnhancedExecutionLogger', () => {
let logger: EnhancedExecutionLogger
@@ -1,10 +1,10 @@
import { eq, sql } from 'drizzle-orm'
import { v4 as uuidv4 } from 'uuid'
import { getCostMultiplier } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { snapshotService } from '@/lib/logs/snapshot-service'
import { db } from '@/db'
import { userStats, workflow, workflowExecutionBlocks, workflowExecutionLogs } from '@/db/schema'
import { createLogger } from './console-logger'
import { snapshotService } from './snapshot-service'
import type {
BlockExecutionLog,
BlockInputData,
@@ -1,5 +1,5 @@
import type { ExecutionEnvironment, ExecutionTrigger, WorkflowState } from '@/lib/logs/types'
import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/db-helpers'
import type { ExecutionEnvironment, ExecutionTrigger, WorkflowState } from './types'
export function createTriggerObject(
type: ExecutionTrigger['type'],
@@ -1,12 +1,12 @@
import { createLogger } from '@/lib/logs/console-logger'
import { enhancedExecutionLogger } from './enhanced-execution-logger'
import { enhancedExecutionLogger } from '@/lib/logs/enhanced-execution-logger'
import {
calculateCostSummary,
createEnvironmentObject,
createTriggerObject,
loadWorkflowStateForExecution,
} from './enhanced-logging-factory'
import type { ExecutionEnvironment, ExecutionTrigger, WorkflowState } from './types'
} from '@/lib/logs/enhanced-logging-factory'
import type { ExecutionEnvironment, ExecutionTrigger, WorkflowState } from '@/lib/logs/types'
const logger = createLogger('EnhancedLoggingSession')
+1 -1
View File
@@ -3,11 +3,11 @@ import { v4 as uuidv4 } from 'uuid'
import { getCostMultiplier } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console-logger'
import { redactApiKeys } from '@/lib/utils'
import { stripCustomToolPrefix } from '@/lib/workflows/utils'
import { db } from '@/db'
import { userStats, workflow, workflowLogs } from '@/db/schema'
import type { ExecutionResult as ExecutorResult } from '@/executor/types'
import { calculateCost } from '@/providers/utils'
import { stripCustomToolPrefix } from '../workflows/utils'
const logger = createLogger('ExecutionLogger')
+2 -2
View File
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, test } from 'vitest'
import { SnapshotService } from './snapshot-service'
import type { WorkflowState } from './types'
import { SnapshotService } from '@/lib/logs/snapshot-service'
import type { WorkflowState } from '@/lib/logs/types'
describe('SnapshotService', () => {
let service: SnapshotService
+4 -4
View File
@@ -1,16 +1,16 @@
import { createHash } from 'crypto'
import { and, eq, lt } from 'drizzle-orm'
import { v4 as uuidv4 } from 'uuid'
import { db } from '@/db'
import { workflowExecutionSnapshots } from '@/db/schema'
import { createLogger } from './console-logger'
import { createLogger } from '@/lib/logs/console-logger'
import type {
SnapshotService as ISnapshotService,
SnapshotCreationResult,
WorkflowExecutionSnapshot,
WorkflowExecutionSnapshotInsert,
WorkflowState,
} from './types'
} from '@/lib/logs/types'
import { db } from '@/db'
import { workflowExecutionSnapshots } from '@/db/schema'
const logger = createLogger('SnapshotService')
+1 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest'
import { buildTraceSpans, stripCustomToolPrefix } from '@/lib/logs/trace-spans'
import type { ExecutionResult } from '@/executor/types'
import { buildTraceSpans, stripCustomToolPrefix } from './trace-spans'
describe('buildTraceSpans', () => {
test('should extract sequential segments from timeSegments data', () => {
+1 -1
View File
@@ -1,5 +1,5 @@
import { createLogger } from '@/lib/logs/console-logger'
import type { TraceSpan } from '@/app/workspace/[workspaceId]/logs/stores/types'
import type { TraceSpan } from '@/lib/logs/types'
import type { ExecutionResult } from '@/executor/types'
const logger = createLogger('TraceSpans')
+1 -1
View File
@@ -1 +1 @@
export * from './oauth'
export * from '@/lib/oauth/oauth'
+5 -1
View File
@@ -1,5 +1,9 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { getUserEntityPermissions, getUsersWithPermissions, hasAdminPermission } from './utils'
import {
getUserEntityPermissions,
getUsersWithPermissions,
hasAdminPermission,
} from '@/lib/permissions/utils'
vi.mock('@/db', () => ({
db: {
+1 -1
View File
@@ -11,7 +11,7 @@ import {
getSubBlockValue,
parseCronToHumanReadable,
parseTimeString,
} from './utils'
} from '@/lib/schedules/utils'
describe('Schedule Utilities', () => {
describe('parseTimeString', () => {
+14 -5
View File
@@ -3,15 +3,24 @@
*/
import { createLogger } from '@/lib/logs/console-logger'
import { calculateCost } from '@/providers/utils'
import { createTokenizationError } from './errors'
import { estimateInputTokens, estimateOutputTokens, estimateTokenCount } from './estimators'
import type { CostBreakdown, StreamingCostResult, TokenizationInput, TokenUsage } from './types'
import { createTokenizationError } from '@/lib/tokenization/errors'
import {
estimateInputTokens,
estimateOutputTokens,
estimateTokenCount,
} from '@/lib/tokenization/estimators'
import type {
CostBreakdown,
StreamingCostResult,
TokenizationInput,
TokenUsage,
} from '@/lib/tokenization/types'
import {
getProviderForTokenization,
logTokenizationDetails,
validateTokenizationInput,
} from './utils'
} from '@/lib/tokenization/utils'
import { calculateCost } from '@/providers/utils'
const logger = createLogger('TokenizationCalculators')
+1 -1
View File
@@ -2,7 +2,7 @@
* Configuration constants for tokenization functionality
*/
import type { ProviderTokenizationConfig } from './types'
import type { ProviderTokenizationConfig } from '@/lib/tokenization/types'
export const TOKENIZATION_CONFIG = {
providers: {
+3 -3
View File
@@ -3,9 +3,9 @@
*/
import { createLogger } from '@/lib/logs/console-logger'
import { MIN_TEXT_LENGTH_FOR_ESTIMATION, TOKENIZATION_CONFIG } from './constants'
import type { TokenEstimate } from './types'
import { createTextPreview, getProviderConfig } from './utils'
import { MIN_TEXT_LENGTH_FOR_ESTIMATION, TOKENIZATION_CONFIG } from '@/lib/tokenization/constants'
import type { TokenEstimate } from '@/lib/tokenization/types'
import { createTextPreview, getProviderConfig } from '@/lib/tokenization/utils'
const logger = createLogger('TokenizationEstimators')
+11 -21
View File
@@ -1,25 +1,16 @@
/**
* Main tokenization module exports
*
* This module provides token estimation and cost calculation functionality
* for streaming LLM executions where actual token counts are not available.
*/
// Core calculation functions
export {
calculateStreamingCost,
calculateTokenizationCost,
createCostResultFromProviderData,
} from './calculators'
// Constants
export { LLM_BLOCK_TYPES, TOKENIZATION_CONFIG } from './constants'
// Error handling
export { createTokenizationError, TokenizationError } from './errors'
// Token estimation functions
export { estimateInputTokens, estimateOutputTokens, estimateTokenCount } from './estimators'
// Streaming-specific helpers
export { processStreamingBlockLog, processStreamingBlockLogs } from './streaming'
// Types
} from '@/lib/tokenization/calculators'
export { LLM_BLOCK_TYPES, TOKENIZATION_CONFIG } from '@/lib/tokenization/constants'
export { createTokenizationError, TokenizationError } from '@/lib/tokenization/errors'
export {
estimateInputTokens,
estimateOutputTokens,
estimateTokenCount,
} from '@/lib/tokenization/estimators'
export { processStreamingBlockLog, processStreamingBlockLogs } from '@/lib/tokenization/streaming'
export type {
CostBreakdown,
ProviderTokenizationConfig,
@@ -27,8 +18,7 @@ export type {
TokenEstimate,
TokenizationInput,
TokenUsage,
} from './types'
// Utility functions
} from '@/lib/tokenization/types'
export {
createTextPreview,
extractTextContent,
@@ -40,4 +30,4 @@ export {
isTokenizableBlockType,
logTokenizationDetails,
validateTokenizationInput,
} from './utils'
} from '@/lib/tokenization/utils'
+4 -4
View File
@@ -3,16 +3,16 @@
*/
import { createLogger } from '@/lib/logs/console-logger'
import type { BlockLog } from '@/executor/types'
import { calculateStreamingCost } from './calculators'
import { TOKENIZATION_CONFIG } from './constants'
import { calculateStreamingCost } from '@/lib/tokenization/calculators'
import { TOKENIZATION_CONFIG } from '@/lib/tokenization/constants'
import {
extractTextContent,
hasRealCostData,
hasRealTokenData,
isTokenizableBlockType,
logTokenizationDetails,
} from './utils'
} from '@/lib/tokenization/utils'
import type { BlockLog } from '@/executor/types'
const logger = createLogger('StreamingTokenization')
+1 -1
View File
@@ -4,7 +4,7 @@ import {
generateBlobSASQueryParameters,
StorageSharedKeyCredential,
} from '@azure/storage-blob'
import { BLOB_CONFIG } from '../setup'
import { BLOB_CONFIG } from '@/lib/uploads/setup'
// Lazily create a single Blob service client instance.
let _blobServiceClient: BlobServiceClient | null = null
+1 -1
View File
@@ -5,7 +5,7 @@ import {
getStorageProvider,
USE_BLOB_STORAGE,
USE_S3_STORAGE,
} from './setup'
} from '@/lib/uploads/setup'
const logger = createLogger('UploadsSetup')
+3 -3
View File
@@ -7,7 +7,7 @@ import {
getPresignedUrl as getBlobPresignedUrl,
getPresignedUrlWithConfig as getBlobPresignedUrlWithConfig,
uploadToBlob,
} from './blob/blob-client'
} from '@/lib/uploads/blob/blob-client'
import {
type CustomS3Config,
deleteFromS3,
@@ -16,8 +16,8 @@ import {
getPresignedUrlWithConfig as getS3PresignedUrlWithConfig,
type FileInfo as S3FileInfo,
uploadToS3,
} from './s3/s3-client'
import { USE_BLOB_STORAGE, USE_S3_STORAGE } from './setup'
} from '@/lib/uploads/s3/s3-client'
import { USE_BLOB_STORAGE, USE_S3_STORAGE } from '@/lib/uploads/setup'
const logger = createLogger('StorageClient')
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { VariableManager } from './variable-manager'
import { VariableManager } from '@/lib/variables/variable-manager'
describe('VariableManager', () => {
describe('parseInputForStorage', () => {
+78 -5
View File
@@ -34,6 +34,7 @@ interface OperationQueueState {
const retryTimeouts = new Map<string, NodeJS.Timeout>()
const operationTimeouts = new Map<string, NodeJS.Timeout>()
const subblockDebounceTimeouts = new Map<string, NodeJS.Timeout>()
let emitWorkflowOperation:
| ((operation: string, target: string, payload: any, operationId?: string) => void)
@@ -59,6 +60,54 @@ export const useOperationQueueStore = create<OperationQueueState>((set, get) =>
hasOperationError: false,
addToQueue: (operation) => {
// Handle debouncing for subblock operations
if (
operation.operation.operation === 'subblock-update' &&
operation.operation.target === 'subblock'
) {
const { blockId, subblockId } = operation.operation.payload
const debounceKey = `${blockId}-${subblockId}`
const existingTimeout = subblockDebounceTimeouts.get(debounceKey)
if (existingTimeout) {
clearTimeout(existingTimeout)
}
set((state) => ({
operations: state.operations.filter(
(op) =>
!(
op.status === 'pending' &&
op.operation.operation === 'subblock-update' &&
op.operation.target === 'subblock' &&
op.operation.payload?.blockId === blockId &&
op.operation.payload?.subblockId === subblockId
)
),
}))
const timeoutId = setTimeout(() => {
subblockDebounceTimeouts.delete(debounceKey)
const queuedOp: QueuedOperation = {
...operation,
timestamp: Date.now(),
retryCount: 0,
status: 'pending',
}
set((state) => ({
operations: [...state.operations, queuedOp],
}))
get().processNextOperation()
}, 150) // 150ms debounce for subblock operations
subblockDebounceTimeouts.set(debounceKey, timeoutId)
return
}
// Handle non-subblock operations (existing logic)
const state = get()
// Check for duplicate operation ID
@@ -80,13 +129,8 @@ export const useOperationQueueStore = create<OperationQueueState>((set, get) =>
// For block operations, check the block ID specifically
((operation.operation.target === 'block' &&
op.operation.payload?.id === operation.operation.payload?.id) ||
// For subblock operations, check blockId and subblockId
(operation.operation.target === 'subblock' &&
op.operation.payload?.blockId === operation.operation.payload?.blockId &&
op.operation.payload?.subblockId === operation.operation.payload?.subblockId) ||
// For other operations, fall back to full payload comparison
(operation.operation.target !== 'block' &&
operation.operation.target !== 'subblock' &&
JSON.stringify(op.operation.payload) === JSON.stringify(operation.operation.payload)))
)
@@ -127,6 +171,7 @@ export const useOperationQueueStore = create<OperationQueueState>((set, get) =>
confirmOperation: (operationId) => {
const state = get()
const operation = state.operations.find((op) => op.id === operationId)
const newOperations = state.operations.filter((op) => op.id !== operationId)
const retryTimeout = retryTimeouts.get(operationId)
@@ -141,6 +186,20 @@ export const useOperationQueueStore = create<OperationQueueState>((set, get) =>
operationTimeouts.delete(operationId)
}
// Clean up any debounce timeouts for subblock operations
if (
operation?.operation.operation === 'subblock-update' &&
operation.operation.target === 'subblock'
) {
const { blockId, subblockId } = operation.operation.payload
const debounceKey = `${blockId}-${subblockId}`
const debounceTimeout = subblockDebounceTimeouts.get(debounceKey)
if (debounceTimeout) {
clearTimeout(debounceTimeout)
subblockDebounceTimeouts.delete(debounceKey)
}
}
logger.debug('Removing operation from queue', {
operationId,
remainingOps: newOperations.length,
@@ -166,6 +225,20 @@ export const useOperationQueueStore = create<OperationQueueState>((set, get) =>
operationTimeouts.delete(operationId)
}
// Clean up any debounce timeouts for subblock operations
if (
operation.operation.operation === 'subblock-update' &&
operation.operation.target === 'subblock'
) {
const { blockId, subblockId } = operation.operation.payload
const debounceKey = `${blockId}-${subblockId}`
const debounceTimeout = subblockDebounceTimeouts.get(debounceKey)
if (debounceTimeout) {
clearTimeout(debounceTimeout)
subblockDebounceTimeouts.delete(debounceKey)
}
}
if (operation.retryCount < 3) {
const newRetryCount = operation.retryCount + 1
const delay = 2 ** newRetryCount * 1000 // 2s, 4s, 8s
+2 -4
View File
@@ -183,10 +183,8 @@ export const useConsoleStore = create<ConsoleStore>()(
) => {
set((state) => {
const updatedEntries = state.entries.map((entry) => {
// Match by executionId if provided, otherwise fall back to blockId for backward compatibility
const isMatch = executionId
? entry.executionId === executionId
: entry.blockId === blockId
// Only update if both blockId and executionId match
const isMatch = entry.blockId === blockId && entry.executionId === executionId
if (isMatch) {
if (typeof update === 'string') {
// Simple content update for backward compatibility
+5 -1
View File
@@ -65,6 +65,7 @@ export const knowledgeCreateDocumentTool: ToolConfig<any, KnowledgeCreateDocumen
'Content-Type': 'application/json',
}),
body: (params) => {
const workflowId = params._context?.workflowId
const textContent = params.content?.trim()
const documentName = params.name?.trim()
@@ -111,7 +112,7 @@ export const knowledgeCreateDocumentTool: ToolConfig<any, KnowledgeCreateDocumen
},
]
return {
const requestBody = {
documents: documents,
processingOptions: {
chunkSize: 1024,
@@ -121,7 +122,10 @@ export const knowledgeCreateDocumentTool: ToolConfig<any, KnowledgeCreateDocumen
lang: 'en',
},
bulk: true,
...(workflowId && { workflowId }),
}
return requestBody
},
isInternalRoute: true,
},
+27 -20
View File
@@ -214,7 +214,6 @@
"overrides": {
"react": "19.1.0",
"react-dom": "19.1.0",
"tailwindcss": "3.4.1",
},
"packages": {
"@adobe/css-tools": ["@adobe/css-tools@4.4.3", "", {}, "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA=="],
@@ -1589,7 +1588,7 @@
"check-error": ["check-error@2.1.1", "", {}, "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw=="],
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
@@ -2559,7 +2558,7 @@
"postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="],
"postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
"postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
@@ -2655,7 +2654,7 @@
"readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
@@ -2879,7 +2878,7 @@
"tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="],
"tailwindcss": ["tailwindcss@3.4.1", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA=="],
"tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
"tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="],
@@ -3419,8 +3418,6 @@
"chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"cli-truncate/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
@@ -3449,12 +3446,8 @@
"form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"fumadocs-mdx/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"fumadocs-ui/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
"fumadocs-ui/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="],
"gaxios/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
"gaxios/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
@@ -3541,6 +3534,8 @@
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
"postcss-nested/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
"pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
"pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
@@ -3551,12 +3546,8 @@
"react-email/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
"react-email/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"react-email/commander": ["commander@13.1.0", "", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="],
"readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"resend/@react-email/render": ["@react-email/render@1.1.2", "", { "dependencies": { "html-to-text": "^9.0.5", "prettier": "^3.5.3", "react-promise-suspense": "^0.3.4" }, "peerDependencies": { "react": "^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-RnRehYN3v9gVlNMehHPHhyp2RQo7+pSkHDtXPvg3s0GbzM9SQMW4Qrf8GRNvtpLC4gsI+Wt0VatNRUFqjvevbw=="],
"restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
@@ -3565,6 +3556,8 @@
"sim/tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="],
"sim/tailwindcss": ["tailwindcss@3.4.1", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.0", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.19.1", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA=="],
"simstudio/@types/node": ["@types/node@20.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA=="],
"simstudio-ts-sdk/@types/node": ["@types/node@20.19.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA=="],
@@ -3593,14 +3586,14 @@
"sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
"tailwindcss/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
"test-exclude/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
"unicode-trie/pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="],
"unplugin/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
"webpack/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
@@ -3781,8 +3774,6 @@
"form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"fumadocs-mdx/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"gaxios/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
"groq-sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
@@ -3861,7 +3852,11 @@
"ora/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"react-email/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"sim/tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"sim/tailwindcss/lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="],
"sim/tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="],
"sucrase/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
@@ -3871,6 +3866,10 @@
"test-exclude/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
"unplugin/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"unplugin/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"webpack/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"@anthropic-ai/sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
@@ -3947,10 +3946,16 @@
"ora/cli-cursor/restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
"sim/tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"sim/tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"sucrase/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"test-exclude/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"unplugin/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"lint-staged/listr2/cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
"lint-staged/listr2/log-update/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
@@ -3963,6 +3968,8 @@
"lint-staged/listr2/wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"sim/tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"lint-staged/listr2/cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"lint-staged/listr2/log-update/cli-cursor/restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
+1 -2
View File
@@ -25,8 +25,7 @@
},
"overrides": {
"react": "19.1.0",
"react-dom": "19.1.0",
"tailwindcss": "3.4.1"
"react-dom": "19.1.0"
},
"dependencies": {
"@linear/sdk": "40.0.0",