Skip to content

Commit b50696e

Browse files
committed
feat(api): add env runtime checkks
1 parent f313fd8 commit b50696e

6 files changed

Lines changed: 72 additions & 116 deletions

File tree

apps/api/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ REDIS_URL=redis://localhost:6379
55
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/codecrawl
66
REDIS_RATE_LIMIT_URL=redis://localhost:6379
77
CODECRAWL_ENCRYPTION_KEY=your_encryption_key
8+
ALLOWED_ORIGINS=http://localhost:3000,https://crawl.revoks.dev
89

910
### Better Auth
1011
BETTER_AUTH_SECRET=your_secret

apps/api/src/env-runtime.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { parseEnv } from './env'
2+
3+
export const env = parseEnv(Object.assign(process.env))

apps/api/src/env.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { z } from 'zod'
2+
3+
const EnvSchema = z.object({
4+
// generic stuff
5+
NODE_ENV: z.string().default('development'),
6+
PORT: z.string().optional().default('4000'),
7+
DATABASE_URL: z.url(),
8+
REDIS_URL: z.url(),
9+
ALLOWED_API_ORIGINS: z.string().default('http://localhost:3000'),
10+
CODECRAWL_ENCRYPTION_KEY: z.string(),
11+
12+
// auth providers
13+
GOOGLE_CLIENT_ID: z.string(),
14+
GOOGLE_CLIENT_SECRET: z.string(),
15+
16+
// better-auth
17+
BETTER_AUTH_SECRET: z.string(),
18+
BETTER_AUTH_URL: z.url().default('http://localhost:4000'),
19+
BASE_URL: z.url().default('http://localhost:4000'),
20+
})
21+
22+
export type Environment = z.infer<typeof EnvSchema>
23+
24+
export function parseEnv(data: any) {
25+
const { data: env, error, success } = EnvSchema.safeParse(data)
26+
27+
if (!success) {
28+
console.error('Invalid environment variables:', error.format())
29+
process.exit(1)
30+
}
31+
32+
return env
33+
}

apps/api/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Scalar } from '@scalar/hono-api-reference'
22
import { cors } from 'hono/cors'
33
import { secureHeaders } from 'hono/secure-headers'
44

5+
import { env } from '~/env-runtime'
56
import { auth } from '~/lib/auth'
67
import { BASE_URL } from '~/lib/constants'
78
import { logger } from '~/lib/logger'
@@ -15,7 +16,7 @@ app.use(secureHeaders())
1516
app.use(
1617
'*',
1718
cors({
18-
origin: '*',
19+
origin: env.ALLOWED_API_ORIGINS.split(','),
1920
credentials: true,
2021
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],
2122
allowHeaders: [
@@ -83,7 +84,7 @@ app.get(
8384
})
8485
)
8586

86-
const DEFAULT_PORT = process.env.PORT ?? 4000
87+
const DEFAULT_PORT = env.PORT
8788

8889
// Graceful shutdown handling
8990
const shutdown = async (signal: string) => {

apps/api/src/lib/auth/auth.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import { betterAuth } from 'better-auth'
22
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
33

44
import { db } from '~/db'
5+
import { env } from '~/env-runtime'
56
import { isProd } from '~/lib/constants'
67

78
export const auth = betterAuth({
89
basePath: '/auth',
910
database: drizzleAdapter(db, {
1011
provider: 'pg',
1112
}),
13+
trustedOrigins: env.ALLOWED_API_ORIGINS.split(','),
1214
advanced: {
1315
cookiePrefix: 'codecrawl',
1416
crossSubDomainCookies: {
@@ -28,8 +30,8 @@ export const auth = betterAuth({
2830
},
2931
socialProviders: {
3032
google: {
31-
clientId: process.env.GOOGLE_CLIENT_ID as string,
32-
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
33+
clientId: env.GOOGLE_CLIENT_ID,
34+
clientSecret: env.GOOGLE_CLIENT_SECRET,
3335
scopes: [
3436
'https://www.googleapis.com/auth/userinfo.email',
3537
'https://www.googleapis.com/auth/userinfo.profile',

0 commit comments

Comments
 (0)