mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
fix(envvars): t3-env standardization (#606)
* chore: use t3-env as source of truth * chore: update mock env for failing tests
This commit is contained in:
committed by
Vikhyath Mondreti
parent
231bfb9add
commit
e22f0123a3
@@ -3,6 +3,7 @@ import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { verifyInternalToken } from '@/lib/auth/internal'
|
||||
import { env } from '@/lib/env'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { getUserEntityPermissions, hasAdminPermission } from '@/lib/permissions/utils'
|
||||
import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/db-helpers'
|
||||
@@ -215,7 +216,7 @@ export async function DELETE(
|
||||
// This prevents "Block not found" errors when collaborative updates try to process
|
||||
// after the workflow has been deleted
|
||||
try {
|
||||
const socketUrl = process.env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||
const socketUrl = env.SOCKET_SERVER_URL || 'http://localhost:3002'
|
||||
const socketResponse = await fetch(`${socketUrl}/api/workflow-deleted`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
|
||||
@@ -30,6 +30,7 @@ import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { env } from '@/lib/env'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { getBaseDomain } from '@/lib/urls/utils'
|
||||
import { cn } from '@/lib/utils'
|
||||
@@ -54,7 +55,7 @@ interface ChatDeployProps {
|
||||
type AuthType = 'public' | 'password' | 'email'
|
||||
|
||||
const getDomainSuffix = (() => {
|
||||
const suffix = process.env.NODE_ENV === 'development' ? `.${getBaseDomain()}` : '.simstudio.ai'
|
||||
const suffix = env.NODE_ENV === 'development' ? `.${getBaseDomain()}` : '.simstudio.ai'
|
||||
return () => suffix
|
||||
})()
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useParams, usePathname, useRouter } from 'next/navigation'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { useSession } from '@/lib/auth-client'
|
||||
import { env } from '@/lib/env'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import {
|
||||
getKeyboardShortcutText,
|
||||
@@ -27,7 +28,7 @@ import { WorkspaceHeader } from './components/workspace-header/workspace-header'
|
||||
|
||||
const logger = createLogger('Sidebar')
|
||||
|
||||
const IS_DEV = process.env.NODE_ENV === 'development'
|
||||
const IS_DEV = env.NODE_ENV === 'development'
|
||||
|
||||
export function Sidebar() {
|
||||
useGlobalShortcuts()
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { DocumentIcon } from '@/components/icons'
|
||||
import { env } from '@/lib/env'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import type { FileParserOutput } from '@/tools/file/types'
|
||||
import type { BlockConfig, SubBlockConfig, SubBlockLayout, SubBlockType } from '../types'
|
||||
|
||||
const logger = createLogger('FileBlock')
|
||||
|
||||
const shouldEnableURLInput = process.env.NODE_ENV === 'production'
|
||||
const shouldEnableURLInput = env.NODE_ENV === 'production'
|
||||
|
||||
const inputMethodBlock: SubBlockConfig = {
|
||||
id: 'inputMethod',
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { MistralIcon } from '@/components/icons'
|
||||
import { env } from '@/lib/env'
|
||||
import type { MistralParserOutput } from '@/tools/mistral/types'
|
||||
import type { BlockConfig, SubBlockConfig, SubBlockLayout, SubBlockType } from '../types'
|
||||
|
||||
const shouldEnableFileUpload = process.env.NODE_ENV === 'production'
|
||||
const shouldEnableFileUpload = env.NODE_ENV === 'production'
|
||||
|
||||
const inputMethodBlock: SubBlockConfig = {
|
||||
id: 'inputMethod',
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Section,
|
||||
Text,
|
||||
} from '@react-email/components'
|
||||
import { env } from '@/lib/env'
|
||||
import { baseStyles } from './base-styles'
|
||||
import EmailFooter from './footer'
|
||||
|
||||
@@ -20,7 +21,7 @@ interface WorkspaceInvitationEmailProps {
|
||||
invitationLink?: string
|
||||
}
|
||||
|
||||
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://simstudio.ai'
|
||||
const baseUrl = env.NEXT_PUBLIC_APP_URL || 'https://simstudio.ai'
|
||||
|
||||
export const WorkspaceInvitationEmail = ({
|
||||
workspaceName = 'Workspace',
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from 'react'
|
||||
import { useParams } from 'next/navigation'
|
||||
import { io, type Socket } from 'socket.io-client'
|
||||
import { env } from '@/lib/env'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
|
||||
const logger = createLogger('SocketContext')
|
||||
@@ -134,7 +135,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
|
||||
// Generate initial token for socket authentication
|
||||
const token = await generateSocketToken()
|
||||
|
||||
const socketUrl = process.env.NEXT_PUBLIC_SOCKET_URL || 'http://localhost:3002'
|
||||
const socketUrl = env.NEXT_PUBLIC_SOCKET_URL || 'http://localhost:3002'
|
||||
|
||||
logger.info('Attempting to connect to Socket.IO server', {
|
||||
url: socketUrl,
|
||||
|
||||
@@ -38,4 +38,4 @@ declare global {
|
||||
}
|
||||
|
||||
export const db = global.database || drizzleClient
|
||||
if (process.env.NODE_ENV !== 'production') global.database = db
|
||||
if (env.NODE_ENV !== 'production') global.database = db
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { stripeClient } from '@better-auth/stripe/client'
|
||||
import { emailOTPClient, genericOAuthClient, organizationClient } from 'better-auth/client/plugins'
|
||||
import { createAuthClient } from 'better-auth/react'
|
||||
import { env } from './env'
|
||||
|
||||
const clientEnv = {
|
||||
NEXT_PUBLIC_VERCEL_URL: process.env.NEXT_PUBLIC_VERCEL_URL,
|
||||
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
VERCEL_ENV: process.env.VERCEL_ENV || '',
|
||||
BETTER_AUTH_URL: process.env.BETTER_AUTH_URL,
|
||||
NEXT_PUBLIC_VERCEL_URL: env.NEXT_PUBLIC_VERCEL_URL,
|
||||
NEXT_PUBLIC_APP_URL: env.NEXT_PUBLIC_APP_URL,
|
||||
NODE_ENV: env.NODE_ENV,
|
||||
VERCEL_ENV: env.VERCEL_ENV || '',
|
||||
BETTER_AUTH_URL: env.BETTER_AUTH_URL,
|
||||
}
|
||||
|
||||
export function getBaseURL() {
|
||||
|
||||
@@ -6,7 +6,11 @@ import {
|
||||
verifyUnsubscribeToken,
|
||||
} from './unsubscribe'
|
||||
|
||||
vi.stubEnv('BETTER_AUTH_SECRET', 'test-secret-key')
|
||||
vi.mock('../env', () => ({
|
||||
env: {
|
||||
BETTER_AUTH_SECRET: 'test-secret-key',
|
||||
},
|
||||
}))
|
||||
|
||||
describe('unsubscribe utilities', () => {
|
||||
const testEmail = 'test@example.com'
|
||||
@@ -75,10 +79,9 @@ describe('unsubscribe utilities', () => {
|
||||
it.concurrent('should handle legacy tokens (2 parts) and default to marketing', () => {
|
||||
// Generate a real legacy token using the actual hashing logic to ensure backward compatibility
|
||||
const salt = 'abc123'
|
||||
const secret = 'test-secret-key'
|
||||
const { createHash } = require('crypto')
|
||||
const hash = createHash('sha256')
|
||||
.update(`${testEmail}:${salt}:${process.env.BETTER_AUTH_SECRET}`)
|
||||
.digest('hex')
|
||||
const hash = createHash('sha256').update(`${testEmail}:${salt}:${secret}`).digest('hex')
|
||||
const legacyToken = `${salt}:${hash}`
|
||||
|
||||
// This should return valid since we're using the actual legacy format properly
|
||||
|
||||
@@ -3,6 +3,7 @@ import { eq } from 'drizzle-orm'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { db } from '@/db'
|
||||
import { settings, user } from '@/db/schema'
|
||||
import { env } from '../env'
|
||||
import type { EmailType } from './mailer'
|
||||
|
||||
const logger = createLogger('Unsubscribe')
|
||||
@@ -20,7 +21,7 @@ export interface EmailPreferences {
|
||||
export function generateUnsubscribeToken(email: string, emailType = 'marketing'): string {
|
||||
const salt = randomBytes(16).toString('hex')
|
||||
const hash = createHash('sha256')
|
||||
.update(`${email}:${salt}:${emailType}:${process.env.BETTER_AUTH_SECRET}`)
|
||||
.update(`${email}:${salt}:${emailType}:${env.BETTER_AUTH_SECRET}`)
|
||||
.digest('hex')
|
||||
|
||||
return `${salt}:${hash}:${emailType}`
|
||||
@@ -41,7 +42,7 @@ export function verifyUnsubscribeToken(
|
||||
if (parts.length === 2) {
|
||||
const [salt, expectedHash] = parts
|
||||
const hash = createHash('sha256')
|
||||
.update(`${email}:${salt}:${process.env.BETTER_AUTH_SECRET}`)
|
||||
.update(`${email}:${salt}:${env.BETTER_AUTH_SECRET}`)
|
||||
.digest('hex')
|
||||
|
||||
return { valid: hash === expectedHash, emailType: 'marketing' }
|
||||
@@ -52,7 +53,7 @@ export function verifyUnsubscribeToken(
|
||||
if (!salt || !expectedHash || !emailType) return { valid: false }
|
||||
|
||||
const hash = createHash('sha256')
|
||||
.update(`${email}:${salt}:${emailType}:${process.env.BETTER_AUTH_SECRET}`)
|
||||
.update(`${email}:${salt}:${emailType}:${env.BETTER_AUTH_SECRET}`)
|
||||
.digest('hex')
|
||||
|
||||
return { valid: hash === expectedHash, emailType }
|
||||
|
||||
@@ -104,6 +104,8 @@ export const env = createEnv({
|
||||
SLACK_CLIENT_ID: z.string().optional(),
|
||||
SLACK_CLIENT_SECRET: z.string().optional(),
|
||||
SOCKET_SERVER_URL: z.string().url().optional(),
|
||||
SOCKET_PORT: z.number().optional(),
|
||||
PORT: z.number().optional(),
|
||||
},
|
||||
|
||||
client: {
|
||||
|
||||
@@ -93,10 +93,10 @@ export async function executeCode(
|
||||
nodeModules: packages,
|
||||
timeout: null,
|
||||
// Add environment variables if needed
|
||||
envVars: Object.entries(process.env).reduce(
|
||||
envVars: Object.entries(env).reduce(
|
||||
(acc, [key, value]) => {
|
||||
if (value !== undefined) {
|
||||
acc[key] = value
|
||||
acc[key] = value as string
|
||||
}
|
||||
return acc
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* It is separate from the user-facing logging system in logging.ts.
|
||||
*/
|
||||
import chalk from 'chalk'
|
||||
import { env } from '../env'
|
||||
|
||||
/**
|
||||
* LogLevel enum defines the severity levels for logging
|
||||
@@ -55,7 +56,7 @@ const LOG_CONFIG = {
|
||||
}
|
||||
|
||||
// Get current environment
|
||||
const ENV = (process.env.NODE_ENV || 'development') as keyof typeof LOG_CONFIG
|
||||
const ENV = (env.NODE_ENV || 'development') as keyof typeof LOG_CONFIG
|
||||
const config = LOG_CONFIG[ENV] || LOG_CONFIG.development
|
||||
|
||||
// Format objects for logging
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { db } from '@/db'
|
||||
import { member, subscription, userStats } from '@/db/schema'
|
||||
import { client } from '../auth-client'
|
||||
import { env } from '../env'
|
||||
import { calculateUsageLimit, checkEnterprisePlan, checkProPlan, checkTeamPlan } from './utils'
|
||||
|
||||
const logger = createLogger('Subscription')
|
||||
@@ -172,9 +173,7 @@ export async function hasExceededCostLimit(userId: string): Promise<boolean> {
|
||||
limit,
|
||||
})
|
||||
} else {
|
||||
limit = process.env.FREE_TIER_COST_LIMIT
|
||||
? Number.parseFloat(process.env.FREE_TIER_COST_LIMIT)
|
||||
: 5
|
||||
limit = env.FREE_TIER_COST_LIMIT || 5
|
||||
logger.info('Using free tier limit', { userId, limit })
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { calculateUsageLimit, checkEnterprisePlan } from './utils'
|
||||
|
||||
const ORIGINAL_ENV = { ...process.env }
|
||||
|
||||
beforeAll(() => {
|
||||
process.env.FREE_TIER_COST_LIMIT = '5'
|
||||
process.env.PRO_TIER_COST_LIMIT = '20'
|
||||
process.env.TEAM_TIER_COST_LIMIT = '40'
|
||||
process.env.ENTERPRISE_TIER_COST_LIMIT = '200'
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
process.env = ORIGINAL_ENV
|
||||
})
|
||||
vi.mock('../env', () => ({
|
||||
env: {
|
||||
FREE_TIER_COST_LIMIT: 5,
|
||||
PRO_TIER_COST_LIMIT: 20,
|
||||
TEAM_TIER_COST_LIMIT: 40,
|
||||
ENTERPRISE_TIER_COST_LIMIT: 200,
|
||||
},
|
||||
}))
|
||||
|
||||
describe('Subscription Utilities', () => {
|
||||
describe('checkEnterprisePlan', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { env } from '../env'
|
||||
|
||||
export function checkEnterprisePlan(subscription: any): boolean {
|
||||
return subscription?.plan === 'enterprise' && subscription?.status === 'active'
|
||||
}
|
||||
@@ -17,16 +19,16 @@ export function checkTeamPlan(subscription: any): boolean {
|
||||
*/
|
||||
export function calculateUsageLimit(subscription: any): number {
|
||||
if (!subscription || subscription.status !== 'active') {
|
||||
return Number.parseFloat(process.env.FREE_TIER_COST_LIMIT!)
|
||||
return env.FREE_TIER_COST_LIMIT || 0
|
||||
}
|
||||
|
||||
const seats = subscription.seats || 1
|
||||
|
||||
if (subscription.plan === 'pro') {
|
||||
return Number.parseFloat(process.env.PRO_TIER_COST_LIMIT!)
|
||||
return env.PRO_TIER_COST_LIMIT || 0
|
||||
}
|
||||
if (subscription.plan === 'team') {
|
||||
return seats * Number.parseFloat(process.env.TEAM_TIER_COST_LIMIT!)
|
||||
return seats * (env.TEAM_TIER_COST_LIMIT || 0)
|
||||
}
|
||||
if (subscription.plan === 'enterprise') {
|
||||
const metadata = subscription.metadata || {}
|
||||
@@ -39,8 +41,8 @@ export function calculateUsageLimit(subscription: any): number {
|
||||
return Number.parseFloat(metadata.totalAllowance)
|
||||
}
|
||||
|
||||
return seats * Number.parseFloat(process.env.ENTERPRISE_TIER_COST_LIMIT!)
|
||||
return seats * (env.ENTERPRISE_TIER_COST_LIMIT || 0)
|
||||
}
|
||||
|
||||
return Number.parseFloat(process.env.FREE_TIER_COST_LIMIT!)
|
||||
return env.FREE_TIER_COST_LIMIT || 0
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { env } from '../env'
|
||||
|
||||
/**
|
||||
* 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')
|
||||
@@ -7,13 +9,13 @@ export function getBaseUrl(): string {
|
||||
return window.location.origin
|
||||
}
|
||||
|
||||
const baseUrl = process.env.NEXT_PUBLIC_APP_URL
|
||||
const baseUrl = env.NEXT_PUBLIC_APP_URL
|
||||
if (baseUrl) {
|
||||
if (baseUrl.startsWith('http://') || baseUrl.startsWith('https://')) {
|
||||
return baseUrl
|
||||
}
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
const isProd = env.NODE_ENV === 'production'
|
||||
const protocol = isProd ? 'https://' : 'http://'
|
||||
return `${protocol}${baseUrl}`
|
||||
}
|
||||
@@ -30,11 +32,11 @@ export function getBaseDomain(): string {
|
||||
const url = new URL(getBaseUrl())
|
||||
return url.host // host includes port if specified
|
||||
} catch (_e) {
|
||||
const fallbackUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
|
||||
const fallbackUrl = env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
|
||||
try {
|
||||
return new URL(fallbackUrl).host
|
||||
} catch {
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
const isProd = env.NODE_ENV === 'production'
|
||||
return isProd ? 'simstudio.ai' : 'localhost:3000'
|
||||
}
|
||||
}
|
||||
@@ -49,7 +51,7 @@ export function getEmailDomain(): string {
|
||||
const baseDomain = getBaseDomain()
|
||||
return baseDomain.startsWith('www.') ? baseDomain.substring(4) : baseDomain
|
||||
} catch (_e) {
|
||||
const isProd = process.env.NODE_ENV === 'production'
|
||||
const isProd = env.NODE_ENV === 'production'
|
||||
return isProd ? 'simstudio.ai' : 'localhost:3000'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
...(env.NODE_ENV === 'development' && {
|
||||
allowedDevOrigins: [
|
||||
...(process.env.NEXT_PUBLIC_APP_URL
|
||||
...(env.NEXT_PUBLIC_APP_URL
|
||||
? (() => {
|
||||
try {
|
||||
return [new URL(process.env.NEXT_PUBLIC_APP_URL).host]
|
||||
return [new URL(env.NEXT_PUBLIC_APP_URL).host]
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
@@ -81,7 +81,7 @@ const nextConfig: NextConfig = {
|
||||
{ key: 'Access-Control-Allow-Credentials', value: 'true' },
|
||||
{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3001',
|
||||
value: env.NEXT_PUBLIC_APP_URL || 'http://localhost:3001',
|
||||
},
|
||||
{
|
||||
key: 'Access-Control-Allow-Methods',
|
||||
@@ -158,7 +158,7 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
{
|
||||
key: 'Content-Security-Policy',
|
||||
value: `default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.google.com https://apis.google.com https://*.vercel-scripts.com https://*.vercel-insights.com https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app https://vitals.vercel-insights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com; media-src 'self' blob:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ${process.env.NEXT_PUBLIC_APP_URL || ''} ${env.OLLAMA_URL || 'http://localhost:11434'} ${process.env.NEXT_PUBLIC_SOCKET_URL || 'http://localhost:3002'} ${process.env.NEXT_PUBLIC_SOCKET_URL?.replace('http://', 'ws://').replace('https://', 'wss://') || 'ws://localhost:3002'} https://*.up.railway.app wss://*.up.railway.app https://api.browser-use.com https://*.googleapis.com https://*.amazonaws.com https://*.s3.amazonaws.com https://*.blob.core.windows.net https://*.vercel-insights.com https://vitals.vercel-insights.com https://*.atlassian.com https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app wss://*.vercel.app; frame-src https://drive.google.com https://*.google.com; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; object-src 'none'`,
|
||||
value: `default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.google.com https://apis.google.com https://*.vercel-scripts.com https://*.vercel-insights.com https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app https://vitals.vercel-insights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com; media-src 'self' blob:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' ${env.NEXT_PUBLIC_APP_URL || ''} ${env.OLLAMA_URL || 'http://localhost:11434'} ${env.NEXT_PUBLIC_SOCKET_URL || 'http://localhost:3002'} ${env.NEXT_PUBLIC_SOCKET_URL?.replace('http://', 'ws://').replace('https://', 'wss://') || 'ws://localhost:3002'} https://*.up.railway.app wss://*.up.railway.app https://api.browser-use.com https://*.googleapis.com https://*.amazonaws.com https://*.s3.amazonaws.com https://*.blob.core.windows.net https://*.vercel-insights.com https://vitals.vercel-insights.com https://*.atlassian.com https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app wss://*.vercel.app; frame-src https://drive.google.com https://*.google.com; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; object-src 'none'`,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { env } from '@/lib/env'
|
||||
import { getNodeEnv } from '@/lib/environment'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { getBaseUrl } from '@/lib/urls/utils'
|
||||
@@ -14,7 +15,7 @@ const getReferer = (): string => {
|
||||
try {
|
||||
return getBaseUrl()
|
||||
} catch (_error) {
|
||||
return process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
|
||||
return env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user