mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-08 22:48:14 -05:00
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:
@@ -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'
|
||||
|
||||
@@ -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`)
|
||||
|
||||
@@ -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
36
sim/lib/urls/utils.ts
Normal 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'
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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/'
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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}`
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user