diff --git a/apps/sim/app/(auth)/login/login-form.tsx b/apps/sim/app/(auth)/login/login-form.tsx index 45877f4e8f..aa274086a8 100644 --- a/apps/sim/app/(auth)/login/login-form.tsx +++ b/apps/sim/app/(auth)/login/login-form.tsx @@ -18,6 +18,7 @@ import { client } from '@/lib/auth-client' import { quickValidateEmail } from '@/lib/email/validation' import { env, isFalsy, isTruthy } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' import { cn } from '@/lib/utils' import { SocialLoginButtons } from '@/app/(auth)/components/social-login-buttons' import { SSOLoginButton } from '@/app/(auth)/components/sso-login-button' @@ -322,7 +323,7 @@ export default function LoginPage({ }, body: JSON.stringify({ email: forgotPasswordEmail, - redirectTo: `${window.location.origin}/reset-password`, + redirectTo: `${getBaseUrl()}/reset-password`, }), }) diff --git a/apps/sim/app/api/billing/portal/route.ts b/apps/sim/app/api/billing/portal/route.ts index f7a980cb2f..017fbb8bd7 100644 --- a/apps/sim/app/api/billing/portal/route.ts +++ b/apps/sim/app/api/billing/portal/route.ts @@ -4,8 +4,8 @@ import { and, eq } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { getSession } from '@/lib/auth' import { requireStripeClient } from '@/lib/billing/stripe-client' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' const logger = createLogger('BillingPortal') @@ -21,8 +21,7 @@ export async function POST(request: NextRequest) { const context: 'user' | 'organization' = body?.context === 'organization' ? 'organization' : 'user' const organizationId: string | undefined = body?.organizationId || undefined - const returnUrl: string = - body?.returnUrl || `${env.NEXT_PUBLIC_APP_URL}/workspace?billing=updated` + const returnUrl: string = body?.returnUrl || `${getBaseUrl()}/workspace?billing=updated` const stripe = requireStripeClient() diff --git a/apps/sim/app/api/chat/route.ts b/apps/sim/app/api/chat/route.ts index c546691ecc..fb51159bb2 100644 --- a/apps/sim/app/api/chat/route.ts +++ b/apps/sim/app/api/chat/route.ts @@ -5,9 +5,9 @@ import type { NextRequest } from 'next/server' import { v4 as uuidv4 } from 'uuid' import { z } from 'zod' import { getSession } from '@/lib/auth' -import { env } from '@/lib/env' import { isDev } from '@/lib/environment' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' import { encryptSecret } from '@/lib/utils' import { checkWorkflowAccessForChatCreation } from '@/app/api/chat/utils' import { createErrorResponse, createSuccessResponse } from '@/app/api/workflows/utils' @@ -171,7 +171,7 @@ export async function POST(request: NextRequest) { // Return successful response with chat URL // Generate chat URL using path-based routing instead of subdomains - const baseUrl = env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' + const baseUrl = getBaseUrl() let chatUrl: string try { diff --git a/apps/sim/app/api/files/download/route.ts b/apps/sim/app/api/files/download/route.ts index d1429b1289..dcf0226bc9 100644 --- a/apps/sim/app/api/files/download/route.ts +++ b/apps/sim/app/api/files/download/route.ts @@ -2,6 +2,7 @@ import { type NextRequest, NextResponse } from 'next/server' import { createLogger } from '@/lib/logs/console/logger' import { getPresignedUrl, getPresignedUrlWithConfig, isUsingCloudStorage } from '@/lib/uploads' import { BLOB_EXECUTION_FILES_CONFIG, S3_EXECUTION_FILES_CONFIG } from '@/lib/uploads/setup' +import { getBaseUrl } from '@/lib/urls/utils' import { createErrorResponse } from '@/app/api/files/utils' const logger = createLogger('FileDownload') @@ -81,7 +82,7 @@ export async function POST(request: NextRequest) { } } else { // For local storage, return the direct path - const downloadUrl = `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/api/files/serve/${key}` + const downloadUrl = `${getBaseUrl()}/api/files/serve/${key}` return NextResponse.json({ downloadUrl, diff --git a/apps/sim/app/api/function/execute/route.ts b/apps/sim/app/api/function/execute/route.ts index d1dc9190aa..d9f763e622 100644 --- a/apps/sim/app/api/function/execute/route.ts +++ b/apps/sim/app/api/function/execute/route.ts @@ -1,7 +1,6 @@ import { createContext, Script } from 'vm' import { type NextRequest, NextResponse } from 'next/server' import { env, isTruthy } from '@/lib/env' -import { MAX_EXECUTION_DURATION } from '@/lib/execution/constants' import { executeInE2B } from '@/lib/execution/e2b' import { CodeLanguage, DEFAULT_CODE_LANGUAGE, isValidCodeLanguage } from '@/lib/execution/languages' import { createLogger } from '@/lib/logs/console/logger' @@ -9,7 +8,9 @@ import { validateProxyUrl } from '@/lib/security/input-validation' import { generateRequestId } from '@/lib/utils' export const dynamic = 'force-dynamic' export const runtime = 'nodejs' -export const maxDuration = MAX_EXECUTION_DURATION +// Segment config exports must be statically analyzable. +// Mirror MAX_EXECUTION_DURATION (210s) from '@/lib/execution/constants'. +export const maxDuration = 210 const logger = createLogger('FunctionExecuteAPI') diff --git a/apps/sim/app/api/organizations/[id]/invitations/route.ts b/apps/sim/app/api/organizations/[id]/invitations/route.ts index 0da3668d9e..85fa235c57 100644 --- a/apps/sim/app/api/organizations/[id]/invitations/route.ts +++ b/apps/sim/app/api/organizations/[id]/invitations/route.ts @@ -23,9 +23,9 @@ import { } from '@/lib/billing/validation/seat-management' import { sendEmail } from '@/lib/email/mailer' import { quickValidateEmail } from '@/lib/email/validation' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' import { hasWorkspaceAdminAccess } from '@/lib/permissions/utils' +import { getBaseUrl } from '@/lib/urls/utils' const logger = createLogger('OrganizationInvitations') @@ -339,7 +339,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ organizationEntry[0]?.name || 'organization', role, workspaceInvitationsWithNames, - `${env.NEXT_PUBLIC_APP_URL}/invite/${orgInvitation.id}` + `${getBaseUrl()}/invite/${orgInvitation.id}` ) emailResult = await sendEmail({ @@ -352,7 +352,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ const emailHtml = await renderInvitationEmail( inviter[0]?.name || 'Someone', organizationEntry[0]?.name || 'organization', - `${env.NEXT_PUBLIC_APP_URL}/invite/${orgInvitation.id}`, + `${getBaseUrl()}/invite/${orgInvitation.id}`, email ) diff --git a/apps/sim/app/api/organizations/[id]/members/route.ts b/apps/sim/app/api/organizations/[id]/members/route.ts index 193ace3699..43e69e4813 100644 --- a/apps/sim/app/api/organizations/[id]/members/route.ts +++ b/apps/sim/app/api/organizations/[id]/members/route.ts @@ -9,8 +9,8 @@ import { getUserUsageData } from '@/lib/billing/core/usage' import { validateSeatAvailability } from '@/lib/billing/validation/seat-management' import { sendEmail } from '@/lib/email/mailer' import { quickValidateEmail } from '@/lib/email/validation' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' const logger = createLogger('OrganizationMembersAPI') @@ -260,7 +260,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ const emailHtml = await renderInvitationEmail( inviter[0]?.name || 'Someone', organizationEntry[0]?.name || 'organization', - `${env.NEXT_PUBLIC_APP_URL}/invite/organization?id=${invitationId}`, + `${getBaseUrl()}/invite/organization?id=${invitationId}`, normalizedEmail ) diff --git a/apps/sim/app/api/webhooks/[id]/route.ts b/apps/sim/app/api/webhooks/[id]/route.ts index 1154ef1d89..a8119d9e1d 100644 --- a/apps/sim/app/api/webhooks/[id]/route.ts +++ b/apps/sim/app/api/webhooks/[id]/route.ts @@ -3,9 +3,9 @@ import { webhook, workflow } from '@sim/db/schema' import { eq } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { getSession } from '@/lib/auth' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' import { getUserEntityPermissions } from '@/lib/permissions/utils' +import { getBaseUrl } from '@/lib/urls/utils' import { generateRequestId } from '@/lib/utils' import { getOAuthToken } from '@/app/api/auth/oauth/utils' @@ -282,13 +282,7 @@ export async function DELETE( if (!resolvedExternalId) { try { - if (!env.NEXT_PUBLIC_APP_URL) { - logger.error( - `[${requestId}] NEXT_PUBLIC_APP_URL not configured, cannot match Airtable webhook` - ) - throw new Error('NEXT_PUBLIC_APP_URL must be configured') - } - const expectedNotificationUrl = `${env.NEXT_PUBLIC_APP_URL}/api/webhooks/trigger/${foundWebhook.path}` + const expectedNotificationUrl = `${getBaseUrl()}/api/webhooks/trigger/${foundWebhook.path}` const listUrl = `https://api.airtable.com/v0/bases/${baseId}/webhooks` const listResp = await fetch(listUrl, { diff --git a/apps/sim/app/api/webhooks/[id]/test-url/route.ts b/apps/sim/app/api/webhooks/[id]/test-url/route.ts index b4da4142d6..b844dc8d61 100644 --- a/apps/sim/app/api/webhooks/[id]/test-url/route.ts +++ b/apps/sim/app/api/webhooks/[id]/test-url/route.ts @@ -2,9 +2,9 @@ import { db, webhook, workflow } from '@sim/db' import { eq } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { getSession } from '@/lib/auth' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' import { getUserEntityPermissions } from '@/lib/permissions/utils' +import { getBaseUrl } from '@/lib/urls/utils' import { generateRequestId } from '@/lib/utils' import { signTestWebhookToken } from '@/lib/webhooks/test-tokens' @@ -64,13 +64,8 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ return NextResponse.json({ error: 'Forbidden' }, { status: 403 }) } - if (!env.NEXT_PUBLIC_APP_URL) { - logger.error(`[${requestId}] NEXT_PUBLIC_APP_URL not configured`) - return NextResponse.json({ error: 'Server configuration error' }, { status: 500 }) - } - const token = await signTestWebhookToken(id, ttlSeconds) - const url = `${env.NEXT_PUBLIC_APP_URL}/api/webhooks/test/${id}?token=${encodeURIComponent(token)}` + const url = `${getBaseUrl()}/api/webhooks/test/${id}?token=${encodeURIComponent(token)}` logger.info(`[${requestId}] Minted test URL for webhook ${id}`) return NextResponse.json({ diff --git a/apps/sim/app/api/webhooks/route.ts b/apps/sim/app/api/webhooks/route.ts index d9b39e66c5..f4fcfbe94c 100644 --- a/apps/sim/app/api/webhooks/route.ts +++ b/apps/sim/app/api/webhooks/route.ts @@ -4,9 +4,9 @@ import { and, desc, eq } from 'drizzle-orm' import { nanoid } from 'nanoid' import { type NextRequest, NextResponse } from 'next/server' import { getSession } from '@/lib/auth' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' import { getUserEntityPermissions } from '@/lib/permissions/utils' +import { getBaseUrl } from '@/lib/urls/utils' import { generateRequestId } from '@/lib/utils' import { getOAuthToken } from '@/app/api/auth/oauth/utils' @@ -467,14 +467,7 @@ async function createAirtableWebhookSubscription( ) } - if (!env.NEXT_PUBLIC_APP_URL) { - logger.error( - `[${requestId}] NEXT_PUBLIC_APP_URL not configured, cannot register Airtable webhook` - ) - throw new Error('NEXT_PUBLIC_APP_URL must be configured for Airtable webhook registration') - } - - const notificationUrl = `${env.NEXT_PUBLIC_APP_URL}/api/webhooks/trigger/${path}` + const notificationUrl = `${getBaseUrl()}/api/webhooks/trigger/${path}` const airtableApiUrl = `https://api.airtable.com/v0/bases/${baseId}/webhooks` diff --git a/apps/sim/app/api/webhooks/test/route.ts b/apps/sim/app/api/webhooks/test/route.ts index 5b8886bf23..8467f53063 100644 --- a/apps/sim/app/api/webhooks/test/route.ts +++ b/apps/sim/app/api/webhooks/test/route.ts @@ -2,8 +2,8 @@ import { db } from '@sim/db' import { webhook } from '@sim/db/schema' import { eq } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' import { generateRequestId } from '@/lib/utils' const logger = createLogger('WebhookTestAPI') @@ -35,15 +35,7 @@ export async function GET(request: NextRequest) { const provider = foundWebhook.provider || 'generic' const providerConfig = (foundWebhook.providerConfig as Record) || {} - if (!env.NEXT_PUBLIC_APP_URL) { - logger.error(`[${requestId}] NEXT_PUBLIC_APP_URL not configured, cannot test webhook`) - return NextResponse.json( - { success: false, error: 'NEXT_PUBLIC_APP_URL must be configured' }, - { status: 500 } - ) - } - const baseUrl = env.NEXT_PUBLIC_APP_URL - const webhookUrl = `${baseUrl}/api/webhooks/trigger/${foundWebhook.path}` + const webhookUrl = `${getBaseUrl()}/api/webhooks/trigger/${foundWebhook.path}` logger.info(`[${requestId}] Testing webhook for provider: ${provider}`, { webhookId, diff --git a/apps/sim/app/api/workspaces/invitations/[invitationId]/route.test.ts b/apps/sim/app/api/workspaces/invitations/[invitationId]/route.test.ts index 917a1ddb17..1213c622a0 100644 --- a/apps/sim/app/api/workspaces/invitations/[invitationId]/route.test.ts +++ b/apps/sim/app/api/workspaces/invitations/[invitationId]/route.test.ts @@ -61,17 +61,21 @@ describe('Workspace Invitation [invitationId] API Route', () => { hasWorkspaceAdminAccess: mockHasWorkspaceAdminAccess, })) - vi.doMock('@/lib/env', () => ({ - env: { + vi.doMock('@/lib/env', () => { + const mockEnv = { NEXT_PUBLIC_APP_URL: 'https://test.sim.ai', BILLING_ENABLED: false, - }, - isTruthy: (value: string | boolean | number | undefined) => - typeof value === 'string' - ? value.toLowerCase() === 'true' || value === '1' - : Boolean(value), - getEnv: (variable: string) => process.env[variable], - })) + } + return { + env: mockEnv, + isTruthy: (value: string | boolean | number | undefined) => + typeof value === 'string' + ? value.toLowerCase() === 'true' || value === '1' + : Boolean(value), + getEnv: (variable: string) => + mockEnv[variable as keyof typeof mockEnv] ?? process.env[variable], + } + }) mockTransaction = vi.fn() const mockDbChain = { @@ -384,17 +388,21 @@ describe('Workspace Invitation [invitationId] API Route', () => { vi.doMock('@/lib/permissions/utils', () => ({ hasWorkspaceAdminAccess: vi.fn(), })) - vi.doMock('@/lib/env', () => ({ - env: { + vi.doMock('@/lib/env', () => { + const mockEnv = { NEXT_PUBLIC_APP_URL: 'https://test.sim.ai', BILLING_ENABLED: false, - }, - isTruthy: (value: string | boolean | number | undefined) => - typeof value === 'string' - ? value.toLowerCase() === 'true' || value === '1' - : Boolean(value), - getEnv: (variable: string) => process.env[variable], - })) + } + return { + env: mockEnv, + isTruthy: (value: string | boolean | number | undefined) => + typeof value === 'string' + ? value.toLowerCase() === 'true' || value === '1' + : Boolean(value), + getEnv: (variable: string) => + mockEnv[variable as keyof typeof mockEnv] ?? process.env[variable], + } + }) vi.doMock('@sim/db/schema', () => ({ workspaceInvitation: { id: 'id' }, })) diff --git a/apps/sim/app/api/workspaces/invitations/[invitationId]/route.ts b/apps/sim/app/api/workspaces/invitations/[invitationId]/route.ts index 9b8a379cd5..dc6073a3f1 100644 --- a/apps/sim/app/api/workspaces/invitations/[invitationId]/route.ts +++ b/apps/sim/app/api/workspaces/invitations/[invitationId]/route.ts @@ -14,8 +14,8 @@ import { WorkspaceInvitationEmail } from '@/components/emails/workspace-invitati import { getSession } from '@/lib/auth' import { sendEmail } from '@/lib/email/mailer' import { getFromEmailAddress } from '@/lib/email/utils' -import { env } from '@/lib/env' import { hasWorkspaceAdminAccess } from '@/lib/permissions/utils' +import { getBaseUrl } from '@/lib/urls/utils' // GET /api/workspaces/invitations/[invitationId] - Get invitation details OR accept via token export async function GET( @@ -30,12 +30,7 @@ export async function GET( if (!session?.user?.id) { // For token-based acceptance flows, redirect to login if (isAcceptFlow) { - return NextResponse.redirect( - new URL( - `/invite/${invitationId}?token=${token}`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) - ) + return NextResponse.redirect(new URL(`/invite/${invitationId}?token=${token}`, getBaseUrl())) } return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } @@ -54,10 +49,7 @@ export async function GET( if (!invitation) { if (isAcceptFlow) { return NextResponse.redirect( - new URL( - `/invite/${invitationId}?error=invalid-token`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) + new URL(`/invite/${invitationId}?error=invalid-token`, getBaseUrl()) ) } return NextResponse.json({ error: 'Invitation not found or has expired' }, { status: 404 }) @@ -66,10 +58,7 @@ export async function GET( if (new Date() > new Date(invitation.expiresAt)) { if (isAcceptFlow) { return NextResponse.redirect( - new URL( - `/invite/${invitation.id}?error=expired`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) + new URL(`/invite/${invitation.id}?error=expired`, getBaseUrl()) ) } return NextResponse.json({ error: 'Invitation has expired' }, { status: 400 }) @@ -84,10 +73,7 @@ export async function GET( if (!workspaceDetails) { if (isAcceptFlow) { return NextResponse.redirect( - new URL( - `/invite/${invitation.id}?error=workspace-not-found`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) + new URL(`/invite/${invitation.id}?error=workspace-not-found`, getBaseUrl()) ) } return NextResponse.json({ error: 'Workspace not found' }, { status: 404 }) @@ -96,10 +82,7 @@ export async function GET( if (isAcceptFlow) { if (invitation.status !== ('pending' as WorkspaceInvitationStatus)) { return NextResponse.redirect( - new URL( - `/invite/${invitation.id}?error=already-processed`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) + new URL(`/invite/${invitation.id}?error=already-processed`, getBaseUrl()) ) } @@ -114,10 +97,7 @@ export async function GET( if (!userData) { return NextResponse.redirect( - new URL( - `/invite/${invitation.id}?error=user-not-found`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) + new URL(`/invite/${invitation.id}?error=user-not-found`, getBaseUrl()) ) } @@ -125,10 +105,7 @@ export async function GET( if (!isValidMatch) { return NextResponse.redirect( - new URL( - `/invite/${invitation.id}?error=email-mismatch`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) + new URL(`/invite/${invitation.id}?error=email-mismatch`, getBaseUrl()) ) } @@ -154,10 +131,7 @@ export async function GET( .where(eq(workspaceInvitation.id, invitation.id)) return NextResponse.redirect( - new URL( - `/workspace/${invitation.workspaceId}/w`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) + new URL(`/workspace/${invitation.workspaceId}/w`, getBaseUrl()) ) } @@ -181,12 +155,7 @@ export async function GET( .where(eq(workspaceInvitation.id, invitation.id)) }) - return NextResponse.redirect( - new URL( - `/workspace/${invitation.workspaceId}/w`, - env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' - ) - ) + return NextResponse.redirect(new URL(`/workspace/${invitation.workspaceId}/w`, getBaseUrl())) } return NextResponse.json({ @@ -298,7 +267,7 @@ export async function POST( .set({ token: newToken, expiresAt: newExpiresAt, updatedAt: new Date() }) .where(eq(workspaceInvitation.id, invitationId)) - const baseUrl = env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' + const baseUrl = getBaseUrl() const invitationLink = `${baseUrl}/invite/${invitationId}?token=${newToken}` const emailHtml = await render( diff --git a/apps/sim/app/api/workspaces/invitations/route.ts b/apps/sim/app/api/workspaces/invitations/route.ts index e15885a802..99b89f2b73 100644 --- a/apps/sim/app/api/workspaces/invitations/route.ts +++ b/apps/sim/app/api/workspaces/invitations/route.ts @@ -15,8 +15,8 @@ import { WorkspaceInvitationEmail } from '@/components/emails/workspace-invitati import { getSession } from '@/lib/auth' import { sendEmail } from '@/lib/email/mailer' import { getFromEmailAddress } from '@/lib/email/utils' -import { env } from '@/lib/env' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' export const dynamic = 'force-dynamic' @@ -232,7 +232,7 @@ async function sendInvitationEmail({ token: string }) { try { - const baseUrl = env.NEXT_PUBLIC_APP_URL || 'https://sim.ai' + const baseUrl = getBaseUrl() // Use invitation ID in path, token in query parameter for security const invitationLink = `${baseUrl}/invite/${invitationId}?token=${token}` diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/trigger-config/components/trigger-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/trigger-config/components/trigger-modal.tsx index 73863f3f90..5be21dd2a6 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/trigger-config/components/trigger-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/trigger-config/components/trigger-modal.tsx @@ -20,6 +20,7 @@ import { } from '@/components/ui/select' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' import { cn } from '@/lib/utils' import { useSubBlockStore } from '@/stores/workflows/subblock/store' import { getTrigger } from '@/triggers' @@ -284,8 +285,7 @@ export function TriggerModal({ } if (finalPath) { - const baseUrl = window.location.origin - setWebhookUrl(`${baseUrl}/api/webhooks/trigger/${finalPath}`) + setWebhookUrl(`${getBaseUrl()}/api/webhooks/trigger/${finalPath}`) } }, [ triggerPath, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx index 2f7ce0ab45..7363de60ab 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/webhook/components/webhook-modal.tsx @@ -9,6 +9,7 @@ import { DialogTitle, } from '@/components/ui/dialog' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' import { AirtableConfig, DeleteConfirmDialog, @@ -404,12 +405,7 @@ export function WebhookModal({ }, [webhookPath]) // Construct the full webhook URL - const baseUrl = - typeof window !== 'undefined' - ? `${window.location.protocol}//${window.location.host}` - : 'https://your-domain.com' - - const webhookUrl = `${baseUrl}/api/webhooks/trigger/${formattedPath}` + const webhookUrl = `${getBaseUrl()}/api/webhooks/trigger/${formattedPath}` const generateTestUrl = async () => { if (!webhookId) return diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/account/account.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/account/account.tsx index 99749d6ecf..69b38d4307 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/account/account.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/account/account.tsx @@ -12,6 +12,7 @@ import { Skeleton } from '@/components/ui/skeleton' import { signOut, useSession } from '@/lib/auth-client' import { useBrandConfig } from '@/lib/branding/branding' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' import { useProfilePictureUpload } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/account/hooks/use-profile-picture-upload' import { clearUserData } from '@/stores' @@ -208,7 +209,7 @@ export function Account(_props: AccountProps) { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, - redirectTo: `${window.location.origin}/reset-password`, + redirectTo: `${getBaseUrl()}/reset-password`, }), }) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/sso/sso.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/sso/sso.tsx index 4c10951f6d..985f8217ef 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/sso/sso.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/sso/sso.tsx @@ -5,9 +5,9 @@ import { Check, ChevronDown, Copy, Eye, EyeOff } from 'lucide-react' import { Alert, AlertDescription, Button, Input, Label } from '@/components/ui' import { Skeleton } from '@/components/ui/skeleton' import { useSession } from '@/lib/auth-client' -import { env } from '@/lib/env' import { isBillingEnabled } from '@/lib/environment' import { createLogger } from '@/lib/logs/console/logger' +import { getBaseUrl } from '@/lib/urls/utils' import { cn } from '@/lib/utils' import { useOrganizationStore } from '@/stores/organization' @@ -441,7 +441,7 @@ export function SSO() { }) } - const callbackUrl = `${env.NEXT_PUBLIC_APP_URL}/api/auth/sso/callback/${formData.providerId}` + const callbackUrl = `${getBaseUrl()}/api/auth/sso/callback/${formData.providerId}` const copyCallback = async () => { try { @@ -551,14 +551,14 @@ export function SSO() {
(e.target as HTMLInputElement).select()} />