Skip to content

Commit 2624b5f

Browse files
committed
feat: update environment variable handling and rate limiting
- Made several environment variables optional in env.mjs for better flexibility. - Refactored rate limiting logic in safe-action.ts and related files to utilize the new optional environment variables. - Updated various actions to use the new env imports for AWS credentials and Discord webhook URL, enhancing consistency across the codebase.
1 parent 528c4cb commit 2624b5f

File tree

18 files changed

+324
-232
lines changed

18 files changed

+324
-232
lines changed

apps/app/src/actions/files/delete-file.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
"use server";
22

33
import { authActionClient } from "@/actions/safe-action";
4+
import { env } from "@/env.mjs";
45
import { db } from "@comp/db";
56
import { z } from "zod";
67

78
import { UPLOAD_TYPE } from "@/actions/types";
89

9-
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
10+
if (!env.AWS_ACCESS_KEY_ID || !env.AWS_SECRET_ACCESS_KEY) {
1011
throw new Error("AWS credentials are not set");
1112
}
1213

apps/app/src/actions/files/get-file-url.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,29 @@
22

33
import { authActionClient } from "@/actions/safe-action";
44
import { UPLOAD_TYPE } from "@/actions/types";
5+
import { env } from "@/env.mjs";
56
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
67
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
78
import { db } from "@comp/db";
89
import { z } from "zod";
910

10-
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
11+
if (!env.AWS_ACCESS_KEY_ID || !env.AWS_SECRET_ACCESS_KEY) {
1112
throw new Error("AWS credentials are not set");
1213
}
1314

