Skip to content

Commit 24e9a1b

Browse files
committed
fix(api): requests and table
1 parent 33de83b commit 24e9a1b

File tree

5 files changed

+171
-10
lines changed

5 files changed

+171
-10
lines changed

sim/app/api/proxy/route.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,22 @@ export async function POST(request: Request) {
117117
startTime: startTimeISO,
118118
endTime: endTimeISO,
119119
})
120-
return NextResponse.json(responseWithTimingData)
120+
121+
// Return the response with CORS headers
122+
return NextResponse.json(responseWithTimingData, {
123+
headers: {
124+
'Access-Control-Allow-Origin': '*',
125+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
126+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
127+
},
128+
})
121129
} catch (error: any) {
122130
throw error
123131
}
124132
} catch (error: any) {
125133
logger.error(`[${requestId}] Proxy request failed`, {
126134
error: error instanceof Error ? error.message : String(error),
135+
stack: error instanceof Error ? error.stack : undefined
127136
})
128137

129138
// Add timing information even to error responses
@@ -137,6 +146,25 @@ export async function POST(request: Request) {
137146
startTime: startTimeISO,
138147
endTime: endTimeISO,
139148
duration,
149+
}, {
150+
headers: {
151+
'Access-Control-Allow-Origin': '*',
152+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
153+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
154+
},
140155
})
141156
}
142157
}
158+
159+
// Add OPTIONS handler for CORS preflight requests
160+
export async function OPTIONS() {
161+
return new NextResponse(null, {
162+
status: 204,
163+
headers: {
164+
'Access-Control-Allow-Origin': '*',
165+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
166+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
167+
'Access-Control-Max-Age': '86400',
168+
},
169+
})
170+
}

