mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-31 01:37:58 -05:00
Compare commits
44 Commits
fix/invite
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31fdd2be13 | ||
|
|
028bc652c2 | ||
|
|
c6bf5cd58c | ||
|
|
11dc18a80d | ||
|
|
ab4e9dc72f | ||
|
|
1c58c35bd8 | ||
|
|
d63a5cb504 | ||
|
|
8bd5d41723 | ||
|
|
c12931bc50 | ||
|
|
e9c4251c1c | ||
|
|
cc2be33d6b | ||
|
|
45371e521e | ||
|
|
0ce0f98aa5 | ||
|
|
dff1c9d083 | ||
|
|
b09f683072 | ||
|
|
a8bb0db660 | ||
|
|
af82820a28 | ||
|
|
4372841797 | ||
|
|
5e8c843241 | ||
|
|
7bf3d73ee6 | ||
|
|
7ffc11a738 | ||
|
|
be578e2ed7 | ||
|
|
f415e5edc4 | ||
|
|
13a6e6c3fa | ||
|
|
f5ab7f21ae | ||
|
|
bfb6fffe38 | ||
|
|
4fbec0a43f | ||
|
|
585f5e365b | ||
|
|
3792bdd252 | ||
|
|
eb5d1f3e5b | ||
|
|
54ab82c8dd | ||
|
|
f895bf469b | ||
|
|
dd3209af06 | ||
|
|
b6ba3b50a7 | ||
|
|
b304233062 | ||
|
|
57e4b49bd6 | ||
|
|
e12dd204ed | ||
|
|
3d9d9cbc54 | ||
|
|
0f4ec962ad | ||
|
|
4827866f9a | ||
|
|
3e697d9ed9 | ||
|
|
4431a1a484 | ||
|
|
4d1a9a3f22 | ||
|
|
eb07a080fb |
@@ -39,8 +39,18 @@ export function SocialLoginButtons({
|
||||
setIsGithubLoading(true)
|
||||
try {
|
||||
await client.signIn.social({ provider: 'github', callbackURL })
|
||||
} catch (_err: unknown) {
|
||||
// Error handling is done silently - user will see the OAuth error page if needed
|
||||
} catch (err: any) {
|
||||
let errorMessage = 'Failed to sign in with GitHub'
|
||||
|
||||
if (err.message?.includes('account exists')) {
|
||||
errorMessage = 'An account with this email already exists. Please sign in instead.'
|
||||
} else if (err.message?.includes('cancelled')) {
|
||||
errorMessage = 'GitHub sign in was cancelled. Please try again.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
} else if (err.message?.includes('rate limit')) {
|
||||
errorMessage = 'Too many attempts. Please try again later.'
|
||||
}
|
||||
} finally {
|
||||
setIsGithubLoading(false)
|
||||
}
|
||||
@@ -52,8 +62,18 @@ export function SocialLoginButtons({
|
||||
setIsGoogleLoading(true)
|
||||
try {
|
||||
await client.signIn.social({ provider: 'google', callbackURL })
|
||||
} catch (_err: unknown) {
|
||||
// Error handling is done silently - user will see the OAuth error page if needed
|
||||
} catch (err: any) {
|
||||
let errorMessage = 'Failed to sign in with Google'
|
||||
|
||||
if (err.message?.includes('account exists')) {
|
||||
errorMessage = 'An account with this email already exists. Please sign in instead.'
|
||||
} else if (err.message?.includes('cancelled')) {
|
||||
errorMessage = 'Google sign in was cancelled. Please try again.'
|
||||
} else if (err.message?.includes('network')) {
|
||||
errorMessage = 'Network error. Please check your connection and try again.'
|
||||
} else if (err.message?.includes('rate limit')) {
|
||||
errorMessage = 'Too many attempts. Please try again later.'
|
||||
}
|
||||
} finally {
|
||||
setIsGoogleLoading(false)
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ export default function LoginPage({
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown)
|
||||
}
|
||||
}, [forgotPasswordOpen])
|
||||
}, [forgotPasswordEmail, forgotPasswordOpen])
|
||||
|
||||
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const newEmail = e.target.value
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import Link from 'next/link'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
@@ -52,6 +52,7 @@ const validateCallbackUrl = (url: string): boolean => {
|
||||
}
|
||||
|
||||
export default function SSOForm() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [email, setEmail] = useState('')
|
||||
|
||||
@@ -196,7 +196,7 @@ export function useVerification({
|
||||
|
||||
return () => clearTimeout(timeoutId)
|
||||
}
|
||||
}, [otp, email, isLoading, isVerified, verifyCode])
|
||||
}, [otp, email, isLoading, isVerified])
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
@@ -220,7 +220,7 @@ export function useVerification({
|
||||
handleRedirect()
|
||||
}
|
||||
}
|
||||
}, [isEmailVerificationEnabled, router, isInviteFlow, redirectUrl, refetchSession])
|
||||
}, [isEmailVerificationEnabled, router, isInviteFlow, redirectUrl])
|
||||
|
||||
return {
|
||||
otp,
|
||||
|
||||
@@ -118,7 +118,7 @@ export function DotPattern({
|
||||
<stop offset='100%' stopColor='currentColor' stopOpacity='0' />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
{dots.map((dot, _index) => (
|
||||
{dots.map((dot, index) => (
|
||||
<circle
|
||||
key={`${dot.x}-${dot.y}`}
|
||||
cx={dot.x}
|
||||
|
||||
@@ -106,8 +106,9 @@ export function LandingFlow({
|
||||
proOptions={{ hideAttribution: true }}
|
||||
fitView={false}
|
||||
defaultViewport={{ x: 0, y: 0, zoom: 1 }}
|
||||
onInit={() => {
|
||||
onInit={(instance) => {
|
||||
setRfReady(true)
|
||||
// Expose limited viewport API for outer timeline to pan smoothly
|
||||
viewportApiRef.current = {
|
||||
panTo: (x: number, y: number, options?: { duration?: number }) => {
|
||||
setViewport({ x, y, zoom: 1 }, { duration: options?.duration ?? 0 })
|
||||
|
||||
@@ -140,7 +140,7 @@ export default function Hero() {
|
||||
*/
|
||||
const [rfNodes, setRfNodes] = React.useState<Node[]>([])
|
||||
const [rfEdges, setRfEdges] = React.useState<Edge[]>([])
|
||||
const [groupBox] = React.useState<LandingGroupData | null>(null)
|
||||
const [groupBox, setGroupBox] = React.useState<LandingGroupData | null>(null)
|
||||
const [worldWidth, setWorldWidth] = React.useState<number>(1000)
|
||||
const viewportApiRef = React.useRef<LandingViewportApi | null>(null)
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ export function extractAgentContent(executeResult: {
|
||||
if (typeof executeResult.output === 'object' && executeResult.output !== null) {
|
||||
const keys = Object.keys(executeResult.output)
|
||||
// Skip empty objects or objects with only undefined values
|
||||
if (keys.length > 0 && keys.some((k) => executeResult.output?.[k] !== undefined)) {
|
||||
if (keys.length > 0 && keys.some((k) => executeResult.output![k] !== undefined)) {
|
||||
return JSON.stringify(executeResult.output)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ interface GoogleIdToken {
|
||||
/**
|
||||
* Get all OAuth connections for the current user
|
||||
*/
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET(request: NextRequest) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
try {
|
||||
|
||||
@@ -177,6 +177,7 @@ describe('OAuth Token API Routes', () => {
|
||||
const { POST } = await import('@/app/api/auth/oauth/token/route')
|
||||
|
||||
const response = await POST(req)
|
||||
const data = await response.json()
|
||||
|
||||
expect(response.status).toBe(403)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import crypto from 'node:crypto'
|
||||
import crypto from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
|
||||
@@ -8,7 +8,7 @@ const logger = createLogger('TrelloAuthorize')
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
if (!session?.user?.id) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getBaseUrl } from '@/lib/core/utils/urls'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET(request: NextRequest) {
|
||||
const baseUrl = getBaseUrl()
|
||||
|
||||
return new NextResponse(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { db } from '@sim/db'
|
||||
import { chat, verification } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { db } from '@sim/db'
|
||||
import { chat, workflow } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
|
||||
@@ -42,7 +42,7 @@ const chatSchema = z.object({
|
||||
.default([]),
|
||||
})
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ export async function POST(req: NextRequest) {
|
||||
{ success: true, key: { id: data?.id || 'new', apiKey: data.apiKey } },
|
||||
{ status: 201 }
|
||||
)
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return NextResponse.json({ error: 'Failed to generate copilot API key' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getSession } from '@/lib/auth'
|
||||
import { SIM_AGENT_API_URL_DEFAULT } from '@/lib/copilot/constants'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
if (!session?.user?.id) {
|
||||
@@ -49,7 +49,7 @@ export async function GET(_request: NextRequest) {
|
||||
})
|
||||
|
||||
return NextResponse.json({ keys }, { status: 200 })
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return NextResponse.json({ error: 'Failed to get keys' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export async function DELETE(request: NextRequest) {
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true }, { status: 200 })
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return NextResponse.json({ error: 'Failed to delete key' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,6 +494,20 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
// If streaming is requested, forward the stream and update chat later
|
||||
if (stream && simAgentResponse.body) {
|
||||
// Create user message to save
|
||||
const userMessage = {
|
||||
id: userMessageIdToUse, // Consistent ID used for request and persistence
|
||||
role: 'user',
|
||||
content: message,
|
||||
timestamp: new Date().toISOString(),
|
||||
...(fileAttachments && fileAttachments.length > 0 && { fileAttachments }),
|
||||
...(Array.isArray(contexts) && contexts.length > 0 && { contexts }),
|
||||
...(Array.isArray(contexts) &&
|
||||
contexts.length > 0 && {
|
||||
contentBlocks: [{ type: 'contexts', contexts: contexts as any, timestamp: Date.now() }],
|
||||
}),
|
||||
}
|
||||
|
||||
// Create a pass-through stream that captures the response
|
||||
const transformedStream = new ReadableStream({
|
||||
async start(controller) {
|
||||
@@ -501,11 +515,14 @@ export async function POST(req: NextRequest) {
|
||||
let assistantContent = ''
|
||||
const toolCalls: any[] = []
|
||||
let buffer = ''
|
||||
const isFirstDone = true
|
||||
let responseIdFromStart: string | undefined
|
||||
let responseIdFromDone: string | undefined
|
||||
// Track tool call progress to identify a safe done event
|
||||
const announcedToolCallIds = new Set<string>()
|
||||
const startedToolExecutionIds = new Set<string>()
|
||||
const completedToolExecutionIds = new Set<string>()
|
||||
let lastDoneResponseId: string | undefined
|
||||
let lastSafeDoneResponseId: string | undefined
|
||||
|
||||
// Send chatId as first event
|
||||
@@ -547,15 +564,9 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
// Forward the sim agent stream and capture assistant response
|
||||
const reader = simAgentResponse.body?.getReader()
|
||||
const reader = simAgentResponse.body!.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
if (!reader) {
|
||||
logger.error(`[${tracker.requestId}] Failed to get reader from response body`)
|
||||
controller.close()
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
@@ -636,11 +647,15 @@ export async function POST(req: NextRequest) {
|
||||
break
|
||||
|
||||
case 'start':
|
||||
if (event.data?.responseId) {
|
||||
responseIdFromStart = event.data.responseId
|
||||
}
|
||||
break
|
||||
|
||||
case 'done':
|
||||
if (event.data?.responseId) {
|
||||
responseIdFromDone = event.data.responseId
|
||||
lastDoneResponseId = responseIdFromDone
|
||||
|
||||
// Mark this done as safe only if no tool call is currently in progress or pending
|
||||
const announced = announcedToolCallIds.size
|
||||
@@ -675,7 +690,7 @@ export async function POST(req: NextRequest) {
|
||||
`data: ${JSON.stringify({ type: 'content', data: formatted })}\n\n`
|
||||
)
|
||||
)
|
||||
} catch (_enqueueErr) {
|
||||
} catch (enqueueErr) {
|
||||
reader.cancel()
|
||||
break
|
||||
}
|
||||
@@ -684,7 +699,7 @@ export async function POST(req: NextRequest) {
|
||||
controller.enqueue(
|
||||
encoder.encode(`data: ${JSON.stringify({ type: 'done' })}\n\n`)
|
||||
)
|
||||
} catch (_enqueueErr) {
|
||||
} catch (enqueueErr) {
|
||||
reader.cancel()
|
||||
break
|
||||
}
|
||||
@@ -694,7 +709,7 @@ export async function POST(req: NextRequest) {
|
||||
// Forward original event to client
|
||||
try {
|
||||
controller.enqueue(encoder.encode(`data: ${jsonStr}\n\n`))
|
||||
} catch (_enqueueErr) {
|
||||
} catch (enqueueErr) {
|
||||
reader.cancel()
|
||||
break
|
||||
}
|
||||
@@ -752,17 +767,17 @@ export async function POST(req: NextRequest) {
|
||||
controller.enqueue(
|
||||
encoder.encode(`data: ${JSON.stringify({ type: 'done' })}\n\n`)
|
||||
)
|
||||
} catch (_enqueueErr) {
|
||||
} catch (enqueueErr) {
|
||||
reader.cancel()
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
controller.enqueue(encoder.encode(`data: ${jsonStr}\n\n`))
|
||||
} catch (_enqueueErr) {
|
||||
} catch (enqueueErr) {
|
||||
reader.cancel()
|
||||
}
|
||||
}
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
logger.warn(`[${tracker.requestId}] Failed to parse final buffer: "${buffer}"`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
const _result = await stateResponse.json()
|
||||
const result = await stateResponse.json()
|
||||
logger.info(
|
||||
`[${tracker.requestId}] Successfully reverted workflow ${checkpoint.workflowId} to checkpoint ${checkpointId}`
|
||||
)
|
||||
|
||||
@@ -63,7 +63,7 @@ export async function POST(req: NextRequest) {
|
||||
let parsedWorkflowState
|
||||
try {
|
||||
parsedWorkflowState = JSON.parse(workflowState)
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return createBadRequestResponse('Invalid workflow state JSON')
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,8 @@ export async function POST(req: NextRequest) {
|
||||
return createBadRequestResponse('Failed to update tool call status or tool call not found')
|
||||
}
|
||||
|
||||
const duration = tracker.getDuration()
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: message || `Tool call ${toolCallId} has been ${status.toLowerCase()}`,
|
||||
|
||||
@@ -111,7 +111,7 @@ export async function POST(req: NextRequest) {
|
||||
* GET /api/copilot/feedback
|
||||
* Get all feedback records (for analytics)
|
||||
*/
|
||||
export async function GET(_req: NextRequest) {
|
||||
export async function GET(req: NextRequest) {
|
||||
const tracker = createRequestTracker()
|
||||
|
||||
try {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
authenticateCopilotRequestSessionOnly,
|
||||
createBadRequestResponse,
|
||||
createInternalServerErrorResponse,
|
||||
createRequestTracker,
|
||||
createUnauthorizedResponse,
|
||||
} from '@/lib/copilot/request-helpers'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
@@ -18,6 +19,7 @@ const BodySchema = z.object({
|
||||
})
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const tracker = createRequestTracker()
|
||||
try {
|
||||
const { userId, isAuthenticated } = await authenticateCopilotRequestSessionOnly()
|
||||
if (!isAuthenticated || !userId) {
|
||||
@@ -60,7 +62,7 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return createInternalServerErrorResponse('Failed to forward copilot stats')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ const DEFAULT_ENABLED_MODELS: Record<CopilotModelId, boolean> = {
|
||||
}
|
||||
|
||||
// GET - Fetch user's enabled models
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ async function hasPermission(userId: string, profile: any): Promise<boolean> {
|
||||
}
|
||||
|
||||
// GET /api/creators/[id] - Get a specific creator profile
|
||||
export async function GET(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = generateRequestId()
|
||||
const { id } = await params
|
||||
|
||||
@@ -137,7 +137,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
|
||||
|
||||
// DELETE /api/creators/[id] - Delete a creator profile
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
@@ -12,7 +12,7 @@ const logger = createLogger('CreatorVerificationAPI')
|
||||
export const revalidate = 0
|
||||
|
||||
// POST /api/creators/[id]/verify - Verify a creator (super users only)
|
||||
export async function POST(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = generateRequestId()
|
||||
const { id } = await params
|
||||
|
||||
@@ -62,7 +62,7 @@ export async function POST(_request: NextRequest, { params }: { params: Promise<
|
||||
|
||||
// DELETE /api/creators/[id]/verify - Unverify a creator (super users only)
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
@@ -30,6 +30,8 @@ const CreateCreatorProfileSchema = z.object({
|
||||
// GET /api/creators - Get creator profiles for current user
|
||||
export async function GET(request: NextRequest) {
|
||||
const requestId = generateRequestId()
|
||||
const { searchParams } = new URL(request.url)
|
||||
const userId = searchParams.get('userId')
|
||||
|
||||
try {
|
||||
const session = await getSession()
|
||||
|
||||
@@ -37,7 +37,7 @@ async function getCredentialSetWithAccess(credentialSetId: string, userId: strin
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
_req: NextRequest,
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; invitationId: string }> }
|
||||
) {
|
||||
const session = await getSession()
|
||||
|
||||
@@ -41,7 +41,7 @@ async function getCredentialSetWithAccess(credentialSetId: string, userId: strin
|
||||
return { set, role: membership.role }
|
||||
}
|
||||
|
||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
|
||||
@@ -33,7 +33,7 @@ async function getCredentialSetWithAccess(credentialSetId: string, userId: strin
|
||||
return { set, role: membership.role }
|
||||
}
|
||||
|
||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
|
||||
@@ -43,7 +43,7 @@ async function getCredentialSetWithAccess(credentialSetId: string, userId: strin
|
||||
return { set, role: membership.role }
|
||||
}
|
||||
|
||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
@@ -141,7 +141,7 @@ export async function PUT(req: NextRequest, { params }: { params: Promise<{ id:
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function DELETE(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { syncAllWebhooksForCredentialSet } from '@/lib/webhooks/utils.server'
|
||||
|
||||
const logger = createLogger('CredentialSetInviteToken')
|
||||
|
||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ token: string }> }) {
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ token: string }> }) {
|
||||
const { token } = await params
|
||||
|
||||
const [invitation] = await db
|
||||
@@ -61,7 +61,7 @@ export async function GET(_req: NextRequest, { params }: { params: Promise<{ tok
|
||||
})
|
||||
}
|
||||
|
||||
export async function POST(_req: NextRequest, { params }: { params: Promise<{ token: string }> }) {
|
||||
export async function POST(req: NextRequest, { params }: { params: Promise<{ token: string }> }) {
|
||||
const { token } = await params
|
||||
|
||||
const session = await getSession()
|
||||
|
||||
@@ -72,7 +72,7 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(_request: Request) {
|
||||
export async function GET(request: Request) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
try {
|
||||
|
||||
@@ -162,7 +162,7 @@ async function verifyWorkspaceFileAccess(
|
||||
cloudKey: string,
|
||||
userId: string,
|
||||
customConfig?: StorageConfig,
|
||||
_isLocal?: boolean
|
||||
isLocal?: boolean
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
// Priority 1: Check database (most reliable, works for both local and cloud)
|
||||
@@ -228,7 +228,7 @@ async function verifyWorkspaceFileAccess(
|
||||
async function verifyExecutionFileAccess(
|
||||
cloudKey: string,
|
||||
userId: string,
|
||||
_customConfig?: StorageConfig
|
||||
customConfig?: StorageConfig
|
||||
): Promise<boolean> {
|
||||
const parts = cloudKey.split('/')
|
||||
|
||||
@@ -493,7 +493,7 @@ async function verifyRegularFileAccess(
|
||||
cloudKey: string,
|
||||
userId: string,
|
||||
customConfig?: StorageConfig,
|
||||
_isLocal?: boolean
|
||||
isLocal?: boolean
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
// Priority 1: Check if this might be a workspace file (check database)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import path from 'node:path'
|
||||
import path from 'path'
|
||||
/**
|
||||
* Tests for file parse API route
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Buffer } from 'node:buffer'
|
||||
import { createHash } from 'node:crypto'
|
||||
import fsPromises, { readFile } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { Buffer } from 'buffer'
|
||||
import { createHash } from 'crypto'
|
||||
import fsPromises, { readFile } from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import binaryExtensionsList from 'binary-extensions'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
@@ -899,7 +899,7 @@ Please use a PDF viewer for best results.`
|
||||
* Create error message for PDF parsing failure and make it more readable
|
||||
*/
|
||||
function createPdfFailureMessage(
|
||||
_pageCount: number,
|
||||
pageCount: number,
|
||||
size: number,
|
||||
path: string,
|
||||
error: string
|
||||
|
||||
@@ -131,7 +131,7 @@ describe('File Serve API Route', () => {
|
||||
expect(disposition).toContain('filename=')
|
||||
expect(disposition).toContain('test-file.txt')
|
||||
|
||||
const fs = await import('node:fs/promises')
|
||||
const fs = await import('fs/promises')
|
||||
expect(fs.readFile).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
@@ -196,7 +196,7 @@ describe('File Serve API Route', () => {
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
|
||||
const fs = await import('node:fs/promises')
|
||||
const fs = await import('fs/promises')
|
||||
expect(fs.readFile).toHaveBeenCalledWith('/test/uploads/nested/path/file.txt')
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { readFile } from 'fs/promises'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import { join, resolve, sep } from 'node:path'
|
||||
import { existsSync } from 'fs'
|
||||
import { join, resolve, sep } from 'path'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { UPLOAD_DIR } from '@/lib/uploads/config'
|
||||
@@ -119,7 +119,7 @@ export function extractFilename(path: string): string {
|
||||
return filename
|
||||
}
|
||||
|
||||
function _sanitizeFilename(filename: string): string {
|
||||
function sanitizeFilename(filename: string): string {
|
||||
if (!filename || typeof filename !== 'string') {
|
||||
throw new Error('Invalid filename provided')
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ describe('Individual Folder API Route', () => {
|
||||
await PUT(req, { params })
|
||||
|
||||
expect(capturedUpdates).not.toBeNull()
|
||||
expect(capturedUpdates?.name).toBe('Folder With Spaces')
|
||||
expect(capturedUpdates!.name).toBe('Folder With Spaces')
|
||||
})
|
||||
|
||||
it('should handle database errors gracefully', async () => {
|
||||
|
||||
@@ -106,7 +106,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
|
||||
|
||||
// DELETE - Delete a folder and all its contents
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
|
||||
@@ -551,7 +551,7 @@ describe('Folders API Route', () => {
|
||||
await POST(req)
|
||||
|
||||
expect(capturedValues).not.toBeNull()
|
||||
expect(capturedValues?.name).toBe('Test Folder With Spaces')
|
||||
expect(capturedValues!.name).toBe('Test Folder With Spaces')
|
||||
})
|
||||
|
||||
it('should use default color when not provided', async () => {
|
||||
@@ -591,7 +591,7 @@ describe('Folders API Route', () => {
|
||||
await POST(req)
|
||||
|
||||
expect(capturedValues).not.toBeNull()
|
||||
expect(capturedValues?.color).toBe('#6B7280')
|
||||
expect(capturedValues!.color).toBe('#6B7280')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { db } from '@sim/db'
|
||||
import { form, workflow, workflowBlocks } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
@@ -235,11 +235,28 @@ export async function POST(
|
||||
// For forms, we don't stream back - we wait for completion and return success
|
||||
// Consume the stream to wait for completion
|
||||
const reader = stream.getReader()
|
||||
let lastOutput: any = null
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { done } = await reader.read()
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
|
||||
// Parse SSE data if present
|
||||
const text = new TextDecoder().decode(value)
|
||||
const lines = text.split('\n')
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('data: ')) {
|
||||
try {
|
||||
const data = JSON.parse(line.slice(6))
|
||||
if (data.type === 'complete' || data.output) {
|
||||
lastOutput = data.output || data
|
||||
}
|
||||
} catch {
|
||||
// Ignore parse errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
reader.releaseLock()
|
||||
|
||||
@@ -62,7 +62,7 @@ const updateFormSchema = z.object({
|
||||
isActive: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
|
||||
@@ -201,7 +201,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
|
||||
@@ -64,7 +64,7 @@ const formSchema = z.object({
|
||||
showBranding: z.boolean().optional().default(true),
|
||||
})
|
||||
|
||||
export async function GET(_request: NextRequest) {
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('Form API Utils', () => {
|
||||
|
||||
it.concurrent('should validate tokens with password hash', async () => {
|
||||
const { validateAuthToken } = await import('@/lib/core/security/deployment')
|
||||
const crypto = await import('node:crypto')
|
||||
const crypto = await import('crypto')
|
||||
|
||||
const formId = 'test-form-id'
|
||||
const encryptedPassword = 'encrypted-password-value'
|
||||
|
||||
@@ -292,7 +292,7 @@ function formatE2BError(
|
||||
*/
|
||||
function createUserFriendlyErrorMessage(
|
||||
enhanced: EnhancedError,
|
||||
_requestId: string,
|
||||
requestId: string,
|
||||
userCode?: string
|
||||
): string {
|
||||
let errorMessage = enhanced.message
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
@@ -14,7 +14,7 @@ const UpdateChunkSchema = z.object({
|
||||
})
|
||||
|
||||
export async function GET(
|
||||
_req: NextRequest,
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; documentId: string; chunkId: string }> }
|
||||
) {
|
||||
const requestId = randomUUID().slice(0, 8)
|
||||
@@ -134,7 +134,7 @@ export async function PUT(
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
_req: NextRequest,
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; documentId: string; chunkId: string }> }
|
||||
) {
|
||||
const requestId = randomUUID().slice(0, 8)
|
||||
|
||||
@@ -47,7 +47,7 @@ const UpdateDocumentSchema = z.object({
|
||||
})
|
||||
|
||||
export async function GET(
|
||||
_req: NextRequest,
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; documentId: string }> }
|
||||
) {
|
||||
const requestId = generateRequestId()
|
||||
@@ -123,6 +123,8 @@ export async function PUT(
|
||||
try {
|
||||
const validatedData = UpdateDocumentSchema.parse(body)
|
||||
|
||||
const updateData: any = {}
|
||||
|
||||
if (validatedData.markFailedDueToTimeout) {
|
||||
const doc = accessCheck.document
|
||||
|
||||
@@ -218,7 +220,7 @@ export async function PUT(
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
_req: NextRequest,
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; documentId: string }> }
|
||||
) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
@@ -31,7 +31,7 @@ const BulkTagDefinitionsSchema = z.object({
|
||||
|
||||
// GET /api/knowledge/[id]/documents/[documentId]/tag-definitions - Get tag definitions for a document
|
||||
export async function GET(
|
||||
_req: NextRequest,
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; documentId: string }> }
|
||||
) {
|
||||
const requestId = randomUUID().slice(0, 8)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
@@ -11,7 +11,7 @@ const logger = createLogger('TagDefinitionAPI')
|
||||
|
||||
// DELETE /api/knowledge/[id]/tag-definitions/[tagId] - Delete a tag definition
|
||||
export async function DELETE(
|
||||
_req: NextRequest,
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; tagId: string }> }
|
||||
) {
|
||||
const requestId = randomUUID().slice(0, 8)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
@@ -10,7 +10,7 @@ export const dynamic = 'force-dynamic'
|
||||
const logger = createLogger('TagUsageAPI')
|
||||
|
||||
// GET /api/knowledge/[id]/tag-usage - Get usage statistics for all tag definitions
|
||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = randomUUID().slice(0, 8)
|
||||
const { id: knowledgeBaseId } = await params
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ function getStructuredTagFilters(filters: StructuredFilter[], embeddingTable: an
|
||||
if (!filtersBySlot.has(slot)) {
|
||||
filtersBySlot.set(slot, [])
|
||||
}
|
||||
filtersBySlot.get(slot)?.push(filter)
|
||||
filtersBySlot.get(slot)!.push(filter)
|
||||
}
|
||||
|
||||
// Build conditions: OR within same slot, AND across different slots
|
||||
|
||||
@@ -63,7 +63,7 @@ async function getServer(serverId: string) {
|
||||
return server
|
||||
}
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: { params: Promise<RouteParams> }) {
|
||||
export async function GET(request: NextRequest, { params }: { params: Promise<RouteParams> }) {
|
||||
const { serverId } = await params
|
||||
|
||||
try {
|
||||
|
||||
@@ -140,7 +140,7 @@ async function syncToolSchemasToWorkflows(
|
||||
}
|
||||
|
||||
export const POST = withMcpAuth<{ id: string }>('read')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
const { id: serverId } = await params
|
||||
|
||||
try {
|
||||
|
||||
@@ -19,7 +19,7 @@ export const dynamic = 'force-dynamic'
|
||||
* GET - List all registered MCP servers for the workspace
|
||||
*/
|
||||
export const GET = withMcpAuth('read')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }) => {
|
||||
try {
|
||||
logger.info(`[${requestId}] Listing MCP servers for workspace ${workspaceId}`)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ const logger = createLogger('McpStoredToolsAPI')
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export const GET = withMcpAuth('read')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }) => {
|
||||
try {
|
||||
logger.info(`[${requestId}] Fetching stored MCP tools for workspace ${workspaceId}`)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ interface RouteParams {
|
||||
* GET - Get a specific workflow MCP server with its tools
|
||||
*/
|
||||
export const GET = withMcpAuth<RouteParams>('read')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
try {
|
||||
const { id: serverId } = await params
|
||||
|
||||
@@ -127,7 +127,7 @@ export const PATCH = withMcpAuth<RouteParams>('write')(
|
||||
* DELETE - Delete a workflow MCP server and all its tools
|
||||
*/
|
||||
export const DELETE = withMcpAuth<RouteParams>('admin')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
try {
|
||||
const { id: serverId } = await params
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ interface RouteParams {
|
||||
* GET - Get a specific tool
|
||||
*/
|
||||
export const GET = withMcpAuth<RouteParams>('read')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
try {
|
||||
const { id: serverId, toolId } = await params
|
||||
|
||||
@@ -131,7 +131,7 @@ export const PATCH = withMcpAuth<RouteParams>('write')(
|
||||
* DELETE - Remove a tool from an MCP server
|
||||
*/
|
||||
export const DELETE = withMcpAuth<RouteParams>('write')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
try {
|
||||
const { id: serverId, toolId } = await params
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ interface RouteParams {
|
||||
* GET - List all tools for a workflow MCP server
|
||||
*/
|
||||
export const GET = withMcpAuth<RouteParams>('read')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }, { params }) => {
|
||||
try {
|
||||
const { id: serverId } = await params
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export const dynamic = 'force-dynamic'
|
||||
* GET - List all workflow MCP servers for the workspace
|
||||
*/
|
||||
export const GET = withMcpAuth('read')(
|
||||
async (_request: NextRequest, { userId, workspaceId, requestId }) => {
|
||||
async (request: NextRequest, { userId, workspaceId, requestId }) => {
|
||||
try {
|
||||
logger.info(`[${requestId}] Listing workflow MCP servers for workspace ${workspaceId}`)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { db } from '@sim/db'
|
||||
import {
|
||||
invitation,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { db } from '@sim/db'
|
||||
import {
|
||||
invitation,
|
||||
@@ -42,7 +42,7 @@ interface WorkspaceInvitation {
|
||||
* GET /api/organizations/[id]/invitations
|
||||
* Get all pending invitations for an organization
|
||||
*/
|
||||
export async function GET(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
try {
|
||||
const session = await getSession()
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ export async function PUT(
|
||||
* Remove member from organization
|
||||
*/
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string; memberId: string }> }
|
||||
) {
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { db } from '@sim/db'
|
||||
import { invitation, member, organization, user, userStats } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
|
||||
@@ -32,7 +32,7 @@ async function getPermissionGroupWithAccess(groupId: string, userId: string) {
|
||||
return { group, role: membership.role }
|
||||
}
|
||||
|
||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
|
||||
@@ -70,7 +70,7 @@ async function getPermissionGroupWithAccess(groupId: string, userId: string) {
|
||||
return { group, role: membership.role }
|
||||
}
|
||||
|
||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
@@ -195,7 +195,7 @@ export async function PUT(req: NextRequest, { params }: { params: Promise<{ id:
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function DELETE(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
|
||||
@@ -5,7 +5,7 @@ export async function GET() {
|
||||
try {
|
||||
const allModels = Object.keys(getBaseModelProviders())
|
||||
return NextResponse.json({ models: allModels })
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return NextResponse.json({ models: [], error: 'Failed to fetch models' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
|
||||
@@ -14,7 +14,7 @@ export const revalidate = 0
|
||||
/**
|
||||
* POST /api/templates/[id]/approve - Approve a template (super users only)
|
||||
*/
|
||||
export async function POST(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = generateRequestId()
|
||||
const { id } = await params
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export const revalidate = 0
|
||||
/**
|
||||
* POST /api/templates/[id]/reject - Reject a template (super users only)
|
||||
*/
|
||||
export async function POST(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = generateRequestId()
|
||||
const { id } = await params
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const logger = createLogger('TemplateByIdAPI')
|
||||
|
||||
export const revalidate = 0
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = generateRequestId()
|
||||
const { id } = await params
|
||||
|
||||
@@ -234,7 +234,7 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
|
||||
|
||||
// DELETE /api/templates/[id] - Delete a template
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
@@ -13,7 +13,7 @@ export const dynamic = 'force-dynamic'
|
||||
export const revalidate = 0
|
||||
|
||||
// GET /api/templates/[id]/star - Check if user has starred this template
|
||||
export async function GET(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = generateRequestId()
|
||||
const { id } = await params
|
||||
|
||||
@@ -47,7 +47,7 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{
|
||||
}
|
||||
|
||||
// POST /api/templates/[id]/star - Add a star to the template
|
||||
export async function POST(_request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = generateRequestId()
|
||||
const { id } = await params
|
||||
|
||||
@@ -120,7 +120,7 @@ export async function POST(_request: NextRequest, { params }: { params: Promise<
|
||||
|
||||
// DELETE /api/templates/[id]/star - Remove a star from the template
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
@@ -136,7 +136,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
||||
}
|
||||
|
||||
// Use a transaction for template updates and deployment version
|
||||
const _result = await db.transaction(async (tx) => {
|
||||
const result = await db.transaction(async (tx) => {
|
||||
// Prepare template update data
|
||||
const updateData: any = {
|
||||
views: sql`${templates.views} + 1`,
|
||||
|
||||
@@ -20,6 +20,7 @@ export async function GET(request: NextRequest) {
|
||||
const requestId = generateRequestId()
|
||||
|
||||
try {
|
||||
const url = new URL(request.url)
|
||||
const hasApiKey = !!request.headers.get('x-api-key')
|
||||
|
||||
// Check internal API key authentication
|
||||
@@ -125,7 +126,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
// Add a helpful OPTIONS handler for CORS preflight
|
||||
export async function OPTIONS(_request: NextRequest) {
|
||||
export async function OPTIONS(request: NextRequest) {
|
||||
const requestId = generateRequestId()
|
||||
logger.info(`[${requestId}] OPTIONS request received for /api/templates/approved/sanitized`)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import type {
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { createA2AClient, isTerminalState } from '@/lib/a2a/utils'
|
||||
import { createA2AClient, extractTextContent, isTerminalState } from '@/lib/a2a/utils'
|
||||
import { checkHybridAuth } from '@/lib/auth/hybrid'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
|
||||
@@ -50,12 +50,14 @@ export async function POST(request: NextRequest) {
|
||||
let taskId = validatedData.taskId
|
||||
let contextId: string | undefined
|
||||
let state: TaskState = 'working'
|
||||
let content = ''
|
||||
let artifacts: Artifact[] = []
|
||||
let history: Message[] = []
|
||||
|
||||
for await (const event of stream) {
|
||||
if (event.kind === 'message') {
|
||||
const msg = event as Message
|
||||
content = extractTextContent(msg)
|
||||
taskId = msg.taskId || taskId
|
||||
contextId = msg.contextId || contextId
|
||||
state = 'completed'
|
||||
@@ -66,6 +68,10 @@ export async function POST(request: NextRequest) {
|
||||
state = task.status.state
|
||||
artifacts = task.artifacts || []
|
||||
history = task.history || []
|
||||
const lastAgentMessage = history.filter((m) => m.role === 'agent').pop()
|
||||
if (lastAgentMessage) {
|
||||
content = extractTextContent(lastAgentMessage)
|
||||
}
|
||||
} else if ('status' in event) {
|
||||
const statusEvent = event as TaskStatusUpdateEvent
|
||||
state = statusEvent.status.state
|
||||
|
||||
@@ -82,7 +82,7 @@ describe('Custom Tools API Routes', () => {
|
||||
|
||||
mockSelect.mockReturnValue({ from: mockFrom })
|
||||
mockFrom.mockReturnValue({ where: mockWhere })
|
||||
mockWhere.mockImplementation((_condition) => {
|
||||
mockWhere.mockImplementation((condition) => {
|
||||
const queryBuilder = {
|
||||
orderBy: mockOrderBy,
|
||||
limit: mockLimit,
|
||||
@@ -90,7 +90,7 @@ describe('Custom Tools API Routes', () => {
|
||||
resolve(sampleTools)
|
||||
return queryBuilder
|
||||
},
|
||||
catch: (_reject: (error: Error) => void) => queryBuilder,
|
||||
catch: (reject: (error: Error) => void) => queryBuilder,
|
||||
}
|
||||
return queryBuilder
|
||||
})
|
||||
@@ -101,7 +101,7 @@ describe('Custom Tools API Routes', () => {
|
||||
resolve(sampleTools)
|
||||
return queryBuilder
|
||||
},
|
||||
catch: (_reject: (error: Error) => void) => queryBuilder,
|
||||
catch: (reject: (error: Error) => void) => queryBuilder,
|
||||
}
|
||||
return queryBuilder
|
||||
})
|
||||
@@ -131,12 +131,12 @@ describe('Custom Tools API Routes', () => {
|
||||
resolve(sampleTools)
|
||||
return queryBuilder
|
||||
},
|
||||
catch: (_reject: (error: Error) => void) => queryBuilder,
|
||||
catch: (reject: (error: Error) => void) => queryBuilder,
|
||||
}
|
||||
return queryBuilder
|
||||
})
|
||||
|
||||
const txMockWhere = vi.fn().mockImplementation((_condition) => {
|
||||
const txMockWhere = vi.fn().mockImplementation((condition) => {
|
||||
const queryBuilder = {
|
||||
orderBy: txMockOrderBy,
|
||||
limit: mockLimit,
|
||||
@@ -144,7 +144,7 @@ describe('Custom Tools API Routes', () => {
|
||||
resolve(sampleTools)
|
||||
return queryBuilder
|
||||
},
|
||||
catch: (_reject: (error: Error) => void) => queryBuilder,
|
||||
catch: (reject: (error: Error) => void) => queryBuilder,
|
||||
}
|
||||
return queryBuilder
|
||||
})
|
||||
@@ -274,14 +274,14 @@ describe('Custom Tools API Routes', () => {
|
||||
|
||||
mockLimit.mockResolvedValueOnce([{ workspaceId: 'workspace-123' }])
|
||||
|
||||
mockWhere.mockImplementationOnce((_condition) => {
|
||||
mockWhere.mockImplementationOnce((condition) => {
|
||||
const queryBuilder = {
|
||||
limit: mockLimit,
|
||||
then: (resolve: (value: typeof sampleTools) => void) => {
|
||||
resolve(sampleTools)
|
||||
return queryBuilder
|
||||
},
|
||||
catch: (_reject: (error: Error) => void) => queryBuilder,
|
||||
catch: (reject: (error: Error) => void) => queryBuilder,
|
||||
}
|
||||
return queryBuilder
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
@@ -19,6 +20,7 @@ export async function POST(request: Request) {
|
||||
}
|
||||
|
||||
try {
|
||||
const requestId = generateRequestId()
|
||||
const authz = await authorizeCredentialUse(request as any, {
|
||||
credentialId: credential,
|
||||
workflowId,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { db } from '@sim/db'
|
||||
import { account } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import {
|
||||
createMongoDBConnection,
|
||||
sanitizeCollectionName,
|
||||
validateFilter,
|
||||
} from '@/app/api/tools/mongodb/utils'
|
||||
import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from '../utils'
|
||||
|
||||
const logger = createLogger('MongoDBDeleteAPI')
|
||||
|
||||
@@ -73,7 +69,7 @@ export async function POST(request: NextRequest) {
|
||||
let filterDoc
|
||||
try {
|
||||
filterDoc = JSON.parse(params.filter)
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] Invalid filter JSON: ${params.filter}`)
|
||||
return NextResponse.json({ error: 'Invalid JSON format in filter' }, { status: 400 })
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import {
|
||||
createMongoDBConnection,
|
||||
sanitizeCollectionName,
|
||||
validatePipeline,
|
||||
} from '@/app/api/tools/mongodb/utils'
|
||||
import { createMongoDBConnection, sanitizeCollectionName, validatePipeline } from '../utils'
|
||||
|
||||
const logger = createLogger('MongoDBExecuteAPI')
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { createMongoDBConnection, sanitizeCollectionName } from '@/app/api/tools/mongodb/utils'
|
||||
import { createMongoDBConnection, sanitizeCollectionName } from '../utils'
|
||||
|
||||
const logger = createLogger('MongoDBInsertAPI')
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { createMongoDBConnection, executeIntrospect } from '@/app/api/tools/mongodb/utils'
|
||||
import { createMongoDBConnection, executeIntrospect } from '../utils'
|
||||
|
||||
const logger = createLogger('MongoDBIntrospectAPI')
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import {
|
||||
createMongoDBConnection,
|
||||
sanitizeCollectionName,
|
||||
validateFilter,
|
||||
} from '@/app/api/tools/mongodb/utils'
|
||||
import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from '../utils'
|
||||
|
||||
const logger = createLogger('MongoDBQueryAPI')
|
||||
|
||||
@@ -87,7 +83,7 @@ export async function POST(request: NextRequest) {
|
||||
if (params.sort?.trim()) {
|
||||
try {
|
||||
sortCriteria = JSON.parse(params.sort)
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] Invalid sort JSON: ${params.sort}`)
|
||||
return NextResponse.json({ error: 'Invalid JSON format in sort criteria' }, { status: 400 })
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import {
|
||||
createMongoDBConnection,
|
||||
sanitizeCollectionName,
|
||||
validateFilter,
|
||||
} from '@/app/api/tools/mongodb/utils'
|
||||
import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from '../utils'
|
||||
|
||||
const logger = createLogger('MongoDBUpdateAPI')
|
||||
|
||||
@@ -94,7 +90,7 @@ export async function POST(request: NextRequest) {
|
||||
try {
|
||||
filterDoc = JSON.parse(params.filter)
|
||||
updateDoc = JSON.parse(params.update)
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] Invalid JSON in filter or update`)
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid JSON format in filter or update' },
|
||||
|
||||
@@ -72,7 +72,7 @@ export function validateFilter(filter: string): { isValid: boolean; error?: stri
|
||||
}
|
||||
|
||||
return { isValid: true }
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: 'Invalid JSON format in filter',
|
||||
@@ -113,7 +113,7 @@ export function validatePipeline(pipeline: string): { isValid: boolean; error?:
|
||||
}
|
||||
|
||||
return { isValid: true }
|
||||
} catch (_error) {
|
||||
} catch (error) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: 'Invalid JSON format in pipeline',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
@@ -29,7 +29,7 @@ const UpdateSchema = z.object({
|
||||
throw new Error('Data must be a JSON object')
|
||||
}
|
||||
return parsed
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
throw new Error('Invalid JSON format in data field')
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -271,7 +271,7 @@ export async function executeIntrospect(
|
||||
unique: row.NON_UNIQUE === 0,
|
||||
})
|
||||
}
|
||||
indexMap.get(indexName)?.columns.push(row.COLUMN_NAME)
|
||||
indexMap.get(indexName)!.columns.push(row.COLUMN_NAME)
|
||||
}
|
||||
const indexes = Array.from(indexMap.values())
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user