14-
if (!process.env.AWS_BUCKET_NAME) {
15+
if (!env.AWS_BUCKET_NAME) {
1516
throw new Error("AWS bucket name is not set");
1617
}
1718

18-
if (!process.env.AWS_REGION) {
19+
if (!env.AWS_REGION) {
1920
throw new Error("AWS region is not set");
2021
}
2122

2223
const s3Client = new S3Client({
23-
region: process.env.AWS_REGION,
24+
region: env.AWS_REGION,
2425
credentials: {
25-
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
26-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
26+
accessKeyId: env.AWS_ACCESS_KEY_ID,
27+
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
2728
},
2829
});
2930

apps/app/src/actions/files/upload-file.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22

33
import { authActionClient } from "@/actions/safe-action";
44
import { UPLOAD_TYPE } from "@/actions/types";
5+
import { env } from "@/env.mjs";
56
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
67
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
78
import { db } from "@comp/db";
89
import { z } from "zod";
910

10-
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
11+
if (!env.AWS_ACCESS_KEY_ID || !env.AWS_SECRET_ACCESS_KEY) {
1112
throw new Error("AWS credentials are not set");
1213
}
1314

1415
const s3Client = new S3Client({
15-
region: process.env.AWS_REGION!,
16+
region: env.AWS_REGION!,
1617
credentials: {
17-
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
18-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
18+
accessKeyId: env.AWS_ACCESS_KEY_ID!,
19+
secretAccessKey: env.AWS_SECRET_ACCESS_KEY!,
1920
},
2021
});
2122

apps/app/src/actions/organization/accept-invitation.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,16 @@ export const completeInvitation = authActionClient
141141
const resend = new Resend(process.env.RESEND_API_KEY);
142142

143143
await resend.contacts.create({
144-
firstName: user.name?.split(" ")[0] || "",
145-
lastName: user.name?.split(" ")[1] || "",
144+
firstName:
145+
(user.name?.split(" ")[0] || "")
146+
.charAt(0)
147+
.toUpperCase() +
148+
(user.name?.split(" ")[0] || "").slice(1),
149+
lastName:
150+
(user.name?.split(" ")[1] || "")
151+
.charAt(0)
152+
.toUpperCase() +
153+
(user.name?.split(" ")[1] || "").slice(1),
146154
email: user.email,
147155
unsubscribed: false,
148156
audienceId: process.env.RESEND_AUDIENCE_ID,

apps/app/src/actions/organization/lib/create-stripe-customer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ async function createStripeCustomer(input: {
66
organizationId: string;
77
}): Promise<string> {
88
try {
9+
if (!stripe) {
10+
return "test_customer_id";
11+
}
12+
913
const customer = await stripe.customers.create({
1014
name: input.name,
1115
email: input.email,
Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
import { env } from "@/env.mjs";
12
import Stripe from "stripe";
23

3-
if (!process.env.STRIPE_SECRET_KEY) {
4-
throw new Error("STRIPE_SECRET_KEY is not set");
5-
}
4+
export const stripeWebhookSecret = env.STRIPE_WEBHOOK_SECRET;
65

7-
if (!process.env.STRIPE_WEBHOOK_SECRET) {
8-
throw new Error("STRIPE_WEBHOOK_SECRET is not set");
9-
}
6+
let stripe: Stripe | undefined;
107

11-
export const stripeWebhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
8+
if (env.STRIPE_SECRET_KEY && env.STRIPE_WEBHOOK_SECRET) {
9+
stripe = new Stripe(env.STRIPE_SECRET_KEY, {
10+
apiVersion: "2025-02-24.acacia",
11+
});
12+
} else {
13+
console.warn(
14+
"Stripe environment variables (STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET) are not fully configured. Stripe functionality will be disabled.",
15+
);
16+
}
1217

13-
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
14-
apiVersion: "2025-02-24.acacia",
15-
});
18+
export { stripe };

apps/app/src/actions/safe-action.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { track } from "@/app/posthog";
2+
import { env } from "@/env.mjs";
23
import { auth } from "@/utils/auth";
34
import { logger } from "@/utils/logger";
45
import { client } from "@comp/kv";
@@ -10,10 +11,14 @@ import {
1011
import { headers } from "next/headers";
1112
import { z } from "zod";
1213

13-
const ratelimit = new Ratelimit({
14-
limiter: Ratelimit.fixedWindow(10, "10s"),
15-
redis: client,
16-
});
14+
let ratelimit: Ratelimit | undefined;
15+
16+
if (env.UPSTASH_REDIS_REST_URL && env.UPSTASH_REDIS_REST_TOKEN) {
17+
ratelimit = new Ratelimit({
18+
limiter: Ratelimit.fixedWindow(10, "10s"),
19+
redis: client,
20+
});
21+
}
1722

1823
export const actionClientWithMeta = createSafeActionClient({
1924
handleServerError(e) {
@@ -68,21 +73,24 @@ export const authActionClient = actionClientWithMeta
6873
})
6974
.use(async ({ next, metadata }) => {
7075
const headersList = await headers();
76+
let remaining: number | undefined;
7177

72-
const { success, remaining } = await ratelimit.limit(
73-
`${headersList.get("x-forwarded-for")}-${metadata.name}`,
74-
);
78+
if (ratelimit) {
79+
const { success, remaining } = await ratelimit.limit(
80+
`${headersList.get("x-forwarded-for")}-${metadata.name}`,
81+
);
7582

76-
if (!success) {
77-
throw new Error("Too many requests");
83+
if (!success) {
84+
throw new Error("Too many requests");
85+
}
7886
}
7987

8088
return next({
8189
ctx: {
8290
ip: headersList.get("x-forwarded-for"),
8391
userAgent: headersList.get("user-agent"),
8492
ratelimit: {
85-
remaining,
93+
remaining: remaining ?? 0,
8694
},
8795
},
8896
});

apps/app/src/actions/send-feedback-action.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use server";
22

3+
import { env } from "@/env.mjs";
34
import ky from "ky";
45
import { authActionClient } from "./safe-action";
56
import { sendFeedbackSchema } from "./schema";
@@ -10,7 +11,7 @@ export const sendFeebackAction = authActionClient
1011
name: "send-feedback",
1112
})
1213
.action(async ({ parsedInput: { feedback }, ctx: { user } }) => {
13-
if (process.env.DISCORD_WEBHOOK_URL) {
14+
if (env.DISCORD_WEBHOOK_URL) {
1415
await ky.post(process.env.DISCORD_WEBHOOK_URL as string, {
1516
json: {
1617
content: `New feedback from ${user?.email}: \n\n ${feedback}`,

apps/app/src/app/[locale]/(app)/(dashboard)/[orgId]/evidence/[evidenceId]/actions/getEvidenceFileUrl.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
"use server";
22

33
import { authActionClient } from "@/actions/safe-action";
4+
import { env } from "@/env.mjs";
45
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
56
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
67
import { db } from "@comp/db";
78
import { z } from "zod";
89

9-
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
10+
if (!env.AWS_ACCESS_KEY_ID || !env.AWS_SECRET_ACCESS_KEY) {
1011
throw new Error("AWS credentials are not set");
1112
}
1213

@@ -19,10 +20,10 @@ if (!process.env.AWS_REGION) {
1920
}
2021

2122
const s3Client = new S3Client({
22-
region: process.env.AWS_REGION,
23+
region: env.AWS_REGION,
2324
credentials: {
24-
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
25-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
25+
accessKeyId: env.AWS_ACCESS_KEY_ID,
26+
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
2627
},
2728
});
2829

apps/app/src/app/[locale]/(public)/auth/page.tsx

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GithubSignIn } from "@/components/github-sign-in";
22
import { GoogleSignIn } from "@/components/google-sign-in";
33
import { MagicLinkSignIn } from "@/components/magic-link";
4+
import { env } from "@/env.mjs";
45
import { getI18n } from "@/locales/server";
56
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@comp/ui/accordion";
67
import { Icons } from "@comp/ui/icons";
@@ -21,18 +22,35 @@ export default async function Page({
2122

2223
const { inviteCode } = await searchParams;
2324

24-
const preferredSignInOption = (
25-
<div className="flex flex-col space-y-2">
26-
<GoogleSignIn inviteCode={inviteCode} />
27-
</div>
28-
);
25+
let preferredSignInOption: React.ReactNode;
2926

30-
const moreSignInOptions = (
31-
<div className="flex flex-col space-y-2">
32-
<MagicLinkSignIn inviteCode={inviteCode} />
33-
<GithubSignIn inviteCode={inviteCode} />
34-
</div>
35-
);
27+
if (env.AUTH_GOOGLE_ID && env.AUTH_GOOGLE_SECRET) {
28+
preferredSignInOption = (
29+
<div className="flex flex-col space-y-2">
30+
<GoogleSignIn inviteCode={inviteCode} />
31+
</div>
32+
);
33+
} else {
34+
preferredSignInOption = (
35+
<div className="flex flex-col space-y-2">
36+
<MagicLinkSignIn inviteCode={inviteCode} />
37+
</div>
38+
);
39+
}
40+
41+
42+
let moreSignInOptions: React.ReactNode;
43+
44+
if (env.AUTH_GOOGLE_ID && env.AUTH_GOOGLE_SECRET && env.AUTH_GITHUB_ID && env.AUTH_GITHUB_SECRET) {
45+
moreSignInOptions = (
46+
<div className="flex flex-col space-y-2">
47+
<MagicLinkSignIn inviteCode={inviteCode} />
48+
<GithubSignIn inviteCode={inviteCode} />
49+
</div>
50+
);
51+
} else {
52+
moreSignInOptions = null;
53+
}
3654

3755
return (
3856
<div>
@@ -64,16 +82,18 @@ export default async function Page({
6482
collapsible
6583
className="border-t-[1px] pt-2 mt-6"
6684
>
67-
<AccordionItem value="item-1" className="border-0">
68-
<AccordionTrigger className="justify-center space-x-2 flex text-sm">
69-
<span>More options</span>
70-
</AccordionTrigger>
71-
<AccordionContent className="mt-4">
72-
<div className="flex flex-col space-y-4">
73-
{moreSignInOptions}
74-
</div>
75-
</AccordionContent>
76-
</AccordionItem>
85+
{moreSignInOptions && (
86+
<AccordionItem value="item-1" className="border-0">
87+
<AccordionTrigger className="justify-center space-x-2 flex text-sm">
88+
<span>More options</span>
89+
</AccordionTrigger>
90+
<AccordionContent className="mt-4">
91+
<div className="flex flex-col space-y-4">
92+
{moreSignInOptions}
93+
</div>
94+
</AccordionContent>
95+
</AccordionItem>
96+
)}
7797
</Accordion>
7898
</div>
7999

0 commit comments

Comments
 (0)