sim/app/w/[id]/components/workflow-block/components/sub-block/components/table.tsx

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ interface TableRow {
2222
export function Table({ columns, blockId, subBlockId }: TableProps) {
2323
const [value, setValue] = useSubBlockValue(blockId, subBlockId)
2424

25+
// Create refs for input elements
26+
const inputRefs = useRef<Map<string, HTMLInputElement>>(new Map())
27+
2528
// Ensure value is properly typed and initialized
2629
const rows = useMemo(() => {
2730
if (!Array.isArray(value)) {
@@ -47,6 +50,26 @@ export function Table({ columns, blockId, subBlockId }: TableProps) {
4750
element?: HTMLElement | null
4851
} | null>(null)
4952

53+
// Sync overlay scroll with input scroll
54+
useEffect(() => {
55+
if (activeCell) {
56+
const cellKey = `${activeCell.rowIndex}-${activeCell.column}`
57+
const input = inputRefs.current.get(cellKey)
58+
const overlay = document.querySelector(`[data-overlay="${cellKey}"]`) as HTMLElement
59+
60+
if (input && overlay) {
61+
const handleScroll = () => {
62+
overlay.scrollLeft = input.scrollLeft
63+
}
64+
65+
input.addEventListener('scroll', handleScroll)
66+
return () => {
67+
input.removeEventListener('scroll', handleScroll)
68+
}
69+
}
70+
}
71+
}, [activeCell])
72+
5073
const handleCellChange = (rowIndex: number, column: string, value: string) => {
5174
const updatedRows = [...rows].map((row, idx) =>
5275
idx === rowIndex
@@ -92,14 +115,18 @@ export function Table({ columns, blockId, subBlockId }: TableProps) {
92115

93116
const renderCell = (row: TableRow, rowIndex: number, column: string, cellIndex: number) => {
94117
const cellValue = row.cells[column] || ''
118+
const cellKey = `${rowIndex}-${column}`
95119

96120
return (
97121
<td
98122
key={`${row.id}-${column}`}
99123
className={cn('p-1 relative', cellIndex < columns.length - 1 && 'border-r')}
100124
>
101-
<div className="relative">
125+
<div className="relative w-full">
102126
<Input
127+
ref={(el) => {
128+
if (el) inputRefs.current.set(cellKey, el)
129+
}}
103130
value={cellValue}
104131
placeholder={column}
105132
onChange={(e) => {
@@ -145,10 +172,13 @@ export function Table({ columns, blockId, subBlockId }: TableProps) {
145172
setActiveCell(null)
146173
}
147174
}}
148-
className="border-0 focus-visible:ring-0 focus-visible:ring-offset-0 text-transparent caret-foreground placeholder:text-muted-foreground/50"
175+
className="border-0 focus-visible:ring-0 focus-visible:ring-offset-0 text-transparent caret-foreground placeholder:text-muted-foreground/50 w-full"
149176
/>
150-
<div className="absolute inset-0 pointer-events-none px-3 flex items-center overflow-x-auto whitespace-pre text-sm bg-transparent">
151-
{formatDisplayText(cellValue)}
177+
<div
178+
data-overlay={cellKey}
179+
className="absolute inset-0 pointer-events-none px-3 flex items-center text-sm bg-transparent overflow-hidden"
180+
>
181+
<div className="whitespace-pre">{formatDisplayText(cellValue)}</div>
152182
</div>
153183
</div>
154184
</td>

sim/blocks/blocks/reddit.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const RedditBlock: BlockConfig<RedditHotPostsResponse> = {
2323
// Limit input
2424
{
2525
id: 'limit',
26-
title: 'Number of Posts',
26+
title: 'Number of Top Posts',
2727
type: 'short-input',
2828
layout: 'full',
2929
placeholder: '10',

sim/blocks/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { SerperBlock } from './blocks/serper'
2727
import { GoogleSheetsBlock } from './blocks/sheets'
2828
import { SlackBlock } from './blocks/slack'
2929
import { StarterBlock } from './blocks/starter'
30-
import { SupabaseBlock } from './blocks/supabase'
30+
// import { SupabaseBlock } from './blocks/supabase'
3131
import { TavilyBlock } from './blocks/tavily'
3232
import { TranslateBlock } from './blocks/translate'
3333
import { TwilioSMSBlock } from './blocks/twilio'
@@ -61,7 +61,7 @@ export {
6161
YouTubeBlock,
6262
NotionBlock,
6363
GmailBlock,
64-
SupabaseBlock,
64+
// SupabaseBlock,
6565
XBlock,
6666
StarterBlock,
6767
PineconeBlock,
@@ -109,7 +109,7 @@ const blocks: Record<string, BlockConfig> = {
109109
serper: SerperBlock,
110110
slack: SlackBlock,
111111
starter: StarterBlock,
112-
supabase: SupabaseBlock,
112+
// supabase: SupabaseBlock,
113113
tavily: TavilyBlock,
114114
translate: TranslateBlock,
115115
twilio_sms: TwilioSMSBlock,

sim/tools/index.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import { tavilyExtractTool, tavilySearchTool } from './tavily'
4747
import { sendSMSTool } from './twilio/send'
4848
import { typeformFilesTool, typeformInsightsTool, typeformResponsesTool } from './typeform'
4949
import { OAuthTokenPayload, ToolConfig, ToolResponse } from './types'
50-
import { formatRequestParams, validateToolRequest } from './utils'
50+
import { formatRequestParams, validateToolRequest, transformTable } from './utils'
5151
import { visionTool } from './vision/vision'
5252
import { whatsappSendMessageTool } from './whatsapp'
5353
import { xReadTool, xSearchTool, xUserTool, xWriteTool } from './x'
@@ -559,6 +559,109 @@ async function handleInternalRequest(
559559
const requestParams = formatRequestParams(tool, params)
560560

561561
try {
562+
// Special handling for HTTP request tool - direct fetch
563+
if (toolId === 'http_request') {
564+
logger.info(`Direct fetch for HTTP request to: ${params.url}`)
565+
566+
// Prepare fetch options
567+
const fetchOptions: RequestInit = {
568+
method: params.method || 'GET',
569+
headers: transformTable(params.headers || null),
570+
}
571+
572+
// Add body for non-GET requests
573+
if (params.method && params.method !== 'GET' && params.method !== 'HEAD' && params.body) {
574+
if (typeof params.body === 'object') {
575+
fetchOptions.body = JSON.stringify(params.body)
576+
// Ensure Content-Type is set
577+
if (fetchOptions.headers) {
578+
(fetchOptions.headers as Record<string, string>)['Content-Type'] = 'application/json'
579+
} else {
580+
fetchOptions.headers = { 'Content-Type': 'application/json' }
581+
}
582+
} else {
583+
fetchOptions.body = params.body
584+
}
585+
}
586+
587+
// Handle timeout
588+
const controller = new AbortController()
589+
const timeout = params.timeout || 50000
590+
const timeoutId = setTimeout(() => controller.abort(), timeout)
591+
fetchOptions.signal = controller.signal
592+
593+
try {
594+
// Make the actual fetch request
595+
const response = await fetch(params.url, fetchOptions)
596+
clearTimeout(timeoutId)
597+
598+
// Use the tool's response transformer if available
599+
if (tool.transformResponse) {
600+
return await tool.transformResponse(response, params)
601+
}
602+
603+
// Default response handling
604+
const headers: Record<string, string> = {}
605+
response.headers.forEach((value, key) => {
606+
headers[key] = value
607+
})
608+
609+
let data
610+
try {
611+
// Try to parse as JSON first
612+
if (response.headers.get('content-type')?.includes('application/json')) {
613+
data = await response.json()
614+
} else {
615+
data = await response.text()
616+
}
617+
} catch (error) {
618+
data = await response.text()
619+
}
620+
621+
return {
622+
success: response.ok,
623+
output: {
624+
data,
625+
status: response.status,
626+
headers,
627+
},
628+
error: response.ok ? undefined : `HTTP error ${response.status}: ${response.statusText}`
629+
}
630+
} catch (error: any) {
631+
clearTimeout(timeoutId)
632+
633+
// Handle specific abort error
634+
if (error.name === 'AbortError') {
635+
return {
636+
success: false,
637+
output: {},
638+
error: `Request timeout after ${timeout}ms`
639+
}
640+
}
641+
642+
// Use the tool's error transformer if available
643+
if (tool.transformError) {
644+
try {
645+
const errorResult = tool.transformError(error)
646+
if (typeof errorResult === 'string') {
647+
return {
648+
success: false,
649+
output: {},
650+
error: errorResult,
651+
}
652+
}
653+
} catch {} // Fallthrough to default error handling
654+
}
655+
656+
return {
657+
success: false,
658+
output: {},
659+
error: error.message || 'Failed to fetch'
660+
}
661+
}
662+
}
663+
664+
// Standard handling for other tools (existing code)
562665
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || ''
563666
// Handle the case where url may be a function or string
564667
const endpointUrl =

0 commit comments

Comments
 (0)