Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
8 changes: 8 additions & 0 deletions apps/sim/tools/elevenlabs/tts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ 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: {},
}
}

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