Skip to content

Commit cc33742

Browse files
committed
feat(internal): added internal api base url for internal calls
1 parent 022e84c commit cc33742

File tree

20 files changed

+82
-46
lines changed

20 files changed

+82
-46
lines changed

apps/sim/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ BETTER_AUTH_URL=http://localhost:3000
1313

1414
# NextJS (Required)
1515
NEXT_PUBLIC_APP_URL=http://localhost:3000
16+
# INTERNAL_API_BASE_URL=http://sim-app.default.svc.cluster.local:3000 # Optional: internal URL for server-side /api self-calls; defaults to NEXT_PUBLIC_APP_URL
1617

1718
# Security (Required)
1819
ENCRYPTION_KEY=your_encryption_key # Use `openssl rand -hex 32` to generate, used to encrypt environment variables

apps/sim/app/api/a2a/serve/[agentId]/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Artifact, Message, PushNotificationConfig, Task, TaskState } from '@a2a-js/sdk'
22
import { v4 as uuidv4 } from 'uuid'
33
import { generateInternalToken } from '@/lib/auth/internal'
4-
import { getBaseUrl } from '@/lib/core/utils/urls'
4+
import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
55

66
/** A2A v0.3 JSON-RPC method names */
77
export const A2A_METHODS = {
@@ -118,7 +118,7 @@ export interface ExecuteRequestResult {
118118
export async function buildExecuteRequest(
119119
config: ExecuteRequestConfig
120120
): Promise<ExecuteRequestResult> {
121-
const url = `${getBaseUrl()}/api/workflows/${config.workflowId}/execute`
121+
const url = `${getInternalApiBaseUrl()}/api/workflows/${config.workflowId}/execute`
122122
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
123123
let useInternalAuth = false
124124

apps/sim/app/api/copilot/checkpoints/revert/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
createRequestTracker,
1212
createUnauthorizedResponse,
1313
} from '@/lib/copilot/request-helpers'
14-
import { getBaseUrl } from '@/lib/core/utils/urls'
14+
import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
1515
import { authorizeWorkflowByWorkspacePermission } from '@/lib/workflows/utils'
1616
import { isUuidV4 } from '@/executor/constants'
1717

@@ -99,7 +99,7 @@ export async function POST(request: NextRequest) {
9999
}
100100

101101
const stateResponse = await fetch(
102-
`${getBaseUrl()}/api/workflows/${checkpoint.workflowId}/state`,
102+
`${getInternalApiBaseUrl()}/api/workflows/${checkpoint.workflowId}/state`,
103103
{
104104
method: 'PUT',
105105
headers: {

apps/sim/app/api/mcp/serve/[serverId]/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { type NextRequest, NextResponse } from 'next/server'
2222
import { type AuthResult, checkHybridAuth } from '@/lib/auth/hybrid'
2323
import { generateInternalToken } from '@/lib/auth/internal'
2424
import { getMaxExecutionTimeout } from '@/lib/core/execution-limits'
25-
import { getBaseUrl } from '@/lib/core/utils/urls'
25+
import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
2626
import { getUserEntityPermissions } from '@/lib/workspaces/permissions/utils'
2727

2828
const logger = createLogger('WorkflowMcpServeAPI')
@@ -285,7 +285,7 @@ async function handleToolsCall(
285285
)
286286
}
287287

288-
const executeUrl = `${getBaseUrl()}/api/workflows/${tool.workflowId}/execute`
288+
const executeUrl = `${getInternalApiBaseUrl()}/api/workflows/${tool.workflowId}/execute`
289289
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
290290

291291
if (publicServerOwnerId) {

apps/sim/app/api/templates/[id]/use/route.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { type NextRequest, NextResponse } from 'next/server'
66
import { v4 as uuidv4 } from 'uuid'
77
import { getSession } from '@/lib/auth'
88
import { generateRequestId } from '@/lib/core/utils/request'
9-
import { getBaseUrl } from '@/lib/core/utils/urls'
9+
import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
1010
import {
1111
type RegenerateStateInput,
1212
regenerateWorkflowStateIds,
@@ -115,15 +115,18 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
115115
// Step 3: Save the workflow state using the existing state endpoint (like imports do)
116116
// Ensure variables in state are remapped for the new workflow as well
117117
const workflowStateWithVariables = { ...workflowState, variables: remappedVariables }
118-
const stateResponse = await fetch(`${getBaseUrl()}/api/workflows/${newWorkflowId}/state`, {
119-
method: 'PUT',
120-
headers: {
121-
'Content-Type': 'application/json',
122-
// Forward the session cookie for authentication
123-
cookie: request.headers.get('cookie') || '',
124-
},
125-
body: JSON.stringify(workflowStateWithVariables),
126-
})
118+
const stateResponse = await fetch(
119+
`${getInternalApiBaseUrl()}/api/workflows/${newWorkflowId}/state`,
120+
{
121+
method: 'PUT',
122+
headers: {
123+
'Content-Type': 'application/json',
124+
// Forward the session cookie for authentication
125+
cookie: request.headers.get('cookie') || '',
126+
},
127+
body: JSON.stringify(workflowStateWithVariables),
128+
}
129+
)
127130

128131
if (!stateResponse.ok) {
129132
logger.error(`[${requestId}] Failed to save workflow state for template use`)

apps/sim/executor/handlers/router/router-handler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { db } from '@sim/db'
22
import { account } from '@sim/db/schema'
33
import { createLogger } from '@sim/logger'
44
import { eq } from 'drizzle-orm'
5-
import { getBaseUrl } from '@/lib/core/utils/urls'
5+
import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
66
import { refreshTokenIfNeeded } from '@/app/api/auth/oauth/utils'
77
import { generateRouterPrompt, generateRouterV2Prompt } from '@/blocks/blocks/router'
88
import type { BlockOutput } from '@/blocks/types'
@@ -79,7 +79,7 @@ export class RouterBlockHandler implements BlockHandler {
7979
const providerId = getProviderFromModel(routerConfig.model)
8080

8181
try {
82-
const url = new URL('/api/providers', getBaseUrl())
82+
const url = new URL('/api/providers', getInternalApiBaseUrl())
8383
if (ctx.userId) url.searchParams.set('userId', ctx.userId)
8484

8585
const messages = [{ role: 'user', content: routerConfig.prompt }]
@@ -209,7 +209,7 @@ export class RouterBlockHandler implements BlockHandler {
209209
const providerId = getProviderFromModel(routerConfig.model)
210210

211211
try {
212-
const url = new URL('/api/providers', getBaseUrl())
212+
const url = new URL('/api/providers', getInternalApiBaseUrl())
213213
if (ctx.userId) url.searchParams.set('userId', ctx.userId)
214214

215215
const messages = [{ role: 'user', content: routerConfig.context }]

apps/sim/executor/utils/http.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { generateInternalToken } from '@/lib/auth/internal'
2-
import { getBaseUrl } from '@/lib/core/utils/urls'
2+
import { getBaseUrl, getInternalApiBaseUrl } from '@/lib/core/utils/urls'
33
import { HTTP } from '@/executor/constants'
44

55
export async function buildAuthHeaders(): Promise<Record<string, string>> {
@@ -16,7 +16,8 @@ export async function buildAuthHeaders(): Promise<Record<string, string>> {
1616
}
1717

1818
export function buildAPIUrl(path: string, params?: Record<string, string>): URL {
19-
const url = new URL(path, getBaseUrl())
19+
const baseUrl = path.startsWith('/api/') ? getInternalApiBaseUrl() : getBaseUrl()
20+
const url = new URL(path, baseUrl)
2021

2122
if (params) {
2223
for (const [key, value] of Object.entries(params)) {

apps/sim/lib/core/config/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ export const env = createEnv({
220220
SOCKET_SERVER_URL: z.string().url().optional(), // WebSocket server URL for real-time features
221221
SOCKET_PORT: z.number().optional(), // Port for WebSocket server
222222
PORT: z.number().optional(), // Main application port
223+
INTERNAL_API_BASE_URL: z.string().optional(), // Optional internal base URL for server-side self-calls (e.g., cluster DNS)
223224
ALLOWED_ORIGINS: z.string().optional(), // CORS allowed origins
224225

225226
// OAuth Integration Credentials - All optional, enables third-party integrations

apps/sim/lib/core/utils/urls.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import { getEnv } from '@/lib/core/config/env'
22
import { isProd } from '@/lib/core/config/feature-flags'
33

4+
function normalizeBaseUrl(url: string): string {
5+
if (url.startsWith('http://') || url.startsWith('https://')) {
6+
return url
7+
}
8+
9+
const protocol = isProd ? 'https://' : 'http://'
10+
return `${protocol}${url}`
11+
}
12+
413
/**
514
* Returns the base URL of the application from NEXT_PUBLIC_APP_URL
615
* This ensures webhooks, callbacks, and other integrations always use the correct public URL
@@ -16,12 +25,20 @@ export function getBaseUrl(): string {
1625
)
1726
}
1827

19-
if (baseUrl.startsWith('http://') || baseUrl.startsWith('https://')) {
20-
return baseUrl
28+
return normalizeBaseUrl(baseUrl)
29+
}
30+
31+
/**
32+
* Returns the base URL used by server-side internal API calls.
33+
* Falls back to NEXT_PUBLIC_APP_URL when INTERNAL_API_BASE_URL is not set.
34+
*/
35+
export function getInternalApiBaseUrl(): string {
36+
const internalBaseUrl = getEnv('INTERNAL_API_BASE_URL')?.trim()
37+
if (!internalBaseUrl) {
38+
return getBaseUrl()
2139
}
2240

23-
const protocol = isProd ? 'https://' : 'http://'
24-
return `${protocol}${baseUrl}`
41+
return normalizeBaseUrl(internalBaseUrl)
2542
}
2643

2744
/**

apps/sim/lib/guardrails/validate_hallucination.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { db } from '@sim/db'
22
import { account } from '@sim/db/schema'
33
import { createLogger } from '@sim/logger'
44
import { eq } from 'drizzle-orm'
5-
import { getBaseUrl } from '@/lib/core/utils/urls'
5+
import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
66
import { refreshTokenIfNeeded } from '@/app/api/auth/oauth/utils'
77
import { executeProviderRequest } from '@/providers'
88
import { getProviderFromModel } from '@/providers/utils'
@@ -61,7 +61,7 @@ async function queryKnowledgeBase(
6161
})
6262

6363
// Call the knowledge base search API directly
64-
const searchUrl = `${getBaseUrl()}/api/knowledge/search`
64+
const searchUrl = `${getInternalApiBaseUrl()}/api/knowledge/search`
6565

6666
const response = await fetch(searchUrl, {
6767
method: 'POST',

0 commit comments

Comments
 (0)