Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build-and-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ jobs:
${{ runner.os }}-node-modules-

- name: Build
env:
SKIP_ENV_VALIDATION: "1"
run: npm run build
Comment on lines +94 to 96
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Also skip validation during lint to avoid false CI failures.

Some linters/tsc tasks load Next config and would trigger env validation. Mirror SKIP_ENV_VALIDATION for the lint step.

Apply this diff:

-      - name: Check formatting and lint
-        run: npm run check
+      - name: Check formatting and lint
+        env:
+          SKIP_ENV_VALIDATION: "1"
+        run: npm run check
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
env:
SKIP_ENV_VALIDATION: "1"
run: npm run build
- name: Check formatting and lint
env:
SKIP_ENV_VALIDATION: "1"
run: npm run check
🤖 Prompt for AI Agents
.github/workflows/build-and-lint.yml around lines 94 to 96: the lint step can
trigger Next config env validation causing false CI failures; add the
SKIP_ENV_VALIDATION: "1" environment variable to the lint job just like the
build job so lint/tsc tasks skip env validation. Update the lint step's env
block to include SKIP_ENV_VALIDATION: "1" (mirror the build step) so both steps
run without triggering env checks.

27 changes: 24 additions & 3 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -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 {};
}
66 changes: 62 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Search for remaining process.env usages and update to env.*.

To ensure completeness of the migration, scan for direct process.env access (excluding env modules and config).

Also applies to: 53-53


🏁 Script executed:

#!/bin/bash
# Find raw process.env usages outside env modules and config
rg -nP --type=ts --type=tsx -C2 '(?<!env\/)(?<!next\.config)\bprocess\.env\.[A-Z0-9_]+' -g '!**/src/env/**' -g '!**/next.config.*'

Length of output: 68


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Searching for raw process.env usages in ts/tsx/js/jsx files (excluding src/env and next.config.*)..."
rg -n -S 'process\.env\.' -g '!src/env/**' -g '!**/next.config.*' -g '!node_modules/**' -g '!dist/**' -g '!build/**' -g '!**/.git/**' -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx' -C2 || true
echo "Done."

Length of output: 4167


Replace remaining direct process.env usages with env. (client vs server as appropriate).*

