diff --git a/.github/workflows/build-and-lint.yml b/.github/workflows/build-and-lint.yml index 221a2c12..668eb5ad 100644 --- a/.github/workflows/build-and-lint.yml +++ b/.github/workflows/build-and-lint.yml @@ -91,4 +91,6 @@ jobs: ${{ runner.os }}-node-modules- - name: Build + env: + SKIP_ENV_VALIDATION: "1" run: npm run build diff --git a/next.config.mjs b/next.config.mjs index 4678774e..7de0ae5c 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,25 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {}; +import { fileURLToPath } from "node:url"; +import createJiti from "jiti"; +import { + PHASE_DEVELOPMENT_SERVER, + PHASE_PRODUCTION_BUILD, +} from "next/constants.js"; -export default nextConfig; +/** @type {import('next').NextConfig | ((phase: string) => import('next').NextConfig)} */ +export default function nextConfig(phase) { + const jiti = createJiti(fileURLToPath(import.meta.url)); + + const skipValidation = process.env.SKIP_ENV_VALIDATION === "1"; + + if (!skipValidation) { + if ( + phase === PHASE_DEVELOPMENT_SERVER || + phase === PHASE_PRODUCTION_BUILD + ) { + jiti("./src/env/server.ts"); + jiti("./src/env/client.ts"); + } + } + + return {}; +} diff --git a/package-lock.json b/package-lock.json index 79780a4e..9bf02dcc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@radix-ui/react-tooltip": "^1.2.8", "@reown/appkit": "^1.6.8", "@reown/appkit-adapter-ethers5": "^1.6.8", + "@t3-oss/env-nextjs": "^0.13.8", "@tanstack/react-query": "^4.36.1", "@trpc/client": "^10.45.2", "@trpc/react-query": "^10.45.2", @@ -40,6 +41,7 @@ "drizzle-orm": "^0.36.3", "ethers": "^5.7.2", "ioredis": "^5.4.1", + "jiti": "^1", "lucide-react": "^0.460.0", "next": "14.2.16", "next-themes": "^0.4.4", @@ -54,7 +56,7 @@ "ulid": "^2.3.0", "validator": "^13.12.0", "viem": "^2.21.48", - "zod": "^3.24.2" + "zod": "^3.25.76" }, "devDependencies": { "@biomejs/biome": "^1.9.4", @@ -3807,6 +3809,61 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/@t3-oss/env-core": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/@t3-oss/env-core/-/env-core-0.13.8.tgz", + "integrity": "sha512-L1inmpzLQyYu4+Q1DyrXsGJYCXbtXjC4cICw1uAKv0ppYPQv656lhZPU91Qd1VS6SO/bou1/q5ufVzBGbNsUpw==", + "license": "MIT", + "peerDependencies": { + "arktype": "^2.1.0", + "typescript": ">=5.0.0", + "valibot": "^1.0.0-beta.7 || ^1.0.0", + "zod": "^3.24.0 || ^4.0.0-beta.0" + }, + "peerDependenciesMeta": { + "arktype": { + "optional": true + }, + "typescript": { + "optional": true + }, + "valibot": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@t3-oss/env-nextjs": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/@t3-oss/env-nextjs/-/env-nextjs-0.13.8.tgz", + "integrity": "sha512-QmTLnsdQJ8BiQad2W2nvV6oUpH4oMZMqnFEjhVpzU0h3sI9hn8zb8crjWJ1Amq453mGZs6A4v4ihIeBFDOrLeQ==", + "license": "MIT", + "dependencies": { + "@t3-oss/env-core": "0.13.8" + }, + "peerDependencies": { + "arktype": "^2.1.0", + "typescript": ">=5.0.0", + "valibot": "^1.0.0-beta.7 || ^1.0.0", + "zod": "^3.24.0 || ^4.0.0-beta.0" + }, + "peerDependenciesMeta": { + "arktype": { + "optional": true + }, + "typescript": { + "optional": true + }, + "valibot": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/@tanstack/query-core": { "version": "4.36.1", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz", @@ -8895,9 +8952,10 @@ } }, "node_modules/zod": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 1b7b0d99..5febfba7 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@radix-ui/react-tooltip": "^1.2.8", "@reown/appkit": "^1.6.8", "@reown/appkit-adapter-ethers5": "^1.6.8", + "@t3-oss/env-nextjs": "^0.13.8", "@tanstack/react-query": "^4.36.1", "@trpc/client": "^10.45.2", "@trpc/react-query": "^10.45.2", @@ -63,9 +64,10 @@ "ulid": "^2.3.0", "validator": "^13.12.0", "viem": "^2.21.48", - "zod": "^3.24.2" + "zod": "^3.25.76" }, "devDependencies": { + "jiti": "1.21.7", "@biomejs/biome": "^1.9.4", "@types/crypto-js": "^4.2.2", "@types/node": "^20", diff --git a/src/app/api/trpc/[trpc]/route.ts b/src/app/api/trpc/[trpc]/route.ts index 02dde4d9..a6741f18 100644 --- a/src/app/api/trpc/[trpc]/route.ts +++ b/src/app/api/trpc/[trpc]/route.ts @@ -2,6 +2,7 @@ import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; import { TRPC_ERROR_CODES_BY_KEY } from "@trpc/server/rpc"; import type { NextRequest } from "next/server"; +import { env } from "@/env/server"; import { appRouter } from "@/server/index"; import { createTRPCContext } from "@/server/trpc"; @@ -60,7 +61,7 @@ const handler = (req: NextRequest) => // @ts-expect-error: This works , no need to fix createContext: () => createContext(req), onError: - process.env.NODE_ENV === "development" + env.NODE_ENV === "development" ? ({ path, error }) => { console.error( `❌ tRPC failed on ${path ?? ""}: ${error.message}`, diff --git a/src/app/api/webhook/route.ts b/src/app/api/webhook/route.ts index d85a3406..526cf23c 100644 --- a/src/app/api/webhook/route.ts +++ b/src/app/api/webhook/route.ts @@ -1,4 +1,5 @@ import crypto from "node:crypto"; +import { env } from "@/env/server"; import { ResourceNotFoundError } from "@/lib/errors"; import { generateInvoiceNumber } from "@/lib/helpers/client"; import { getInvoiceCount } from "@/lib/helpers/invoice"; @@ -90,7 +91,7 @@ export async function POST(req: Request) { webhookData = body; const signature = req.headers.get("x-request-network-signature"); - const webhookSecret = process.env.WEBHOOK_SECRET; + const webhookSecret = env.WEBHOOK_SECRET; if (!webhookSecret) { throw new Error("WEBHOOK_SECRET is not set"); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index fa0736f7..91515bad 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -9,6 +9,7 @@ import type { Metadata } from "next"; import localFont from "next/font/local"; import { cookies } from "next/headers"; import "./globals.css"; +import { env } from "@/env/client"; const geistSans = localFont({ src: "./fonts/GeistVF.woff", @@ -33,7 +34,7 @@ export default function RootLayout({ }>) { return ( - + diff --git a/src/app/login/google/route.ts b/src/app/login/google/route.ts index 60f349f0..55209e6a 100644 --- a/src/app/login/google/route.ts +++ b/src/app/login/google/route.ts @@ -1,3 +1,4 @@ +import { env } from "@/env/server"; import { google } from "@/server/auth"; // app/login/google/route.ts import { generateCodeVerifier, generateState } from "arctic"; @@ -17,14 +18,14 @@ export async function GET(): Promise { cookieStore.set("google_oauth_state", state, { path: "/", httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: env.NODE_ENV === "production", maxAge: 60 * 10, sameSite: "lax", }); cookieStore.set("google_code_verifier", codeVerifier, { path: "/", httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: env.NODE_ENV === "production", maxAge: 60 * 10, sameSite: "lax", }); diff --git a/src/app/page.tsx b/src/app/page.tsx index f168edca..2dccdc76 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,6 @@ import { Footer } from "@/components/footer"; import { Header } from "@/components/header"; +import { env } from "@/env/client"; import { getCurrentSession } from "@/server/auth"; import type { Metadata } from "next"; import Image from "next/image"; @@ -52,7 +53,7 @@ export default async function LoginPage() {

By continuing, you agree to our{" "} (null); const TRUSTED_ORIGINS = useMemo(() => { - const origins = process.env.NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS - ? process.env.NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS.split(",") + const origins = env.NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS + ? env.NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS.split(",") : ["https://request.network", "https://core-api-staging.pay.so"]; // Add localhost in development - if (process.env.NODE_ENV === "development") { + if (serverEnv.NODE_ENV === "development") { origins.push("http://localhost:3000"); } diff --git a/src/components/header.tsx b/src/components/header.tsx index b49d4f85..4b8cd6ce 100644 --- a/src/components/header.tsx +++ b/src/components/header.tsx @@ -1,5 +1,6 @@ "use client"; +import { env } from "@/env/client"; import type { User } from "@/server/db/schema"; import Link from "next/link"; import { usePathname } from "next/navigation"; @@ -7,7 +8,7 @@ import { Button } from "./ui/button"; import { UserMenu } from "./user-menu"; export function Header({ user }: { user?: User | undefined }) { - const demoMeetingUrl = process.env.NEXT_PUBLIC_DEMO_MEETING; + const demoMeetingUrl = env.NEXT_PUBLIC_DEMO_MEETING; const pathname = usePathname(); // Don't show nav items on invoice payment pages diff --git a/src/env/client.ts b/src/env/client.ts new file mode 100644 index 00000000..4d5fc01d --- /dev/null +++ b/src/env/client.ts @@ -0,0 +1,21 @@ +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; + +export const env = createEnv({ + client: { + NEXT_PUBLIC_REOWN_PROJECT_ID: z.string().min(1), + NEXT_PUBLIC_API_TERMS_CONDITIONS: z.string().url(), + NEXT_PUBLIC_GTM_ID: z.string().optional(), + NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS: z.string().optional(), + NEXT_PUBLIC_DEMO_MEETING: z.string().optional(), + }, + runtimeEnv: { + NEXT_PUBLIC_REOWN_PROJECT_ID: process.env.NEXT_PUBLIC_REOWN_PROJECT_ID, + NEXT_PUBLIC_API_TERMS_CONDITIONS: + process.env.NEXT_PUBLIC_API_TERMS_CONDITIONS, + NEXT_PUBLIC_GTM_ID: process.env.NEXT_PUBLIC_GTM_ID, + NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS: + process.env.NEXT_PUBLIC_CRYPTO_TO_FIAT_TRUSTED_ORIGINS, + NEXT_PUBLIC_DEMO_MEETING: process.env.NEXT_PUBLIC_DEMO_MEETING, + }, +}); diff --git a/src/env/server.ts b/src/env/server.ts new file mode 100644 index 00000000..a3a3c611 --- /dev/null +++ b/src/env/server.ts @@ -0,0 +1,24 @@ +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; + +export const env = createEnv({ + server: { + ENCRYPTION_KEY: z.string().min(1), + DATABASE_URL: z.string().min(1), + GOOGLE_CLIENT_ID: z.string().min(1), + GOOGLE_CLIENT_SECRET: z.string().min(1), + GOOGLE_REDIRECT_URI: z.string().min(1), + CURRENT_ENCRYPTION_VERSION: z.string().min(1), + REQUEST_API_URL: z.string().url(), + REQUEST_API_KEY: z.string().min(1), + WEBHOOK_SECRET: z.string().min(1), + FEE_PERCENTAGE_FOR_PAYMENT: z.string().default(""), + FEE_ADDRESS_FOR_PAYMENT: z.string().default(""), + REDIS_URL: z.string().default(""), + INVOICE_PROCESSING_TTL: z.string().default(""), + NODE_ENV: z.enum(["development", "production", "test"]), + VERCEL_URL: z.string().optional(), + PORT: z.coerce.number().optional(), + }, + experimental__runtimeEnv: process.env, +}); diff --git a/src/lib/axios.ts b/src/lib/axios.ts index 8fa091fd..c74470df 100644 --- a/src/lib/axios.ts +++ b/src/lib/axios.ts @@ -1,8 +1,9 @@ +import { env } from "@/env/server"; import axios from "axios"; export const apiClient = axios.create({ - baseURL: process.env.REQUEST_API_URL, - headers: { - "x-api-key": process.env.REQUEST_API_KEY, - }, + baseURL: env.REQUEST_API_URL, + headers: { + "x-api-key": env.REQUEST_API_KEY, + }, }); diff --git a/src/lib/encryption/index.ts b/src/lib/encryption/index.ts index f5f2bfc8..7bc24566 100644 --- a/src/lib/encryption/index.ts +++ b/src/lib/encryption/index.ts @@ -1,8 +1,10 @@ +import { env } from "@/env/server"; + export type EncryptionVersion = "v1"; export function getEncryptionKey(version: EncryptionVersion = "v1"): string { return ENCRYPTION_KEYS[version]; } const ENCRYPTION_KEYS = { - v1: process.env.ENCRYPTION_KEY as string, + v1: env.ENCRYPTION_KEY as string, }; diff --git a/src/lib/redis/index.ts b/src/lib/redis/index.ts index 0670c709..3c4ef08a 100644 --- a/src/lib/redis/index.ts +++ b/src/lib/redis/index.ts @@ -1,10 +1,11 @@ +import { env } from "@/env/server"; import Redis from "ioredis"; let redis: Redis | null = null; export function getRedis(): Redis { if (!redis) { - redis = new Redis(process.env.REDIS_URL || "redis://localhost:6379", { + redis = new Redis(env.REDIS_URL || "redis://localhost:6379", { lazyConnect: true, }); diff --git a/src/middleware.ts b/src/middleware.ts index 82b45e12..26d59080 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,6 +1,7 @@ import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; +import { env } from "./env/server"; export async function middleware(request: NextRequest): Promise { if (request.method === "GET") { @@ -14,7 +15,7 @@ export async function middleware(request: NextRequest): Promise { maxAge: 60 * 60 * 24 * 30, sameSite: "lax", httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: env.NODE_ENV === "production", }); } return response; diff --git a/src/server/auth/index.ts b/src/server/auth/index.ts index e97bfff3..3f7a593c 100644 --- a/src/server/auth/index.ts +++ b/src/server/auth/index.ts @@ -1,3 +1,4 @@ +import { env } from "@/env/server"; import { db } from "@/server/db"; import { type Session, @@ -76,7 +77,7 @@ export async function setSessionTokenCookie( cookieStore.set("session", token, { httpOnly: true, sameSite: "lax", - secure: process.env.NODE_ENV === "production", + secure: env.NODE_ENV === "production", expires: expiresAt, path: "/", }); @@ -87,7 +88,7 @@ export async function deleteSessionTokenCookie(): Promise { cookieStore.set("session", "", { httpOnly: true, sameSite: "lax", - secure: process.env.NODE_ENV === "production", + secure: env.NODE_ENV === "production", maxAge: 0, path: "/", }); @@ -107,7 +108,7 @@ export type SessionValidationResult = | { session: null; user: null }; export const google = new Google( - process.env.GOOGLE_CLIENT_ID as string, - process.env.GOOGLE_CLIENT_SECRET as string, - process.env.GOOGLE_REDIRECT_URI as string, + env.GOOGLE_CLIENT_ID as string, + env.GOOGLE_CLIENT_SECRET as string, + env.GOOGLE_REDIRECT_URI as string, ); diff --git a/src/server/db/index.ts b/src/server/db/index.ts index 0b9454de..d612345d 100644 --- a/src/server/db/index.ts +++ b/src/server/db/index.ts @@ -1,10 +1,11 @@ +import { env } from "@/env/server"; import { drizzle as drizzlePg } from "drizzle-orm/node-postgres"; -import { Pool } from "pg"; import type { NodePgDatabase } from "drizzle-orm/node-postgres"; +import { Pool } from "pg"; import * as schema from "./schema"; const pool = new Pool({ - connectionString: process.env.DATABASE_URL as string, + connectionString: env.DATABASE_URL as string, }); export const db = drizzlePg(pool, { diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index ad8d484a..e3dfb179 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -1,3 +1,4 @@ +import { env } from "@/env/server"; import { type EncryptionVersion, getEncryptionKey } from "@/lib/encryption"; import CryptoJS from "crypto-js"; import { type InferSelectModel, relations } from "drizzle-orm"; @@ -14,7 +15,7 @@ import { export const createTable = pgTableCreator((name) => `easyinvoice_${name}`); -const encryptionKey = process.env.ENCRYPTION_KEY as string; +const encryptionKey = env.ENCRYPTION_KEY as string; // Define enum types for status fields export const agreementStatusEnum = pgEnum("agreement_status", [ diff --git a/src/server/routers/invoice.ts b/src/server/routers/invoice.ts index c970b1bf..56d4f9e5 100644 --- a/src/server/routers/invoice.ts +++ b/src/server/routers/invoice.ts @@ -1,3 +1,4 @@ +import { env } from "@/env/server"; import { apiClient } from "@/lib/axios"; import { toTRPCError } from "@/lib/errors"; import { getRedis } from "@/lib/redis"; @@ -374,11 +375,11 @@ export const invoiceRouter = router({ params.append("token", input.token); } - if (process.env.FEE_PERCENTAGE_FOR_PAYMENT) { - params.append("feePercentage", process.env.FEE_PERCENTAGE_FOR_PAYMENT); + if (env.FEE_PERCENTAGE_FOR_PAYMENT) { + params.append("feePercentage", env.FEE_PERCENTAGE_FOR_PAYMENT); } - if (process.env.FEE_ADDRESS_FOR_PAYMENT) { - params.append("feeAddress", process.env.FEE_ADDRESS_FOR_PAYMENT); + if (env.FEE_ADDRESS_FOR_PAYMENT) { + params.append("feeAddress", env.FEE_ADDRESS_FOR_PAYMENT); } const paymentEndpoint = `/v2/request/${invoice.requestId}/pay?${params.toString()}`; @@ -448,7 +449,7 @@ export const invoiceRouter = router({ const { requestId, walletAddress } = input; const response = await apiClient.get( - `/v2/request/${requestId}/routes?wallet=${walletAddress}&feePercentage=${process.env.FEE_PERCENTAGE_FOR_PAYMENT}&feeAddress=${process.env.FEE_ADDRESS_FOR_PAYMENT}`, + `/v2/request/${requestId}/routes?wallet=${walletAddress}&feePercentage=${env.FEE_PERCENTAGE_FOR_PAYMENT}&feeAddress=${env.FEE_ADDRESS_FOR_PAYMENT}`, ); if (response.status !== 200) { @@ -505,7 +506,7 @@ export const invoiceRouter = router({ await redis.setex( `processing:${invoice.id}`, - Number(process.env.INVOICE_PROCESSING_TTL) || 60, + Number(env.INVOICE_PROCESSING_TTL) || 60, "true", ); } catch (error) { diff --git a/src/server/routers/payment.ts b/src/server/routers/payment.ts index 5fc1f715..3de00e9f 100644 --- a/src/server/routers/payment.ts +++ b/src/server/routers/payment.ts @@ -1,3 +1,4 @@ +import { env } from "@/env/server"; import { apiClient } from "@/lib/axios"; import { toTRPCError } from "@/lib/errors"; import { batchPaymentApiSchema, paymentApiSchema } from "@/lib/schemas/payment"; @@ -19,8 +20,8 @@ export const paymentRouter = router({ }); } - const feePercentage = process.env.FEE_PERCENTAGE_FOR_PAYMENT; - const feeAddress = process.env.FEE_ADDRESS_FOR_PAYMENT; + const feePercentage = env.FEE_PERCENTAGE_FOR_PAYMENT; + const feeAddress = env.FEE_ADDRESS_FOR_PAYMENT; const response = await apiClient.post("v2/payouts", { amount: input.amount.toString(), @@ -64,8 +65,8 @@ export const paymentRouter = router({ payee: payout.payee, invoiceCurrency: payout.invoiceCurrency, paymentCurrency: payout.paymentCurrency, - feePercentage: process.env.FEE_PERCENTAGE_FOR_PAYMENT, - feeAddress: process.env.FEE_ADDRESS_FOR_PAYMENT, + feePercentage: env.FEE_PERCENTAGE_FOR_PAYMENT, + feeAddress: env.FEE_ADDRESS_FOR_PAYMENT, })) : undefined, requestIds: input.requestIds, diff --git a/src/trpc/react.tsx b/src/trpc/react.tsx index 3c212318..f4a0105c 100644 --- a/src/trpc/react.tsx +++ b/src/trpc/react.tsx @@ -6,6 +6,7 @@ import { createTRPCReact } from "@trpc/react-query"; import { useState } from "react"; import superjson from "superjson"; +import { env } from "@/env/server"; import type { AppRouter } from "@/server/index"; import { getUrl } from "./shared"; @@ -34,7 +35,7 @@ export function TRPCReactProvider(props: { links: [ loggerLink({ enabled: (op) => - process.env.NODE_ENV === "development" || + env.NODE_ENV === "development" || (op.direction === "down" && op.result instanceof Error), }), httpBatchLink({ diff --git a/src/trpc/server.ts b/src/trpc/server.ts index d661b317..033228b4 100644 --- a/src/trpc/server.ts +++ b/src/trpc/server.ts @@ -11,6 +11,7 @@ import type { TRPCErrorResponse } from "@trpc/server/rpc"; import { cookies } from "next/headers"; import { cache } from "react"; +import { env } from "@/env/server"; import { type AppRouter, appRouter } from "@/server/"; import { createTRPCContext } from "@/server/trpc"; import { transformer } from "./shared"; @@ -33,7 +34,7 @@ export const api = createTRPCProxyClient({ links: [ loggerLink({ enabled: (op) => - process.env.NODE_ENV === "development" || + env.NODE_ENV === "development" || (op.direction === "down" && op.result instanceof Error), }), () => diff --git a/src/trpc/shared.ts b/src/trpc/shared.ts index 3aed1c46..e508ce4f 100644 --- a/src/trpc/shared.ts +++ b/src/trpc/shared.ts @@ -1,14 +1,15 @@ import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server"; import superjson from "superjson"; +import { env } from "@/env/server"; import type { AppRouter } from "@/server/index"; export const transformer = superjson; function getBaseUrl() { if (typeof window !== "undefined") return ""; - if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; - return `http://localhost:${process.env.PORT ?? 3000}`; + if (env.VERCEL_URL) return `https://${env.VERCEL_URL}`; + return `http://localhost:${env.PORT ?? 3000}`; } export function getUrl() {