Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/sim/app/api/proxy/image/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type NextRequest, NextResponse } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { createLogger } from '@/lib/logs/console/logger'
import { validateImageUrl } from '@/lib/security/input-validation'
import { generateRequestId } from '@/lib/utils'
Expand All @@ -14,6 +15,12 @@ export async function GET(request: NextRequest) {
const imageUrl = url.searchParams.get('url')
const requestId = generateRequestId()

const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error(`[${requestId}] Authentication failed for image proxy:`, authResult.error)
return new NextResponse('Unauthorized', { status: 401 })
}

if (!imageUrl) {
logger.error(`[${requestId}] Missing 'url' parameter`)
return new NextResponse('Missing URL parameter', { status: 400 })
Expand Down
15 changes: 9 additions & 6 deletions apps/sim/app/api/proxy/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { generateInternalToken } from '@/lib/auth/internal'
import { isDev } from '@/lib/environment'
import { createLogger } from '@/lib/logs/console/logger'
Expand Down Expand Up @@ -242,12 +244,18 @@ export async function GET(request: Request) {
}
}

export async function POST(request: Request) {
export async function POST(request: NextRequest) {
const requestId = generateRequestId()
const startTime = new Date()
const startTimeISO = startTime.toISOString()

try {
const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error(`[${requestId}] Authentication failed for proxy:`, authResult.error)
return createErrorResponse('Unauthorized', 401)
}

let requestBody
try {
requestBody = await request.json()
Expand Down Expand Up @@ -311,18 +319,15 @@ export async function POST(request: Request) {
error: result.error || 'Unknown error',
})

// Let the main executeTool handle error transformation to avoid double transformation
throw new Error(result.error || 'Tool execution failed')
}

const endTime = new Date()
const endTimeISO = endTime.toISOString()
const duration = endTime.getTime() - startTime.getTime()

// Add explicit timing information directly to the response
const responseWithTimingData = {
...result,
// Add timing data both at root level and in nested timing object
startTime: startTimeISO,
endTime: endTimeISO,
duration,
Expand All @@ -335,7 +340,6 @@ export async function POST(request: Request) {

logger.info(`[${requestId}] Tool executed successfully: ${toolId} (${duration}ms)`)

// Return the response with CORS headers
return formatResponse(responseWithTimingData)
} catch (error: any) {
logger.error(`[${requestId}] Proxy request failed`, {
Expand All @@ -344,7 +348,6 @@ export async function POST(request: Request) {
name: error instanceof Error ? error.name : undefined,
})

// Add timing information even to error responses
const endTime = new Date()
const endTimeISO = endTime.toISOString()
const duration = endTime.getTime() - startTime.getTime()
Expand Down
31 changes: 20 additions & 11 deletions apps/sim/app/api/proxy/tts/route.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { createLogger } from '@/lib/logs/console/logger'
import { validateAlphanumericId } from '@/lib/security/input-validation'
import { uploadFile } from '@/lib/uploads/storage-client'
import { getBaseUrl } from '@/lib/urls/utils'

const logger = createLogger('ProxyTTSAPI')

export async function POST(request: Request) {
export async function POST(request: NextRequest) {
try {
const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error('Authentication failed for TTS proxy:', authResult.error)
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

const body = await request.json()
const { text, voiceId, apiKey, modelId = 'eleven_monolingual_v1' } = body

if (!text || !voiceId || !apiKey) {
return new NextResponse('Missing required parameters', { status: 400 })
return NextResponse.json({ error: 'Missing required parameters' }, { status: 400 })
}

const voiceIdValidation = validateAlphanumericId(voiceId, 'voiceId', 255)
if (!voiceIdValidation.isValid) {
logger.error(`Invalid voice ID: ${voiceIdValidation.error}`)
return new NextResponse(voiceIdValidation.error, { status: 400 })
return NextResponse.json({ error: voiceIdValidation.error }, { status: 400 })
}

logger.info('Proxying TTS request for voice:', voiceId)
Expand All @@ -41,16 +49,17 @@ export async function POST(request: Request) {

if (!response.ok) {
logger.error(`Failed to generate TTS: ${response.status} ${response.statusText}`)
return new NextResponse(`Failed to generate TTS: ${response.status} ${response.statusText}`, {
status: response.status,
})
return NextResponse.json(
{ error: `Failed to generate TTS: ${response.status} ${response.statusText}` },
{ status: response.status }
)
}

const audioBlob = await response.blob()

if (audioBlob.size === 0) {
logger.error('Empty audio received from ElevenLabs')
return new NextResponse('Empty audio received', { status: 422 })
return NextResponse.json({ error: 'Empty audio received' }, { status: 422 })
}

const audioBuffer = Buffer.from(await audioBlob.arrayBuffer())
Expand All @@ -67,11 +76,11 @@ export async function POST(request: Request) {
} catch (error) {
logger.error('Error proxying TTS:', error)

return new NextResponse(
`Internal Server Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
return NextResponse.json(
{
status: 500,
}
error: `Internal Server Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
{ status: 500 }
)
}
}
7 changes: 7 additions & 0 deletions apps/sim/app/api/proxy/tts/stream/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { NextRequest } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { env } from '@/lib/env'
import { createLogger } from '@/lib/logs/console/logger'
import { validateAlphanumericId } from '@/lib/security/input-validation'
Expand All @@ -7,6 +8,12 @@ const logger = createLogger('ProxyTTSStreamAPI')

export async function POST(request: NextRequest) {
try {
const authResult = await checkHybridAuth(request, { requireWorkflowId: false })
if (!authResult.success) {
logger.error('Authentication failed for TTS stream proxy:', authResult.error)
return new Response('Unauthorized', { status: 401 })
}

const body = await request.json()
const { text, voiceId, modelId = 'eleven_turbo_v2_5' } = body

Expand Down
10 changes: 10 additions & 0 deletions apps/sim/tools/elevenlabs/tts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ export const elevenLabsTtsTool: ToolConfig<ElevenLabsTtsParams, ElevenLabsTtsRes
transformResponse: async (response: Response) => {
const data = await response.json()

if (!response.ok || data.error) {
return {
success: false,
error: data.error || 'Unknown error occurred',
output: {
audioUrl: '',
},
}
}

return {
success: true,
output: {
Expand Down
Loading