Found raw process.env references that must be migrated (ignore src/env/* — that’s the env module):

  • src/trpc/shared.ts:10-11 — VERCEL_URL, PORT
  • src/trpc/server.ts:36 — NODE_ENV
  • src/trpc/react.tsx:37 — NODE_ENV
  • src/middleware.ts:17 — NODE_ENV
  • src/server/auth/index.ts:80,91 — NODE_ENV
  • src/components/header.tsx:10 — NEXT_PUBLIC_DEMO_MEETING
  • src/components/compliance-form.tsx:76 — NODE_ENV
  • src/app/login/google/route.ts:20,27 — NODE_ENV
  • src/app/api/trpc/[trpc]/route.ts:63 — NODE_ENV
  • drizzle.config.ts:8,10 — DATABASE_URL

Update public vars to the env client accessor (env.NEXT_PUBLIC_…), and server-only vars (DATABASE_URL, PORT, NODE_ENV, VERCEL_URL) to the server env accessor from your env module. Re-run a repo-wide search (excluding src/env/** and next.config.*) to confirm no raw process.env remain.

🤖 Prompt for AI Agents
package.json lines 37-37: Several raw process.env usages remain across the repo
and must be replaced with the project's env accessors; update public variables
to use the client accessor (env.NEXT_PUBLIC_...) and server-only variables to
use the server env accessor from src/env (e.g., env.DATABASE_URL, env.PORT,
env.NODE_ENV, env.VERCEL_URL), changing the specific occurrences noted
(src/trpc/shared.ts:10-11, src/trpc/server.ts:36, src/trpc/react.tsx:37,
src/middleware.ts:17, src/server/auth/index.ts:80,91,
src/components/header.tsx:10, src/components/compliance-form.tsx:76,
src/app/login/google/route.ts:20,27, src/app/api/trpc/[trpc]/route.ts:63,
drizzle.config.ts:8,10), then run a repo-wide search (excluding src/env/** and
next.config.*) to ensure no raw process.env references remain.

"@tanstack/react-query": "^4.36.1",
"@trpc/client": "^10.45.2",
"@trpc/react-query": "^10.45.2",
Expand Down Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion src/app/api/trpc/[trpc]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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 ?? "<no-path>"}: ${error.message}`,
Expand Down
3 changes: 2 additions & 1 deletion src/app/api/webhook/route.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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");
Expand Down
3 changes: 2 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -33,7 +34,7 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<GoogleTagManager gtmId={process.env.NEXT_PUBLIC_GTM_ID as string} />
<GoogleTagManager gtmId={env.NEXT_PUBLIC_GTM_ID as string} />
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
Expand Down
5 changes: 3 additions & 2 deletions src/app/login/google/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { env } from "@/env/server";
import { google } from "@/server/auth";
// app/login/google/route.ts
import { generateCodeVerifier, generateState } from "arctic";
Expand All @@ -17,14 +18,14 @@ export async function GET(): Promise<Response> {
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",
});
Expand Down
3 changes: 2 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -52,7 +53,7 @@ export default async function LoginPage() {
<p className="text-center text-sm text-zinc-500">
By continuing, you agree to our{" "}
<Link
href={process.env.NEXT_PUBLIC_API_TERMS_CONDITIONS as string}
href={env.NEXT_PUBLIC_API_TERMS_CONDITIONS as string}
className="underline hover:text-zinc-900"
target="_blank"
rel="noopener noreferrer"
Expand Down
3 changes: 2 additions & 1 deletion src/components/app-kit.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";

import { env } from "@/env/client";
import { Ethers5Adapter } from "@reown/appkit-adapter-ethers5";
import {
arbitrum,
Expand All @@ -18,7 +19,7 @@ const metadata = {
icons: ["./assets/logo.svg"],
};

const projectId = process.env.NEXT_PUBLIC_REOWN_PROJECT_ID;
const projectId = env.NEXT_PUBLIC_REOWN_PROJECT_ID;

if (!projectId) {
throw new Error("NEXT_PUBLIC_REOWN_PROJECT_ID is not set");
Expand Down
8 changes: 5 additions & 3 deletions src/components/compliance-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { env } from "@/env/client";
import { env as serverEnv } from "@/env/server";
import { COMPLIANCE_COUNTRIES } from "@/lib/constants/compliance";
Comment on lines +34 to 36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Don’t import server env in a client component; trim/dedupe origins.

Importing "@/env/server" in a "use client" file risks bundling server-only values and can break builds. Also, normalize the comma list and avoid duplicates.

Apply this diff:

-import { env as serverEnv } from "@/env/server";
+// Avoid importing server env in client code

 ...
   const TRUSTED_ORIGINS = useMemo(() => {
-    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"];
+    const originsBase = 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"];
+    const origins = originsBase.map((s) => s.trim()).filter(Boolean);
 
     // Add localhost in development
-    if (serverEnv.NODE_ENV === "development") {
-      origins.push("http://localhost:3000");
-    }
+    if (process.env.NODE_ENV === "development") {
+      origins.push("http://localhost:3000");
+    }
 
-    return origins;
+    return Array.from(new Set(origins));
   }, []);

Run to ensure no other client files import the server env:

Also applies to: 72-79


🏁 Script executed:

#!/bin/bash
# Find client components importing "@/env/server"
mapfile -t CLIENTS < <(rg -l -nP --type=tsx '^\s*"use client";')
for f in "${CLIENTS[@]}"; do
  rg -n '@/env/server' "$f" || true
done

Length of output: 84


🏁 Script executed:

#!/bin/bash
# Find client components importing "@/env/server" without process substitution or --type
PAT="^\s*['\"]use client['\"]\s*;?"
CLIENT_FILES=$(rg -l -nP "$PAT" -g '**/*.{tsx,jsx}' --color=never || true)
if [ -z "$CLIENT_FILES" ]; then
  echo "NO_CLIENT_FILES_FOUND"
  exit 0
fi
printf '%s\n' "$CLIENT_FILES" | while IFS= read -r f; do
  echo "---- $f ----"
  rg -n --color=never '@/env/server' "$f" || echo "No @/env/server import in $f"
done

Length of output: 5499


Remove server env imports from client components; trim/dedupe trusted origins

Found '@/env/server' imported in client files:

  • src/components/compliance-form.tsx — line 35
  • src/trpc/react.tsx — line 9

Apply the diff below to compliance-form.tsx (remove server import, trim origins, dedupe). For src/trpc/react.tsx remove the server env import and move the logic server-side or replace with client-safe NEXT_PUBLIC_* env vars.

-import { env as serverEnv } from "@/env/server";
+// Avoid importing server env in client code

 ...
   const TRUSTED_ORIGINS = useMemo(() => {
-    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"];
+    const originsBase = 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"];
+    const origins = originsBase.map((s) => s.trim()).filter(Boolean);
 
     // Add localhost in development
-    if (serverEnv.NODE_ENV === "development") {
-      origins.push("http://localhost:3000");
-    }
+    if (process.env.NODE_ENV === "development") {
+      origins.push("http://localhost:3000");
+    }
 
-    return origins;
+    return Array.from(new Set(origins));
   }, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { env } from "@/env/client";
import { env as serverEnv } from "@/env/server";
import { COMPLIANCE_COUNTRIES } from "@/lib/constants/compliance";
import { env } from "@/env/client";
// Avoid importing server env in client code
import { COMPLIANCE_COUNTRIES } from "@/lib/constants/compliance";
🤖 Prompt for AI Agents
In src/components/compliance-form.tsx around lines 34 to 36, remove the import
of server-only env (import { env as serverEnv } from "@/env/server") so the
client component only uses client-safe env values; replace any usage of
serverEnv with appropriate NEXT_PUBLIC_* variables or derive values on the
server and pass them as props; also trim whitespace from the trusted origins
list and deduplicate entries (e.g., normalize and filter unique) before using
them in the client. For the other occurrence in src/trpc/react.tsx (line ~9)
remove the server env import and either move the logic that needs server env to
a server-side module or switch to NEXT_PUBLIC_* env vars so no server-only
imports remain in client code.

import {
BeneficiaryType,
Expand Down Expand Up @@ -67,12 +69,12 @@ export function ComplianceForm({ user }: { user: User }) {

const iframeRef = useRef<HTMLIFrameElement>(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");
}

Expand Down
3 changes: 2 additions & 1 deletion src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"use client";

import { env } from "@/env/client";
import type { User } from "@/server/db/schema";
import Link from "next/link";
import { usePathname } from "next/navigation";
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
Expand Down
21 changes: 21 additions & 0 deletions src/env/client.ts
Original file line number Diff line number Diff line change
@@ -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(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Tighten GTM ID validation.

Reduce silent misconfig by validating the GTM container ID shape.

-    NEXT_PUBLIC_GTM_ID: z.string().optional(),
+    NEXT_PUBLIC_GTM_ID: z
+      .string()
+      .regex(/^GTM-[A-Z0-9]+$/i, "Expected GTM container ID like GTM-XXXXXXX")
+      .optional(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
NEXT_PUBLIC_GTM_ID: z.string().optional(),
NEXT_PUBLIC_GTM_ID: z
.string()
.regex(/^GTM-[A-Z0-9]+$/i, "Expected GTM container ID like GTM-XXXXXXX")
.optional(),
🤖 Prompt for AI Agents
In src/env/client.ts around line 8, the NEXT_PUBLIC_GTM_ID schema uses
z.string().optional() which allows silent misconfigs; tighten validation by
requiring the GTM container ID to match the expected pattern (e.g.
/^GTM-[A-Z0-9]+$/) and optionally trim/uppercase input before validation;
replace the current schema with a regex-based string check
(z.string().transform(...).regex(...).optional() or
z.string().regex(...).optional()) so only valid GTM IDs are accepted and invalid
values are rejected.

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,
},
});
24 changes: 24 additions & 0 deletions src/env/server.ts
Original file line number Diff line number Diff line change
@@ -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,
});
9 changes: 5 additions & 4 deletions src/lib/axios.ts
Original file line number Diff line number Diff line change
@@ -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,
},
});
Comment on lines +5 to 9
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add a client-wide timeout for outbound API calls.

