improvement(utils): removed duplicate logic to get base url with fallback, made util (#337)

* improvement(utils): removed duplicate logic to get base url with fallback, made util

* acknowledged PR comments
This commit is contained in:
Waleed Latif
2025-05-08 23:30:45 -07:00
committed by GitHub
parent fcc590c02b
commit 1438028982
8 changed files with 76 additions and 26 deletions

View File

@@ -1,10 +1,9 @@
import { isProd } from '@/lib/environment'
import { VerifyContent } from './verify-content'
import { getBaseUrl } from '@/lib/urls/utils'
export default function VerifyPage() {
const protocol = isProd ? 'https' : 'http'
const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'localhost:3000'
const baseUrl = `${protocol}://${appUrl}`
const baseUrl = getBaseUrl()
const hasResendKey = Boolean(
process.env.RESEND_API_KEY && process.env.RESEND_API_KEY !== 'placeholder'

View File

@@ -7,6 +7,7 @@ import { chat } from '@/db/schema'
import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils'
import { z } from 'zod'
import { encryptSecret } from '@/lib/utils'
import { getBaseDomain } from '@/lib/urls/utils'
export const dynamic = 'force-dynamic'
@@ -67,17 +68,15 @@ export async function GET(
// Create a new result object without the password
const { password, ...safeData } = chatInstance[0]
// Check if we're in development or production
const isDevelopment = process.env.NODE_ENV === 'development'
const chatUrl = isDevelopment
? `http://${chatInstance[0].subdomain}.localhost:3000`
? `http://${chatInstance[0].subdomain}.${getBaseDomain()}`
: `https://${chatInstance[0].subdomain}.simstudio.ai`
// For security, don't return the actual password value
const result = {
...safeData,
chatUrl,
// Include password presence flag but not the actual value
hasPassword: !!password
}
@@ -228,12 +227,12 @@ export async function PATCH(
.set(updateData)
.where(eq(chat.id, chatId))
// Return success response
const updatedSubdomain = subdomain || existingChat[0].subdomain
// Check if we're in development or production
const isDevelopment = process.env.NODE_ENV === 'development'
const chatUrl = isDevelopment
? `http://${updatedSubdomain}.localhost:3000`
? `http://${updatedSubdomain}.${getBaseDomain()}`
: `https://${updatedSubdomain}.simstudio.ai`
logger.info(`Chat "${chatId}" updated successfully`)

View File

@@ -32,6 +32,7 @@ import { Skeleton } from '@/components/ui/skeleton'
import { Textarea } from '@/components/ui/textarea'
import { createLogger } from '@/lib/logs/console-logger'
import { cn } from '@/lib/utils'
import { getBaseDomain } from '@/lib/urls/utils'
import { useNotificationStore } from '@/stores/notifications/store'
import { OutputSelect } from '@/app/w/[id]/components/panel/components/chat/components/output-select/output-select'
import { OutputConfig } from '@/stores/panel/chat/types'
@@ -54,6 +55,11 @@ type AuthType = 'public' | 'password' | 'email'
const isDevelopment = process.env.NODE_ENV === 'development'
const getDomainSuffix = (() => {
const suffix = isDevelopment ? `.${getBaseDomain()}` : '.simstudio.ai'
return () => suffix
})()
// Define Zod schema for API request validation
const chatSchema = z.object({
workflowId: z.string().min(1, 'Workflow ID is required'),
@@ -810,11 +816,20 @@ export function ChatDeploy({
}
if (deployedChatUrl) {
// Extract just the subdomain from the URL
const url = new URL(deployedChatUrl)
const hostname = url.hostname
const isDevelopmentUrl = hostname.includes('localhost')
const domainSuffix = isDevelopmentUrl ? '.localhost:3000' : '.simstudio.ai'
let domainSuffix
if (isDevelopmentUrl) {
const baseDomain = getBaseDomain()
const baseHost = baseDomain.split(':')[0]
const port = url.port || (baseDomain.includes(':') ? baseDomain.split(':')[1] : '3000')
domainSuffix = `.${baseHost}:${port}`
} else {
domainSuffix = '.simstudio.ai'
}
const subdomainPart = isDevelopmentUrl
? hostname.split('.')[0]
: hostname.split('.simstudio.ai')[0]
@@ -911,7 +926,7 @@ export function ChatDeploy({
disabled={isDeploying}
/>
<div className="h-10 px-3 flex items-center border border-l-0 rounded-r-md bg-muted text-muted-foreground text-sm font-medium whitespace-nowrap">
{isDevelopment ? '.localhost:3000' : '.simstudio.ai'}
{getDomainSuffix()}
</div>
{!isCheckingSubdomain && subdomainAvailable === true && subdomain && (
<div className="absolute right-14 flex items-center">

36
sim/lib/urls/utils.ts Normal file
View File

@@ -0,0 +1,36 @@
/**
* Returns the base URL of the application, respecting environment variables for deployment environments
* @returns The base URL string (e.g., 'http://localhost:3000' or 'https://example.com')
*/
export function getBaseUrl(): string {
if (typeof window !== 'undefined') {
return window.location.origin
}
const baseUrl = process.env.NEXT_PUBLIC_APP_URL
if (baseUrl) {
if (baseUrl.startsWith('http://') || baseUrl.startsWith('https://')) {
return baseUrl
}
const isProd = process.env.NODE_ENV === 'production'
const protocol = isProd ? 'https://' : 'http://'
return `${protocol}${baseUrl}`
}
return 'http://localhost:3000'
}
/**
* Returns just the domain and port part of the application URL
* @returns The domain with port if applicable (e.g., 'localhost:3000' or 'simstudio.ai')
*/
export function getBaseDomain(): string {
try {
const url = new URL(getBaseUrl())
return url.host // host includes port if specified
} catch (e) {
const isProd = process.env.NODE_ENV === 'production'
return isProd ? 'simstudio.ai' : 'localhost:3000'
}
}

View File

@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from 'next/server'
import { getSessionCookie } from 'better-auth/cookies'
import { verifyToken } from './lib/waitlist/token'
import { createLogger } from '@/lib/logs/console-logger'
import { getBaseDomain } from '@/lib/urls/utils'
const logger = createLogger('Middleware')
@@ -15,7 +16,8 @@ const SUSPICIOUS_UA_PATTERNS = [
/^\(\)\s*{/, // Command execution attempt
/\b(sqlmap|nikto|gobuster|dirb|nmap)\b/i // Known scanning tools
]
const BASE_DOMAIN = isDevelopment ? 'localhost:3000' : 'simstudio.ai'
const BASE_DOMAIN = getBaseDomain()
export async function middleware(request: NextRequest) {
// Check for active session

View File

@@ -1,23 +1,21 @@
import { HttpMethod, TableRow, ToolConfig } from '../types'
import { createLogger } from '@/lib/logs/console-logger'
import { RequestParams, RequestResponse } from './types'
import { getBaseUrl } from '@/lib/urls/utils'
const logger = createLogger('HTTPRequestTool')
// Function to get the appropriate referer based on environment
const getReferer = (): string => {
// Check if we're in a browser environment
if (typeof window !== 'undefined') {
return window.location.origin
}
// Use environment variable if available (server-side)
if (process.env.NEXT_PUBLIC_APP_URL) {
return process.env.NEXT_PUBLIC_APP_URL
try {
return getBaseUrl()
} catch (error) {
return 'http://localhost:3000'
}
// Fallback for development
return 'http://localhost:3000/'
}
/**

View File

@@ -1,6 +1,7 @@
import { createLogger } from '@/lib/logs/console-logger'
import { ToolConfig } from '../types'
import { MistralParserInput, MistralParserOutput } from './types'
import { getBaseUrl } from '@/lib/urls/utils'
const logger = createLogger('MistralParserTool')
@@ -97,7 +98,8 @@ export const mistralParserTool: ToolConfig<MistralParserInput, MistralParserOutp
// Make sure the file path is an absolute URL
if (uploadedFilePath.startsWith('/')) {
// If it's a relative path starting with /, convert to absolute URL
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
const baseUrl = getBaseUrl()
if (!baseUrl) throw new Error('Failed to get base URL for file path conversion')
uploadedFilePath = `${baseUrl}${uploadedFilePath}`
}

View File

@@ -1,5 +1,6 @@
import { ToolConfig } from '../types'
import { createLogger } from '@/lib/logs/console-logger'
import { getBaseUrl } from '@/lib/urls/utils'
const logger = createLogger('DalleTool')
@@ -79,10 +80,8 @@ export const dalleTool: ToolConfig = {
logger.info('Using model:', modelName)
try {
// Fetch the image using the proxy/image endpoint instead of direct fetch
logger.info('Fetching image from URL via proxy...')
// Get the base URL from environment or use a fallback
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
const baseUrl = getBaseUrl()
const proxyUrl = new URL(`/api/proxy/image`, baseUrl)
proxyUrl.searchParams.append('url', imageUrl)
@@ -90,7 +89,7 @@ export const dalleTool: ToolConfig = {
headers: {
Accept: 'image/*, */*',
},
cache: 'no-store', // Don't use cache
cache: 'no-store',
})
if (!imageResponse.ok) {