mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-28 03:00:29 -04:00
improvement(utils): add shared utility functions and replace inline patterns
Add sleep, toError, safeJsonParse, isNonNull helpers and invariant/assertNever assertions. Replace all inline implementations across the codebase with these shared utilities for consistency. Zero behavioral changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,5 +30,32 @@ const shortId = generateShortId()
|
||||
const tiny = generateShortId(8)
|
||||
```
|
||||
|
||||
## Common Utilities
|
||||
Use shared helpers from `@/lib/core/utils/helpers` instead of writing inline implementations:
|
||||
|
||||
- `sleep(ms)` — async delay. Never write `new Promise(resolve => setTimeout(resolve, ms))`
|
||||
- `toError(value)` — normalize unknown caught values to `Error`. Never write `e instanceof Error ? e : new Error(String(e))`
|
||||
- `toError(value).message` — get error message safely. Never write `e instanceof Error ? e.message : String(e)`
|
||||
- `safeJsonParse(str, fallback?)` — parse JSON without throwing. Never write `try { JSON.parse(str) } catch { return default }`
|
||||
- `isNonNull(value)` — type-narrowing filter predicate for null/undefined
|
||||
|
||||
Use assertion utilities from `@/lib/core/utils/asserts`:
|
||||
|
||||
- `invariant(condition, message)` — assert a condition is truthy, throws if not
|
||||
- `assertNever(value)` — exhaustive switch/if-else check, TypeScript errors at compile time if a case is unhandled
|
||||
|
||||
```typescript
|
||||
// ✗ Bad
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
const msg = error instanceof Error ? error.message : String(error)
|
||||
const err = error instanceof Error ? error : new Error(String(error))
|
||||
|
||||
// ✓ Good
|
||||
import { sleep, toError } from '@/lib/core/utils/helpers'
|
||||
await sleep(1000)
|
||||
const msg = toError(error).message
|
||||
const err = toError(error)
|
||||
```
|
||||
|
||||
## Package Manager
|
||||
Use `bun` and `bunx`, not `npm` and `npx`.
|
||||
|
||||
@@ -37,5 +37,32 @@ const shortId = generateShortId()
|
||||
const tiny = generateShortId(8)
|
||||
```
|
||||
|
||||
## Common Utilities
|
||||
Use shared helpers from `@/lib/core/utils/helpers` instead of writing inline implementations:
|
||||
|
||||
- `sleep(ms)` — async delay. Never write `new Promise(resolve => setTimeout(resolve, ms))`
|
||||
- `toError(value)` — normalize unknown caught values to `Error`. Never write `e instanceof Error ? e : new Error(String(e))`
|
||||
- `toError(value).message` — get error message safely. Never write `e instanceof Error ? e.message : String(e)`
|
||||
- `safeJsonParse(str, fallback?)` — parse JSON without throwing. Never write `try { JSON.parse(str) } catch { return default }`
|
||||
- `isNonNull(value)` — type-narrowing filter predicate for null/undefined
|
||||
|
||||
Use assertion utilities from `@/lib/core/utils/asserts`:
|
||||
|
||||
- `invariant(condition, message)` — assert a condition is truthy, throws if not
|
||||
- `assertNever(value)` — exhaustive switch/if-else check, TypeScript errors at compile time if a case is unhandled
|
||||
|
||||
```typescript
|
||||
// ✗ Bad
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
const msg = error instanceof Error ? error.message : String(error)
|
||||
const err = error instanceof Error ? error : new Error(String(error))
|
||||
|
||||
// ✓ Good
|
||||
import { sleep, toError } from '@/lib/core/utils/helpers'
|
||||
await sleep(1000)
|
||||
const msg = toError(error).message
|
||||
const err = toError(error)
|
||||
```
|
||||
|
||||
## Package Manager
|
||||
Use `bun` and `bunx`, not `npm` and `npx`.
|
||||
|
||||
@@ -8,6 +8,7 @@ You are a professional software engineer. All code must follow best practices: a
|
||||
- **Comments**: Use TSDoc for documentation. No `====` separators. No non-TSDoc comments
|
||||
- **Styling**: Never update global styles. Keep all styling local to components
|
||||
- **ID Generation**: Never use `crypto.randomUUID()`, `nanoid`, or `uuid` package. Use `generateId()` (UUID v4) or `generateShortId()` (compact) from `@/lib/core/utils/uuid`
|
||||
- **Common Utilities**: Use shared helpers from `@/lib/core/utils/helpers` instead of inline implementations. `sleep(ms)` for delays, `toError(e)` to normalize caught values, `safeJsonParse(str, fallback?)` for safe JSON parsing, `isNonNull(v)` for type-narrowing null filters. Use `invariant(cond, msg)` and `assertNever(val)` from `@/lib/core/utils/asserts` for runtime assertions and exhaustive checks.
|
||||
- **Package Manager**: Use `bun` and `bunx`, not `npm` and `npx`
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
} from '@/lib/academy/types'
|
||||
import { validateExercise } from '@/lib/academy/validation'
|
||||
import { cn } from '@/lib/core/utils/cn'
|
||||
import { sleep } from '@/lib/core/utils/helpers'
|
||||
import { getEffectiveBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
|
||||
import { getQueryClient } from '@/app/_shell/providers/get-query-client'
|
||||
import { GlobalCommandsProvider } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
|
||||
@@ -323,7 +324,7 @@ export function SandboxCanvasProvider({
|
||||
for (let i = 0; i < plan.length; i++) {
|
||||
const step = plan[i]
|
||||
setActiveBlocks(workflowId, new Set([step.blockId]))
|
||||
await new Promise((resolve) => setTimeout(resolve, step.delay))
|
||||
await sleep(step.delay)
|
||||
addConsole({
|
||||
workflowId,
|
||||
blockId: step.blockId,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { account, credential, credentialSetMember } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { and, desc, eq, inArray } from 'drizzle-orm'
|
||||
import { decryptSecret } from '@/lib/core/security/encryption'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { refreshOAuthToken } from '@/lib/oauth'
|
||||
import {
|
||||
getMicrosoftRefreshTokenExpiry,
|
||||
@@ -331,7 +332,7 @@ export async function getOAuthToken(userId: string, providerId: string): Promise
|
||||
return accessToken
|
||||
} catch (error) {
|
||||
logger.error(`Error refreshing token for user ${userId}, provider ${providerId}`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
providerId,
|
||||
userId,
|
||||
@@ -460,7 +461,7 @@ export async function refreshAccessTokenIfNeeded(
|
||||
return refreshedToken.accessToken
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error refreshing token for credential`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
providerId: credential.providerId,
|
||||
credentialId,
|
||||
@@ -664,7 +665,7 @@ export async function getCredentialsForCredentialSet(
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Failed to refresh token for user ${cred.userId}, provider ${providerId}`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { headers } from 'next/headers'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { auth } from '@/lib/auth'
|
||||
import { isAuthDisabled } from '@/lib/core/config/feature-flags'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('SocketTokenAPI')
|
||||
|
||||
@@ -36,7 +37,7 @@ export async function POST() {
|
||||
}
|
||||
|
||||
logger.error('Failed to generate socket token', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
return NextResponse.json({ error: 'Failed to generate token' }, { status: 500 })
|
||||
|
||||
@@ -147,6 +147,32 @@ export async function POST(request: NextRequest) {
|
||||
oidcConfig.userInfoEndpoint = userInfoEndpoint
|
||||
oidcConfig.jwksEndpoint = jwksEndpoint
|
||||
|
||||
const userProvidedEndpoints: Record<string, string | undefined> = {
|
||||
authorizationEndpoint,
|
||||
tokenEndpoint,
|
||||
userInfoEndpoint,
|
||||
jwksEndpoint,
|
||||
}
|
||||
|
||||
for (const [name, endpointUrl] of Object.entries(userProvidedEndpoints)) {
|
||||
if (endpointUrl) {
|
||||
const endpointValidation = await validateUrlWithDNS(endpointUrl, `OIDC ${name}`)
|
||||
if (!endpointValidation.isValid) {
|
||||
logger.warn('Explicitly provided OIDC endpoint failed SSRF validation', {
|
||||
endpoint: name,
|
||||
url: endpointUrl,
|
||||
error: endpointValidation.error,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `OIDC ${name} failed security validation: ${endpointValidation.error}`,
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const needsDiscovery =
|
||||
!oidcConfig.authorizationEndpoint || !oidcConfig.tokenEndpoint || !oidcConfig.jwksEndpoint
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
hasUsableSubscriptionStatus,
|
||||
} from '@/lib/billing/subscriptions/utils'
|
||||
import { isBillingEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { captureServerEvent } from '@/lib/posthog/server'
|
||||
|
||||
const logger = createLogger('SwitchPlan')
|
||||
@@ -185,7 +186,7 @@ export async function POST(request: NextRequest) {
|
||||
} catch (error) {
|
||||
logger.error('Failed to switch subscription', {
|
||||
userId: session?.user?.id,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{ error: error instanceof Error ? error.message : 'Failed to switch plan' },
|
||||
|
||||
@@ -7,6 +7,7 @@ import { checkAndBillOverageThreshold } from '@/lib/billing/threshold-billing'
|
||||
import { checkInternalApiKey } from '@/lib/copilot/request/http'
|
||||
import { isBillingEnabled } from '@/lib/core/config/feature-flags'
|
||||
import { type AtomicClaimResult, billingIdempotency } from '@/lib/core/idempotency/service'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
|
||||
const logger = createLogger('BillingUpdateCostAPI')
|
||||
@@ -170,7 +171,7 @@ export async function POST(req: NextRequest) {
|
||||
const duration = Date.now() - startTime
|
||||
|
||||
logger.error(`[${requestId}] Cost update failed`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
duration,
|
||||
})
|
||||
@@ -180,7 +181,7 @@ export async function POST(req: NextRequest) {
|
||||
.release(claim.normalizedKey, claim.storageMethod)
|
||||
.catch((releaseErr) => {
|
||||
logger.warn(`[${requestId}] Failed to release idempotency claim`, {
|
||||
error: releaseErr instanceof Error ? releaseErr.message : String(releaseErr),
|
||||
error: toError(releaseErr).message,
|
||||
normalizedKey: claim?.normalizedKey,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import { SIM_AGENT_API_URL } from '@/lib/copilot/constants'
|
||||
import { authenticateCopilotRequestSessionOnly } from '@/lib/copilot/request/http'
|
||||
import { abortActiveStream, waitForPendingChatStream } from '@/lib/copilot/request/session'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('CopilotChatAbortAPI')
|
||||
const GO_EXPLICIT_ABORT_TIMEOUT_MS = 3000
|
||||
@@ -20,7 +21,7 @@ export async function POST(request: Request) {
|
||||
|
||||
const body = await request.json().catch((err) => {
|
||||
logger.warn('Abort request body parse failed; continuing with empty object', {
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
return {}
|
||||
})
|
||||
@@ -35,7 +36,7 @@ export async function POST(request: Request) {
|
||||
const run = await getLatestRunForStream(streamId, authenticatedUserId).catch((err) => {
|
||||
logger.warn('getLatestRunForStream failed while resolving chatId for abort', {
|
||||
streamId,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
return null
|
||||
})
|
||||
@@ -70,7 +71,7 @@ export async function POST(request: Request) {
|
||||
} catch (err) {
|
||||
logger.warn('Explicit abort marker request failed; proceeding with local abort', {
|
||||
streamId,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { readFilePreviewSessions } from '@/lib/copilot/request/session'
|
||||
import { readEvents } from '@/lib/copilot/request/session/buffer'
|
||||
import { toStreamBatchEvent } from '@/lib/copilot/request/session/types'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { authorizeWorkflowByWorkspacePermission } from '@/lib/workflows/utils'
|
||||
import { assertActiveWorkspaceAccess } from '@/lib/workspaces/permissions/utils'
|
||||
|
||||
@@ -82,7 +83,7 @@ export async function GET(req: NextRequest) {
|
||||
logger.warn('Failed to read preview sessions for copilot chat', {
|
||||
chatId,
|
||||
conversationId: chat.conversationId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return []
|
||||
}),
|
||||
@@ -90,7 +91,7 @@ export async function GET(req: NextRequest) {
|
||||
logger.warn('Failed to fetch latest run for copilot chat snapshot', {
|
||||
chatId,
|
||||
conversationId: chat.conversationId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return null
|
||||
}),
|
||||
@@ -110,7 +111,7 @@ export async function GET(req: NextRequest) {
|
||||
logger.warn('Failed to load copilot chat stream snapshot', {
|
||||
chatId,
|
||||
conversationId: chat.conversationId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
SSE_RESPONSE_HEADERS,
|
||||
} from '@/lib/copilot/request/session'
|
||||
import { toStreamBatchEvent } from '@/lib/copilot/request/session/types'
|
||||
import { sleep, toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
export const maxDuration = 3600
|
||||
|
||||
@@ -97,7 +98,7 @@ export async function GET(request: NextRequest) {
|
||||
const run = await getLatestRunForStream(streamId, authenticatedUserId).catch((err) => {
|
||||
logger.warn('Failed to fetch latest run for stream', {
|
||||
streamId,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
return null
|
||||
})
|
||||
@@ -119,7 +120,7 @@ export async function GET(request: NextRequest) {
|
||||
readFilePreviewSessions(streamId).catch((error) => {
|
||||
logger.warn('Failed to read preview sessions for stream batch', {
|
||||
streamId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return []
|
||||
}),
|
||||
@@ -235,7 +236,7 @@ export async function GET(request: NextRequest) {
|
||||
(err) => {
|
||||
logger.warn('Failed to poll latest run for stream', {
|
||||
streamId,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
return null
|
||||
}
|
||||
@@ -273,7 +274,7 @@ export async function GET(request: NextRequest) {
|
||||
break
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
|
||||
await sleep(POLL_INTERVAL_MS)
|
||||
}
|
||||
if (!controllerClosed && Date.now() - startTime >= MAX_STREAM_MS) {
|
||||
emitTerminalIfMissing(MothershipStreamV1CompletionStatus.error, {
|
||||
@@ -286,7 +287,7 @@ export async function GET(request: NextRequest) {
|
||||
if (!controllerClosed && !request.signal.aborted) {
|
||||
logger.warn('Stream replay failed', {
|
||||
streamId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
emitTerminalIfMissing(MothershipStreamV1CompletionStatus.error, {
|
||||
message: 'The stream replay failed before completion.',
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
createRequestTracker,
|
||||
createUnauthorizedResponse,
|
||||
} from '@/lib/copilot/request/http'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('CopilotConfirmAPI')
|
||||
|
||||
@@ -106,7 +107,7 @@ async function updateToolCallStatus(
|
||||
logger.error('Failed to update tool call status', {
|
||||
toolCallId,
|
||||
status,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return false
|
||||
}
|
||||
@@ -133,7 +134,7 @@ export async function POST(req: NextRequest) {
|
||||
const existing = await getAsyncToolCall(toolCallId).catch((err) => {
|
||||
logger.warn('Failed to fetch async tool call', {
|
||||
toolCallId,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
return null
|
||||
})
|
||||
@@ -145,7 +146,7 @@ export async function POST(req: NextRequest) {
|
||||
const run = await getRunSegment(existing.runId).catch((err) => {
|
||||
logger.warn('Failed to fetch run segment', {
|
||||
runId: existing.runId,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
return null
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { SIM_AGENT_API_URL } from '@/lib/copilot/constants'
|
||||
import { authenticateCopilotRequestSessionOnly } from '@/lib/copilot/request/http'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
interface AvailableModel {
|
||||
id: string
|
||||
@@ -76,7 +77,7 @@ export async function GET(_req: NextRequest) {
|
||||
return NextResponse.json({ success: true, models })
|
||||
} catch (error) {
|
||||
logger.error('Error fetching available models', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { verifyCronAuth } from '@/lib/auth/internal'
|
||||
import { JOB_RETENTION_HOURS, JOB_STATUS } from '@/lib/core/async-jobs'
|
||||
import { getMaxExecutionTimeout } from '@/lib/core/execution-limits'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('CleanupStaleExecutions')
|
||||
|
||||
@@ -73,7 +74,7 @@ export async function GET(request: NextRequest) {
|
||||
cleaned++
|
||||
} catch (error) {
|
||||
logger.error(`Failed to clean up execution ${execution.executionId}:`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
failed++
|
||||
}
|
||||
@@ -104,7 +105,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to clean up stale async jobs:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to clean up stale pending jobs:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -158,7 +159,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to delete old async jobs:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkHybridAuth } from '@/lib/auth/hybrid'
|
||||
import { getJobQueue } from '@/lib/core/async-jobs'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { createErrorResponse } from '@/app/api/workflows/utils'
|
||||
|
||||
@@ -70,7 +71,7 @@ export async function GET(
|
||||
|
||||
return NextResponse.json(response)
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
logger.error(`[${requestId}] Error fetching task status:`, error)
|
||||
|
||||
if (errorMessage?.includes('not found')) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { prepareExecutionContext } from '@/lib/copilot/tools/handlers/context'
|
||||
import { DIRECT_TOOL_DEFS, SUBAGENT_TOOL_DEFS } from '@/lib/copilot/tools/mcp/definitions'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { RateLimiter } from '@/lib/core/rate-limiter'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getBaseUrl } from '@/lib/core/utils/urls'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import {
|
||||
@@ -231,7 +232,7 @@ class NextResponseCapture {
|
||||
try {
|
||||
handler()
|
||||
} catch (error) {
|
||||
this.triggerErrorHandlers(error instanceof Error ? error : new Error(String(error)))
|
||||
this.triggerErrorHandlers(toError(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +291,7 @@ class NextResponseCapture {
|
||||
try {
|
||||
this._controller.enqueue(normalized)
|
||||
} catch (error) {
|
||||
this.triggerErrorHandlers(error instanceof Error ? error : new Error(String(error)))
|
||||
this.triggerErrorHandlers(toError(error))
|
||||
}
|
||||
} else {
|
||||
this._pendingChunks.push(normalized)
|
||||
@@ -311,7 +312,7 @@ class NextResponseCapture {
|
||||
try {
|
||||
this._controller.close()
|
||||
} catch (error) {
|
||||
this.triggerErrorHandlers(error instanceof Error ? error : new Error(String(error)))
|
||||
this.triggerErrorHandlers(toError(error))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,7 +660,7 @@ async function handleDirectToolCall(
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
text: `Tool execution failed: ${toError(error).message}`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
@@ -740,7 +741,7 @@ async function handleBuildToolCall(
|
||||
logger.warn('Failed to generate workspace context for build tool call', {
|
||||
workflowId: resolved.workflowId,
|
||||
workspaceId: resolvedWorkspaceId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -789,7 +790,7 @@ async function handleBuildToolCall(
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Build failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
text: `Build failed: ${toError(error).message}`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
@@ -880,7 +881,7 @@ async function handleSubagentToolCall(
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Subagent call failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
text: `Subagent call failed: ${toError(error).message}`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { mcpServers, workflow, workflowBlocks } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { withMcpAuth } from '@/lib/mcp/middleware'
|
||||
import { mcpService } from '@/lib/mcp/service'
|
||||
import type { McpServerStatusConfig, McpTool, McpToolSchema } from '@/lib/mcp/types'
|
||||
@@ -249,11 +250,7 @@ export const POST = withMcpAuth<{ id: string }>('read')(
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error refreshing MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to refresh MCP server'),
|
||||
'Failed to refresh MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to refresh MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import {
|
||||
McpDnsResolutionError,
|
||||
McpDomainNotAllowedError,
|
||||
@@ -138,11 +139,7 @@ export const PATCH = withMcpAuth<{ id: string }>('write')(
|
||||
return createMcpSuccessResponse({ server: updatedServer })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error updating MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to update MCP server'),
|
||||
'Failed to update MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to update MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import {
|
||||
McpDnsResolutionError,
|
||||
@@ -44,11 +45,7 @@ export const GET = withMcpAuth('read')(
|
||||
return createMcpSuccessResponse({ servers })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error listing MCP servers:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to list MCP servers'),
|
||||
'Failed to list MCP servers',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to list MCP servers', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -220,11 +217,7 @@ export const POST = withMcpAuth('write')(
|
||||
return createMcpSuccessResponse({ serverId }, 201)
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error registering MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to register MCP server'),
|
||||
'Failed to register MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to register MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -297,11 +290,7 @@ export const DELETE = withMcpAuth('admin')(
|
||||
return createMcpSuccessResponse({ message: `Server ${serverId} deleted successfully` })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error deleting MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to delete MCP server'),
|
||||
'Failed to delete MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to delete MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { McpClient } from '@/lib/mcp/client'
|
||||
import {
|
||||
McpDnsResolutionError,
|
||||
@@ -220,11 +221,7 @@ export const POST = withMcpAuth('write')(
|
||||
return createMcpSuccessResponse(result, result.success ? 200 : 400)
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error testing MCP server connection:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to test server connection'),
|
||||
'Failed to test server connection',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to test server connection', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ import { workflow, workflowBlocks } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { withMcpAuth } from '@/lib/mcp/middleware'
|
||||
import type { McpToolSchema, StoredMcpTool } from '@/lib/mcp/types'
|
||||
import { createMcpErrorResponse, createMcpSuccessResponse } from '@/lib/mcp/utils'
|
||||
@@ -70,11 +71,7 @@ export const GET = withMcpAuth('read')(
|
||||
return createMcpSuccessResponse({ tools: storedTools })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error fetching stored MCP tools:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to fetch stored MCP tools'),
|
||||
'Failed to fetch stored MCP tools',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to fetch stored MCP tools', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getParsedBody, withMcpAuth } from '@/lib/mcp/middleware'
|
||||
import { mcpPubSub } from '@/lib/mcp/pubsub'
|
||||
import { createMcpErrorResponse, createMcpSuccessResponse } from '@/lib/mcp/utils'
|
||||
@@ -63,11 +64,7 @@ export const GET = withMcpAuth<RouteParams>('read')(
|
||||
return createMcpSuccessResponse({ server, tools })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error getting workflow MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to get workflow MCP server'),
|
||||
'Failed to get workflow MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to get workflow MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -146,11 +143,7 @@ export const PATCH = withMcpAuth<RouteParams>('write')(
|
||||
return createMcpSuccessResponse({ server: updatedServer })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error updating workflow MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to update workflow MCP server'),
|
||||
'Failed to update workflow MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to update workflow MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -201,11 +194,7 @@ export const DELETE = withMcpAuth<RouteParams>('admin')(
|
||||
return createMcpSuccessResponse({ message: `Server ${serverId} deleted successfully` })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error deleting workflow MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to delete workflow MCP server'),
|
||||
'Failed to delete workflow MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to delete workflow MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getParsedBody, withMcpAuth } from '@/lib/mcp/middleware'
|
||||
import { mcpPubSub } from '@/lib/mcp/pubsub'
|
||||
import { createMcpErrorResponse, createMcpSuccessResponse } from '@/lib/mcp/utils'
|
||||
@@ -63,11 +64,7 @@ export const GET = withMcpAuth<RouteParams>('read')(
|
||||
return createMcpSuccessResponse({ tool })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error getting tool:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to get tool'),
|
||||
'Failed to get tool',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to get tool', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -164,11 +161,7 @@ export const PATCH = withMcpAuth<RouteParams>('write')(
|
||||
return createMcpSuccessResponse({ tool: updatedTool })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error updating tool:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to update tool'),
|
||||
'Failed to update tool',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to update tool', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -232,11 +225,7 @@ export const DELETE = withMcpAuth<RouteParams>('write')(
|
||||
return createMcpSuccessResponse({ message: `Tool ${toolId} deleted successfully` })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error deleting tool:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to delete tool'),
|
||||
'Failed to delete tool',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to delete tool', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { getParsedBody, withMcpAuth } from '@/lib/mcp/middleware'
|
||||
import { mcpPubSub } from '@/lib/mcp/pubsub'
|
||||
@@ -72,11 +73,7 @@ export const GET = withMcpAuth<RouteParams>('read')(
|
||||
return createMcpSuccessResponse({ tools })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error listing tools:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to list tools'),
|
||||
'Failed to list tools',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to list tools', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -237,11 +234,7 @@ export const POST = withMcpAuth<RouteParams>('write')(
|
||||
return createMcpSuccessResponse({ tool }, 201)
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error adding tool:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to add tool'),
|
||||
'Failed to add tool',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to add tool', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq, inArray, isNull, sql } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { getParsedBody, withMcpAuth } from '@/lib/mcp/middleware'
|
||||
import { mcpPubSub } from '@/lib/mcp/pubsub'
|
||||
@@ -82,11 +83,7 @@ export const GET = withMcpAuth('read')(
|
||||
return createMcpSuccessResponse({ servers: serversWithToolNames })
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error listing workflow MCP servers:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to list workflow MCP servers'),
|
||||
'Failed to list workflow MCP servers',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to list workflow MCP servers', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -221,11 +218,7 @@ export const POST = withMcpAuth('write')(
|
||||
return createMcpSuccessResponse({ server, addedTools }, 201)
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error creating workflow MCP server:`, error)
|
||||
return createMcpErrorResponse(
|
||||
error instanceof Error ? error : new Error('Failed to create workflow MCP server'),
|
||||
'Failed to create workflow MCP server',
|
||||
500
|
||||
)
|
||||
return createMcpErrorResponse(toError(error), 'Failed to create workflow MCP server', 500)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ import { readEvents } from '@/lib/copilot/request/session/buffer'
|
||||
import { readFilePreviewSessions } from '@/lib/copilot/request/session/file-preview-session'
|
||||
import { type StreamBatchEvent, toStreamBatchEvent } from '@/lib/copilot/request/session/types'
|
||||
import { taskPubSub } from '@/lib/copilot/tasks'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { captureServerEvent } from '@/lib/posthog/server'
|
||||
|
||||
const logger = createLogger('MothershipChatAPI')
|
||||
@@ -66,7 +67,7 @@ export async function GET(
|
||||
logger.warn('Failed to read preview sessions for mothership chat', {
|
||||
chatId,
|
||||
conversationId: chat.conversationId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return []
|
||||
}),
|
||||
@@ -75,7 +76,7 @@ export async function GET(
|
||||
logger.warn('Failed to fetch latest run for mothership chat snapshot', {
|
||||
chatId,
|
||||
conversationId: chat.conversationId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return null
|
||||
})
|
||||
@@ -90,7 +91,7 @@ export async function GET(
|
||||
logger.warn('Failed to read stream snapshot for mothership chat', {
|
||||
chatId,
|
||||
conversationId: chat.conversationId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { buildIntegrationToolSchemas } from '@/lib/copilot/chat/payload'
|
||||
import { generateWorkspaceContext } from '@/lib/copilot/chat/workspace-context'
|
||||
import { runHeadlessCopilotLifecycle } from '@/lib/copilot/request/lifecycle/headless'
|
||||
import { requestExplicitStreamAbort } from '@/lib/copilot/request/session/explicit-abort'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import {
|
||||
assertActiveWorkspaceAccess,
|
||||
@@ -110,7 +111,7 @@ export async function POST(req: NextRequest) {
|
||||
chatId: effectiveChatId,
|
||||
}).catch((error) => {
|
||||
reqLogger.warn('Failed to send explicit abort for mothership execution', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { checkWorkspaceAccess } from '@/lib/workspaces/permissions/utils'
|
||||
import {
|
||||
@@ -112,7 +113,7 @@ export async function POST(request: NextRequest) {
|
||||
logger.error(`[${requestId}] Failed to resolve Vertex credential:`, {
|
||||
provider,
|
||||
model,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
hasVertexCredential: !!vertexCredential,
|
||||
})
|
||||
return NextResponse.json(
|
||||
@@ -258,17 +259,14 @@ export async function POST(request: NextRequest) {
|
||||
} catch (error) {
|
||||
const executionTime = Date.now() - startTime
|
||||
logger.error(`[${requestId}] Provider request failed:`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
errorName: error instanceof Error ? error.name : 'Unknown',
|
||||
errorStack: error instanceof Error ? error.stack : undefined,
|
||||
executionTime,
|
||||
timestamp: new Date().toISOString(),
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
{ error: error instanceof Error ? error.message : String(error) },
|
||||
{ status: 500 }
|
||||
)
|
||||
return NextResponse.json({ error: toError(error).message }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { AuthType } from '@/lib/auth/hybrid'
|
||||
import { getJobQueue } from '@/lib/core/async-jobs'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { SSE_HEADERS } from '@/lib/core/utils/sse'
|
||||
import { getBaseUrl } from '@/lib/core/utils/urls'
|
||||
@@ -235,7 +236,7 @@ export async function POST(
|
||||
})
|
||||
} catch (dispatchError) {
|
||||
logger.error('Failed to dispatch async resume execution', {
|
||||
error: dispatchError instanceof Error ? dispatchError.message : String(dispatchError),
|
||||
error: toError(dispatchError).message,
|
||||
resumeExecutionId: enqueueResult.resumeExecutionId,
|
||||
})
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -4,6 +4,7 @@ import { and, eq, isNull, lt, lte, ne, not, or, sql } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { verifyCronAuth } from '@/lib/auth/internal'
|
||||
import { getJobQueue, shouldExecuteInline } from '@/lib/core/async-jobs'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import {
|
||||
@@ -136,7 +137,7 @@ export async function GET(request: NextRequest) {
|
||||
const output = await executeScheduleJob(payload)
|
||||
await jobQueue.completeJob(jobId, output)
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
logger.error(
|
||||
`[${requestId}] Schedule execution failed for workflow ${schedule.workflowId}`,
|
||||
{
|
||||
@@ -191,7 +192,7 @@ export async function GET(request: NextRequest) {
|
||||
await executeJobInline(payload)
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Job execution failed for ${job.id}`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
await releaseScheduleLock(
|
||||
job.id,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import {
|
||||
@@ -163,7 +164,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
inserted += result.length
|
||||
}
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
const message = toError(err).message
|
||||
logger.warn(`[${requestId}] Append failed mid-import for table ${tableId}`, {
|
||||
inserted,
|
||||
total: coerced.length,
|
||||
@@ -238,7 +239,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
const message = toError(err).message
|
||||
const isClientError =
|
||||
message.includes('row limit') ||
|
||||
message.includes('Schema validation') ||
|
||||
@@ -251,7 +252,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
throw err
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
const message = toError(error).message
|
||||
logger.error(`[${requestId}] CSV import into existing table failed:`, error)
|
||||
|
||||
const isClientError =
|
||||
|
||||
@@ -5,6 +5,7 @@ import { and, eq } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import type { RowData } from '@/lib/table'
|
||||
import { deleteRow, updateRow } from '@/lib/table'
|
||||
@@ -193,7 +194,7 @@ export async function PATCH(request: NextRequest, { params }: RowRouteParams) {
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (errorMessage === 'Row not found') {
|
||||
return NextResponse.json({ error: errorMessage }, { status: 404 })
|
||||
@@ -260,7 +261,7 @@ export async function DELETE(request: NextRequest, { params }: RowRouteParams) {
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (errorMessage === 'Row not found') {
|
||||
return NextResponse.json({ error: errorMessage }, { status: 404 })
|
||||
|
||||
@@ -5,6 +5,7 @@ import { and, eq, sql } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import type { Filter, RowData, Sort, TableSchema } from '@/lib/table'
|
||||
import {
|
||||
@@ -181,7 +182,7 @@ async function handleBatchInsert(
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('row limit') ||
|
||||
@@ -289,7 +290,7 @@ export async function POST(request: NextRequest, { params }: TableRowsRouteParam
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('row limit') ||
|
||||
@@ -516,7 +517,7 @@ export async function PUT(request: NextRequest, { params }: TableRowsRouteParams
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('Row size exceeds') ||
|
||||
@@ -616,7 +617,7 @@ export async function DELETE(request: NextRequest, { params }: TableRowsRoutePar
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (errorMessage.includes('Filter is required')) {
|
||||
return NextResponse.json({ error: errorMessage }, { status: 400 })
|
||||
@@ -685,7 +686,7 @@ export async function PATCH(request: NextRequest, { params }: TableRowsRoutePara
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('Row size exceeds') ||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import type { RowData } from '@/lib/table'
|
||||
import { upsertRow } from '@/lib/table'
|
||||
@@ -87,7 +88,7 @@ export async function POST(request: NextRequest, { params }: UpsertRouteParams)
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
// Service layer throws descriptive errors for validation/capacity issues
|
||||
if (
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import {
|
||||
@@ -124,7 +125,7 @@ export async function POST(request: NextRequest) {
|
||||
throw insertError
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
const message = toError(error).message
|
||||
logger.error(`[${requestId}] CSV import failed:`, error)
|
||||
|
||||
const isClientError =
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalApiKey } from '@/lib/copilot/request/http'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { sanitizeForCopilot } from '@/lib/workflows/sanitization/json-sanitizer'
|
||||
|
||||
@@ -97,7 +98,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error sanitizing template ${template.id}`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return null
|
||||
}
|
||||
@@ -112,7 +113,7 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json(response)
|
||||
} catch (error) {
|
||||
logger.error(`[${requestId}] Error fetching approved sanitized templates`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -5,6 +5,7 @@ import { z } from 'zod'
|
||||
import { createA2AClient, extractTextContent, isTerminalState } from '@/lib/a2a/utils'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateUrlWithDNS } from '@/lib/core/security/input-validation.server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
|
||||
@@ -89,7 +90,7 @@ export async function POST(request: NextRequest) {
|
||||
parts.push(dataPart)
|
||||
} catch (parseError) {
|
||||
logger.warn(`[${requestId}] Failed to parse data as JSON, skipping DataPart`, {
|
||||
error: parseError instanceof Error ? parseError.message : String(parseError),
|
||||
error: toError(parseError).message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,17 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateUrlWithDNS } from '@/lib/core/security/input-validation.server'
|
||||
import { secureFetchWithPinnedIP } from '@/lib/core/security/input-validation.server'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { FileInputSchema, type RawFileInput } from '@/lib/uploads/utils/file-schemas'
|
||||
import { processFilesToUserFiles } from '@/lib/uploads/utils/file-utils'
|
||||
import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
|
||||
import { agiloftLogin, agiloftLogout, buildAttachFileUrl } from '@/tools/agiloft/utils'
|
||||
import {
|
||||
agiloftLogin,
|
||||
agiloftLogout,
|
||||
buildAttachFileUrl,
|
||||
validateInstanceUrl,
|
||||
} from '@/tools/agiloft/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
@@ -60,18 +65,20 @@ export async function POST(request: NextRequest) {
|
||||
const fileBuffer = await downloadFileFromStorage(userFile, requestId, logger)
|
||||
const resolvedFileName = data.fileName || userFile.name || 'attachment'
|
||||
|
||||
const urlValidation = await validateUrlWithDNS(data.instanceUrl, 'instanceUrl')
|
||||
if (!urlValidation.isValid) {
|
||||
let resolvedIP: string
|
||||
try {
|
||||
resolvedIP = await validateInstanceUrl(data.instanceUrl)
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] SSRF attempt blocked for Agiloft instance URL`, {
|
||||
instanceUrl: data.instanceUrl,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{ success: false, error: urlValidation.error || 'Invalid instance URL' },
|
||||
{ success: false, error: error instanceof Error ? error.message : 'Invalid instance URL' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
const token = await agiloftLogin(data)
|
||||
const token = await agiloftLogin(data, resolvedIP)
|
||||
const base = data.instanceUrl.replace(/\/$/, '')
|
||||
|
||||
try {
|
||||
@@ -79,7 +86,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
logger.info(`[${requestId}] Uploading file to Agiloft: ${resolvedFileName}`)
|
||||
|
||||
const agiloftResponse = await fetch(url, {
|
||||
const agiloftResponse = await secureFetchWithPinnedIP(url, resolvedIP, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': userFile.type || 'application/octet-stream',
|
||||
@@ -123,7 +130,7 @@ export async function POST(request: NextRequest) {
|
||||
},
|
||||
})
|
||||
} finally {
|
||||
await agiloftLogout(data.instanceUrl, data.knowledgeBase, token)
|
||||
await agiloftLogout(data.instanceUrl, data.knowledgeBase, token, resolvedIP)
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof z.ZodError) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
@@ -115,7 +116,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error('Error creating Asana task:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
@@ -114,7 +115,7 @@ export async function PUT(request: NextRequest) {
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error('Error updating Asana task:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
type ResultField,
|
||||
} from '@aws-sdk/client-cloudwatch-logs'
|
||||
import { DEFAULT_EXECUTION_TIMEOUT_MS } from '@/lib/core/execution-limits'
|
||||
import { sleep } from '@/lib/core/utils/helpers'
|
||||
|
||||
interface AwsCredentials {
|
||||
region: string
|
||||
@@ -79,7 +80,7 @@ export async function pollQueryResults(
|
||||
throw new Error(`CloudWatch Log Insights query ${status.toLowerCase()}`)
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs))
|
||||
await sleep(pollIntervalMs)
|
||||
}
|
||||
|
||||
// Timeout -- fetch one last time for partial results
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
secureFetchWithPinnedIP,
|
||||
validateUrlWithDNS,
|
||||
} from '@/lib/core/security/input-validation.server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
|
||||
const logger = createLogger('ImageProxyAPI')
|
||||
@@ -83,7 +84,7 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
logger.error(`[${requestId}] Image proxy error:`, { error: errorMessage })
|
||||
|
||||
return new NextResponse(`Failed to proxy image: ${errorMessage}`, {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage, toAdf } from '@/tools/jira/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
@@ -182,7 +183,7 @@ export async function PUT(request: NextRequest) {
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error('Error updating Jira issue:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage, toAdf } from '@/tools/jira/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
@@ -225,7 +226,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error('Error creating Jira issue:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
validateJiraCloudId,
|
||||
validateJiraIssueKey,
|
||||
} from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -199,7 +200,7 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
|
||||
} catch (error) {
|
||||
logger.error('Error in approvals operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -112,7 +113,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error adding comment:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -105,7 +106,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching comments:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -157,7 +158,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error with customers operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -96,7 +97,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error getting form answers:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -104,7 +105,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error attaching form:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -111,7 +112,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error copying forms:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -96,7 +97,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error deleting form:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -97,7 +98,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error externalising form:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -98,7 +99,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error getting form:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -97,7 +98,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error internalising form:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -96,7 +97,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching issue forms:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -97,7 +98,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error reopening form:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -103,7 +104,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error saving form answers:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -98,7 +99,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching form structure:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -97,7 +98,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error submitting form:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmFormsApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -96,7 +97,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching form templates:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
validateEnum,
|
||||
validateJiraCloudId,
|
||||
} from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -169,7 +170,7 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
|
||||
} catch (error) {
|
||||
logger.error('Error in organization operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -91,7 +92,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching organizations:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
validateJiraCloudId,
|
||||
validateJiraIssueKey,
|
||||
} from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -174,7 +175,7 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
|
||||
} catch (error) {
|
||||
logger.error('Error in participants operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -100,7 +101,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching queues:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
validateJiraCloudId,
|
||||
validateJiraIssueKey,
|
||||
} from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -250,7 +251,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error with request operation:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
validateEnum,
|
||||
validateJiraCloudId,
|
||||
} from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -140,7 +141,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching requests:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -108,7 +109,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching request type fields:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAlphanumericId, validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -104,7 +105,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching request types:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -82,7 +83,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching service desks:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -92,7 +93,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching SLA info:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
validateJiraCloudId,
|
||||
validateJiraIssueKey,
|
||||
} from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -116,7 +117,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error transitioning request:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getJiraCloudId, parseAtlassianErrorMessage } from '@/tools/jira/utils'
|
||||
import { getJsmApiBaseUrl, getJsmHeaders } from '@/tools/jsm/utils'
|
||||
|
||||
@@ -92,7 +93,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error fetching transitions:', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
|
||||
import { validateMicrosoftGraphId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
@@ -99,7 +100,7 @@ export async function POST(request: Request) {
|
||||
} catch (innerError) {
|
||||
logger.error('Error during API requests:', innerError)
|
||||
|
||||
const errorMessage = innerError instanceof Error ? innerError.message : String(innerError)
|
||||
const errorMessage = toError(innerError).message
|
||||
if (
|
||||
errorMessage.includes('auth') ||
|
||||
errorMessage.includes('token') ||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
|
||||
import { validateMicrosoftGraphId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
@@ -110,15 +111,13 @@ const getChatDisplayName = async (
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`Failed to get better name from messages for chat ${chatId}: ${error instanceof Error ? error.message : String(error)}`
|
||||
`Failed to get better name from messages for chat ${chatId}: ${toError(error).message}`
|
||||
)
|
||||
}
|
||||
|
||||
return `Chat ${chatId.split(':')[0] || chatId.substring(0, 8)}...`
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`Failed to get display name for chat ${chatId}: ${error instanceof Error ? error.message : String(error)}`
|
||||
)
|
||||
logger.warn(`Failed to get display name for chat ${chatId}: ${toError(error).message}`)
|
||||
return `Chat ${chatId.split(':')[0] || chatId.substring(0, 8)}...`
|
||||
}
|
||||
}
|
||||
@@ -200,7 +199,7 @@ export async function POST(request: Request) {
|
||||
} catch (innerError) {
|
||||
logger.error('Error during API requests:', innerError)
|
||||
|
||||
const errorMessage = innerError instanceof Error ? innerError.message : String(innerError)
|
||||
const errorMessage = toError(innerError).message
|
||||
if (
|
||||
errorMessage.includes('auth') ||
|
||||
errorMessage.includes('token') ||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { authorizeCredentialUse } from '@/lib/auth/credential-access'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { refreshAccessTokenIfNeeded } from '@/app/api/auth/oauth/utils'
|
||||
|
||||
@@ -89,7 +90,7 @@ export async function POST(request: Request) {
|
||||
logger.error('Error during API requests:', innerError)
|
||||
|
||||
// Check if it's an authentication error
|
||||
const errorMessage = innerError instanceof Error ? innerError.message : String(innerError)
|
||||
const errorMessage = toError(innerError).message
|
||||
if (
|
||||
errorMessage.includes('auth') ||
|
||||
errorMessage.includes('token') ||
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {
|
||||
import { createLogger } from '@sim/logger'
|
||||
import * as ipaddr from 'ipaddr.js'
|
||||
import { secureFetchWithPinnedIP } from '@/lib/core/security/input-validation.server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
/** Connect-format field type strings returned by normalization. */
|
||||
type ConnectFieldType =
|
||||
@@ -283,7 +284,7 @@ async function validateConnectServerUrl(serverUrl: string): Promise<string> {
|
||||
if (error instanceof Error && error.message.startsWith('1Password')) throw error
|
||||
connectLogger.warn('DNS lookup failed for 1Password Connect server URL', {
|
||||
hostname: clean,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
throw new Error('1Password server URL hostname could not be resolved')
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { eq } from 'drizzle-orm'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { validateAlphanumericId } from '@/lib/core/security/input-validation'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { refreshAccessTokenIfNeeded, resolveOAuthAccountId } from '@/app/api/auth/oauth/utils'
|
||||
|
||||
@@ -135,7 +136,7 @@ export async function GET(request: Request) {
|
||||
} catch (innerError) {
|
||||
logger.error('Error during API requests:', innerError)
|
||||
|
||||
const errorMessage = innerError instanceof Error ? innerError.message : String(innerError)
|
||||
const errorMessage = toError(innerError).message
|
||||
if (
|
||||
errorMessage.includes('auth') ||
|
||||
errorMessage.includes('token') ||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type Attributes, Client, type ConnectConfig, type SFTPWrapper } from 'ssh2'
|
||||
import { validateDatabaseHost } from '@/lib/core/security/input-validation.server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const S_IFMT = 0o170000
|
||||
const S_IFDIR = 0o040000
|
||||
@@ -151,7 +152,7 @@ export async function createSftpConnection(config: SftpConnectionConfig): Promis
|
||||
try {
|
||||
client.connect(connectConfig)
|
||||
} catch (err) {
|
||||
reject(formatSftpError(err instanceof Error ? err : new Error(String(err)), { host, port }))
|
||||
reject(formatSftpError(toError(err), { host, port }))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import nodemailer from 'nodemailer'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateDatabaseHost } from '@/lib/core/security/input-validation.server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { RawFileInputArraySchema } from '@/lib/uploads/utils/file-schemas'
|
||||
import { processFilesToUserFiles } from '@/lib/uploads/utils/file-utils'
|
||||
@@ -223,7 +224,7 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
logger.error(`[${requestId}] Error sending email via SMTP:`, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
code: isNodeError(error) ? error.code : undefined,
|
||||
responseCode: hasResponseCode(error) ? error.responseCode : undefined,
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type Attributes, Client, type ConnectConfig } from 'ssh2'
|
||||
import { validateDatabaseHost } from '@/lib/core/security/input-validation.server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('SSHUtils')
|
||||
|
||||
@@ -168,7 +169,7 @@ export async function createSSHConnection(config: SSHConnectionConfig): Promise<
|
||||
try {
|
||||
client.connect(connectConfig)
|
||||
} catch (err) {
|
||||
reject(formatSSHError(err instanceof Error ? err : new Error(String(err)), { host, port }))
|
||||
reject(formatSSHError(toError(err), { host, port }))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
secureFetchWithPinnedIP,
|
||||
validateUrlWithDNS,
|
||||
} from '@/lib/core/security/input-validation.server'
|
||||
import { sleep } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { getMimeTypeFromExtension, isInternalFileUrl } from '@/lib/uploads/utils/file-utils'
|
||||
import {
|
||||
@@ -663,7 +664,7 @@ async function transcribeWithAssemblyAI(
|
||||
throw new Error(`AssemblyAI transcription failed: ${transcript.error}`)
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000))
|
||||
await sleep(5000)
|
||||
attempts++
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateSupabaseProjectId } from '@/lib/core/security/input-validation'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { FileInputSchema } from '@/lib/uploads/utils/file-schemas'
|
||||
import { processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils'
|
||||
@@ -12,7 +13,10 @@ export const dynamic = 'force-dynamic'
|
||||
const logger = createLogger('SupabaseStorageUploadAPI')
|
||||
|
||||
const SupabaseStorageUploadSchema = z.object({
|
||||
projectId: z.string().min(1, 'Project ID is required'),
|
||||
projectId: z
|
||||
.string()
|
||||
.min(1, 'Project ID is required')
|
||||
.regex(/^[a-z0-9]+$/, 'Project ID must contain only lowercase alphanumeric characters'),
|
||||
apiKey: z.string().min(1, 'API key is required'),
|
||||
bucket: z.string().min(1, 'Bucket name is required'),
|
||||
fileName: z.string().min(1, 'File name is required'),
|
||||
@@ -162,7 +166,12 @@ export async function POST(request: NextRequest) {
|
||||
fullPath = `${folderPath}${validatedData.fileName}`
|
||||
}
|
||||
|
||||
const supabaseUrl = `https://${validatedData.projectId}.supabase.co/storage/v1/object/${validatedData.bucket}/${fullPath}`
|
||||
const projectValidation = validateSupabaseProjectId(validatedData.projectId)
|
||||
if (!projectValidation.isValid) {
|
||||
return NextResponse.json({ success: false, error: projectValidation.error }, { status: 400 })
|
||||
}
|
||||
|
||||
const supabaseUrl = `https://${projectValidation.sanitized}.supabase.co/storage/v1/object/${validatedData.bucket}/${fullPath}`
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
apikey: validatedData.apiKey,
|
||||
@@ -218,7 +227,7 @@ export async function POST(request: NextRequest) {
|
||||
path: fullPath,
|
||||
})
|
||||
|
||||
const publicUrl = `https://${validatedData.projectId}.supabase.co/storage/v1/object/public/${validatedData.bucket}/${fullPath}`
|
||||
const publicUrl = `https://${projectValidation.sanitized}.supabase.co/storage/v1/object/public/${validatedData.bucket}/${fullPath}`
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
secureFetchWithPinnedIP,
|
||||
validateUrlWithDNS,
|
||||
} from '@/lib/core/security/input-validation.server'
|
||||
import { sleep } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { RawFileInputSchema } from '@/lib/uploads/utils/file-schemas'
|
||||
import { isInternalFileUrl, processSingleFileToUserFile } from '@/lib/uploads/utils/file-utils'
|
||||
@@ -169,10 +170,6 @@ function parseS3Uri(s3Uri: string): { bucket: string; key: string } {
|
||||
return { bucket, key }
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
async function callTextractAsync(
|
||||
host: string,
|
||||
amzTarget: string,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { getMaxExecutionTimeout } from '@/lib/core/execution-limits'
|
||||
import { sleep } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { downloadFileFromStorage } from '@/lib/uploads/utils/file-utils.server'
|
||||
import type { UserFile } from '@/executor/types'
|
||||
@@ -974,7 +975,3 @@ function getVideoDimensions(
|
||||
|
||||
return { width, height }
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { hasPaidSubscription } from '@/lib/billing'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('SubscriptionTransferAPI')
|
||||
|
||||
@@ -114,7 +115,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error transferring subscription', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return NextResponse.json({ error: 'Failed to transfer subscription' }, { status: 500 })
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { z } from 'zod'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { getUserUsageLogs, type UsageLogSource } from '@/lib/billing/core/usage-log'
|
||||
import { dollarsToCredits } from '@/lib/billing/credits/conversion'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('UsageLogsAPI')
|
||||
|
||||
@@ -109,7 +110,7 @@ export async function GET(req: NextRequest) {
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Failed to get usage logs', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
|
||||
return NextResponse.json(
|
||||
|
||||
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { COPILOT_REQUEST_MODES } from '@/lib/copilot/constants'
|
||||
import { runHeadlessCopilotLifecycle } from '@/lib/copilot/request/lifecycle/headless'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { getWorkflowById, resolveWorkflowIdForUser } from '@/lib/workflows/utils'
|
||||
import { authenticateV1Request } from '@/app/api/v1/auth'
|
||||
@@ -136,7 +137,7 @@ export async function POST(req: NextRequest) {
|
||||
? `Headless copilot request failed [messageId:${messageId}]`
|
||||
: 'Headless copilot request failed',
|
||||
{
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
}
|
||||
)
|
||||
return NextResponse.json({ success: false, error: 'Internal server error' }, { status: 500 })
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import type { RowData } from '@/lib/table'
|
||||
import { updateRow } from '@/lib/table'
|
||||
@@ -196,7 +197,7 @@ export async function PATCH(request: NextRequest, { params }: RowRouteParams) {
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (errorMessage === 'Row not found') {
|
||||
return NextResponse.json({ error: errorMessage }, { status: 404 })
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { and, eq, sql } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import type { Filter, RowData, Sort, TableSchema } from '@/lib/table'
|
||||
import {
|
||||
@@ -162,7 +163,7 @@ async function handleBatchInsert(
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('row limit') ||
|
||||
@@ -392,7 +393,7 @@ export async function POST(request: NextRequest, { params }: TableRowsRouteParam
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('row limit') ||
|
||||
@@ -489,7 +490,7 @@ export async function PUT(request: NextRequest, { params }: TableRowsRouteParams
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('Row size exceeds') ||
|
||||
@@ -591,7 +592,7 @@ export async function DELETE(request: NextRequest, { params }: TableRowsRoutePar
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (errorMessage.includes('Filter is required')) {
|
||||
return NextResponse.json({ error: errorMessage }, { status: 400 })
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import type { RowData } from '@/lib/table'
|
||||
import { upsertRow } from '@/lib/table'
|
||||
@@ -99,7 +100,7 @@ export async function POST(request: NextRequest, { params }: UpsertRouteParams)
|
||||
)
|
||||
}
|
||||
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
|
||||
if (
|
||||
errorMessage.includes('unique column') ||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getTimeoutErrorMessage,
|
||||
isTimeoutError,
|
||||
} from '@/lib/core/execution-limits'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { SSE_HEADERS } from '@/lib/core/utils/sse'
|
||||
import { getBaseUrl } from '@/lib/core/utils/urls'
|
||||
@@ -218,7 +219,7 @@ async function handleAsyncExecution(params: AsyncExecutionParams): Promise<NextR
|
||||
const output = await executeWorkflowJob(payload)
|
||||
await jobQueue.completeJob(jobId, output)
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
const errorMessage = toError(error).message
|
||||
asyncLogger.error('Async workflow execution failed', {
|
||||
jobId,
|
||||
error: errorMessage,
|
||||
@@ -228,10 +229,7 @@ async function handleAsyncExecution(params: AsyncExecutionParams): Promise<NextR
|
||||
} catch (markFailedError) {
|
||||
asyncLogger.error('Failed to mark job as failed', {
|
||||
jobId,
|
||||
error:
|
||||
markFailedError instanceof Error
|
||||
? markFailedError.message
|
||||
: String(markFailedError),
|
||||
error: toError(markFailedError).message,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1294,7 +1292,7 @@ async function handleExecutePost(
|
||||
await eventWriter.close()
|
||||
} catch (closeError) {
|
||||
reqLogger.warn('Failed to close event writer', {
|
||||
error: closeError instanceof Error ? closeError.message : String(closeError),
|
||||
error: toError(closeError).message,
|
||||
})
|
||||
}
|
||||
if (finalMetaStatus) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { sleep, toError } from '@/lib/core/utils/helpers'
|
||||
import { SSE_HEADERS } from '@/lib/core/utils/sse'
|
||||
import {
|
||||
type ExecutionStreamStatus,
|
||||
@@ -101,7 +102,7 @@ export async function GET(
|
||||
}
|
||||
|
||||
while (!closed && Date.now() < pollDeadline) {
|
||||
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
|
||||
await sleep(POLL_INTERVAL_MS)
|
||||
if (closed) return
|
||||
|
||||
const newEvents = await readExecutionEvents(executionId, lastEventId)
|
||||
@@ -135,7 +136,7 @@ export async function GET(
|
||||
} catch (error) {
|
||||
logger.error('Error in reconnection stream', {
|
||||
executionId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
if (!closed) {
|
||||
try {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { getSocketServerUrl } from '@/lib/core/utils/urls'
|
||||
import { extractAndPersistCustomTools } from '@/lib/workflows/persistence/custom-tools-persistence'
|
||||
@@ -150,7 +151,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch workflow state', {
|
||||
workflowId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { decryptSecret } from '@/lib/core/security/encryption'
|
||||
import { secureFetchWithValidation } from '@/lib/core/security/input-validation.server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
import { getBaseUrl } from '@/lib/core/utils/urls'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { sendEmail } from '@/lib/messaging/email/mailer'
|
||||
@@ -159,7 +160,7 @@ async function testWebhook(subscription: typeof workspaceNotificationSubscriptio
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
logger.warn('Webhook test failed', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return { success: false, error: 'Failed to deliver webhook' }
|
||||
}
|
||||
@@ -273,7 +274,7 @@ async function testSlack(
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
logger.warn('Slack test notification failed', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return { success: false, error: 'Failed to send Slack notification' }
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { createLogger } from '@sim/logger'
|
||||
import { ArrowDown, Download, Loader2, Music } from 'lucide-react'
|
||||
import { Button } from '@/components/emcn'
|
||||
import { DefaultFileIcon, getDocumentIcon } from '@/components/icons/document-icons'
|
||||
import { sleep } from '@/lib/core/utils/helpers'
|
||||
import type { ChatFile } from '@/app/chat/components/message/message'
|
||||
|
||||
const logger = createLogger('ChatFileDownload')
|
||||
@@ -157,7 +158,7 @@ export function ChatFileDownloadAll({ files }: ChatFileDownloadAllProps) {
|
||||
logger.info(`Downloaded file ${i + 1}/${files.length}: ${file.name}`)
|
||||
|
||||
if (i < files.length - 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 150))
|
||||
await sleep(150)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Failed to download file ${file.name}:`, error)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { toError } from '@/lib/core/utils/helpers'
|
||||
|
||||
const logger = createLogger('PostHogProxy')
|
||||
|
||||
@@ -59,7 +60,7 @@ async function handler(request: NextRequest) {
|
||||
logger.error('PostHog proxy error', {
|
||||
url,
|
||||
method: request.method,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return new NextResponse(null, { status: 502 })
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ import {
|
||||
reportManualRunToolStop,
|
||||
} from '@/lib/copilot/tools/client/run-tool-execution'
|
||||
import { isWorkflowToolName } from '@/lib/copilot/tools/workflow-tools'
|
||||
import { sleep, toError } from '@/lib/core/utils/helpers'
|
||||
import { generateId } from '@/lib/core/utils/uuid'
|
||||
import { getNextWorkflowColor } from '@/lib/workflows/colors'
|
||||
import { getQueryClient } from '@/app/_shell/providers/get-query-client'
|
||||
@@ -2512,7 +2513,7 @@ export function useChat(
|
||||
} catch (error) {
|
||||
logger.warn('Failed to load chat history while recovering stream', {
|
||||
chatId,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: toError(error).message,
|
||||
})
|
||||
return null
|
||||
}
|
||||
@@ -2746,7 +2747,7 @@ export function useChat(
|
||||
if (isStaleReconnect()) return true
|
||||
|
||||
setTransportReconnecting()
|
||||
await new Promise((resolve) => setTimeout(resolve, delayMs))
|
||||
await sleep(delayMs)
|
||||
if (streamGenRef.current !== gen) {
|
||||
if (!sendingRef.current) {
|
||||
setTransportIdle()
|
||||
@@ -2816,7 +2817,7 @@ export function useChat(
|
||||
logger.warn('Reconnect attempt failed', {
|
||||
streamId,
|
||||
attempt: attempt + 1,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: toError(err).message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useState } from 'react'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { sleep } from '@/lib/core/utils/helpers'
|
||||
import { getFileExtension, getMimeTypeFromExtension } from '@/lib/uploads/utils/file-utils'
|
||||
import { knowledgeKeys } from '@/hooks/queries/kb/knowledge'
|
||||
|
||||
@@ -111,11 +112,6 @@ const calculateUploadTimeoutMs = (fileSize: number) => {
|
||||
return Math.min(dynamicBudget, UPLOAD_CONFIG.MAX_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays execution for the specified duration
|
||||
*/
|
||||
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
||||
|
||||
/**
|
||||
* Gets high resolution timestamp for performance measurements
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user