External calls without timeouts can hang threads and degrade reliability.

Apply this diff:

 export const apiClient = axios.create({
   baseURL: env.REQUEST_API_URL,
   headers: {
     "x-api-key": env.REQUEST_API_KEY,
   },
+  timeout: 10000, // 10s fail-fast
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
baseURL: env.REQUEST_API_URL,
headers: {
"x-api-key": env.REQUEST_API_KEY,
},
});
export const apiClient = axios.create({
baseURL: env.REQUEST_API_URL,
headers: {
"x-api-key": env.REQUEST_API_KEY,
},
timeout: 10000, // 10s fail-fast
});
🤖 Prompt for AI Agents
In src/lib/axios.ts around lines 5 to 9, the axios instance is created without a
request timeout; add a client-wide timeout to prevent hanging external calls by
adding a timeout property to the axios.create config (use a configurable value,
e.g. parseInt(env.REQUEST_API_TIMEOUT) with a safe default like 5000 ms if the
env var is missing/invalid) so the instance includes baseURL, headers, and
timeout in its config.

4 changes: 3 additions & 1 deletion src/lib/encryption/index.ts
Original file line number Diff line number Diff line change
@@ -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,
};
3 changes: 2 additions & 1 deletion src/lib/redis/index.ts
Original file line number Diff line number Diff line change
@@ -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,
});

Expand Down
Loading
Loading