summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/web/drizzle.config.ts11
-rw-r--r--apps/web/package.json2
-rw-r--r--apps/web/src/components/development-debug.tsx3
-rw-r--r--apps/web/src/components/header.tsx3
-rw-r--r--apps/web/src/env.ts27
-rw-r--r--apps/web/src/lib/rate-limit.ts5
-rw-r--r--apps/web/src/middleware.ts3
-rw-r--r--packages/auth/package.json9
-rw-r--r--packages/auth/src/client.ts7
-rw-r--r--packages/auth/src/index.ts5
-rw-r--r--packages/auth/src/keys.ts20
-rw-r--r--packages/auth/src/server.ts11
-rw-r--r--packages/db/drizzle.config.ts15
-rw-r--r--packages/db/package.json7
-rw-r--r--packages/db/src/index.ts8
-rw-r--r--packages/db/src/keys.ts19
16 files changed, 118 insertions, 37 deletions
diff --git a/apps/web/drizzle.config.ts b/apps/web/drizzle.config.ts
index 615eea57..87547bd0 100644
--- a/apps/web/drizzle.config.ts
+++ b/apps/web/drizzle.config.ts
@@ -1,23 +1,20 @@
import type { Config } from "drizzle-kit";
import * as dotenv from "dotenv";
+import { env } from "@/env";
// Load the right env file based on environment
-if (process.env.NODE_ENV === "production") {
+if (env.NODE_ENV === "production") {
dotenv.config({ path: ".env.production" });
} else {
dotenv.config({ path: ".env.local" });
}
-if (!process.env.DATABASE_URL) {
- throw new Error("DATABASE_URL is not set");
-}
-
export default {
schema: "../../packages/db/src/schema.ts",
dialect: "postgresql",
dbCredentials: {
- url: process.env.DATABASE_URL,
+ url: env.DATABASE_URL,
},
out: "./migrations",
- strict: process.env.NODE_ENV === "production",
+ strict: env.NODE_ENV === "production",
} satisfies Config;
diff --git a/apps/web/package.json b/apps/web/package.json
index 9e1393b7..b7bbc499 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -21,6 +21,8 @@
"@hookform/resolvers": "^3.9.1",
"@opencut/auth": "workspace:*",
"@opencut/db": "workspace:*",
+ "@t3-oss/env-core": "^0.13.8",
+ "@t3-oss/env-nextjs": "^0.13.8",
"@upstash/ratelimit": "^2.0.5",
"@upstash/redis": "^1.35.0",
"@vercel/analytics": "^1.4.1",
diff --git a/apps/web/src/components/development-debug.tsx b/apps/web/src/components/development-debug.tsx
index 3b891e38..62e606ff 100644
--- a/apps/web/src/components/development-debug.tsx
+++ b/apps/web/src/components/development-debug.tsx
@@ -7,9 +7,10 @@ import { usePlaybackStore } from "@/stores/playback-store";
import { Button } from "@/components/ui/button";
import { useState } from "react";
import type { TimelineElement } from "@/types/timeline";
+import { env } from "@/env";
// Only show in development
-const SHOW_DEBUG_INFO = process.env.NODE_ENV === "development";
+const SHOW_DEBUG_INFO = env.NODE_ENV === "development";
interface ActiveElement {
element: TimelineElement;
diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx
index bfe314d6..455e0140 100644
--- a/apps/web/src/components/header.tsx
+++ b/apps/web/src/components/header.tsx
@@ -8,6 +8,7 @@ import { useSession } from "@opencut/auth/client";
import { getStars } from "@/lib/fetch-github-stars";
import { useEffect, useState } from "react";
import Image from "next/image";
+import { env } from "@/env";
export function Header() {
const { data: session } = useSession();
@@ -40,7 +41,7 @@ export function Header() {
Contributors
</Button>
</Link>
- {process.env.NODE_ENV === "development" ? (
+ {env.NODE_ENV === "development" ? (
<Link href="/projects">
<Button size="sm" className="text-sm ml-4">
Projects
diff --git a/apps/web/src/env.ts b/apps/web/src/env.ts
new file mode 100644
index 00000000..8071107e
--- /dev/null
+++ b/apps/web/src/env.ts
@@ -0,0 +1,27 @@
+import { vercel } from "@t3-oss/env-core/presets-zod";
+import { createEnv } from "@t3-oss/env-nextjs";
+import { z } from "zod";
+import { keys as auth } from "@opencut/auth/keys";
+import { keys as db } from "@opencut/db/keys";
+
+export const env = createEnv({
+ extends: [vercel(), auth(), db()],
+ server: {
+ ANALYZE: z.string().optional(),
+ // Added by Vercel
+ NEXT_RUNTIME: z.enum(["nodejs", "edge"]).optional(),
+ NODE_ENV: z
+ .enum(["development", "production", "test"])
+ .default("development"),
+ UPSTASH_REDIS_REST_URL: z.string().url(),
+ UPSTASH_REDIS_REST_TOKEN: z.string(),
+ },
+ client: {},
+ runtimeEnv: {
+ ANALYZE: process.env.ANALYZE,
+ NEXT_RUNTIME: process.env.NEXT_RUNTIME,
+ NODE_ENV: process.env.NODE_ENV,
+ UPSTASH_REDIS_REST_URL: process.env.UPSTASH_REDIS_REST_URL,
+ UPSTASH_REDIS_REST_TOKEN: process.env.UPSTASH_REDIS_REST_TOKEN,
+ },
+});
diff --git a/apps/web/src/lib/rate-limit.ts b/apps/web/src/lib/rate-limit.ts
index bf1cce02..92e78e74 100644
--- a/apps/web/src/lib/rate-limit.ts
+++ b/apps/web/src/lib/rate-limit.ts
@@ -1,10 +1,11 @@
// lib/rate-limit.ts
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
+import { env } from "@/env";
const redis = new Redis({
- url: process.env.UPSTASH_REDIS_REST_URL!,
- token: process.env.UPSTASH_REDIS_REST_TOKEN!,
+ url: env.UPSTASH_REDIS_REST_URL,
+ token: env.UPSTASH_REDIS_REST_TOKEN,
});
export const waitlistRateLimit = new Ratelimit({
diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts
index bdce5cc1..57e1e808 100644
--- a/apps/web/src/middleware.ts
+++ b/apps/web/src/middleware.ts
@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
+import { env } from "./env";
export async function middleware(request: NextRequest) {
// Handle fuckcapcut.com domain redirect
@@ -9,7 +10,7 @@ export async function middleware(request: NextRequest) {
const path = request.nextUrl.pathname;
- if (path === "/editor" && process.env.NODE_ENV === "production") {
+ if (path === "/editor" && env.NODE_ENV === "production") {
const homeUrl = new URL("/", request.url);
homeUrl.searchParams.set("redirect", request.url);
return NextResponse.redirect(homeUrl);
diff --git a/packages/auth/package.json b/packages/auth/package.json
index 3ee43643..bfca9cf7 100644
--- a/packages/auth/package.json
+++ b/packages/auth/package.json
@@ -7,13 +7,16 @@
"exports": {
".": "./src/index.ts",
"./client": "./src/client.ts",
- "./server": "./src/server.ts"
+ "./server": "./src/server.ts",
+ "./keys": "./src/keys.ts"
},
"dependencies": {
+ "@opencut/db": "workspace:*",
+ "@t3-oss/env-nextjs": "^0.13.8",
"better-auth": "^1.1.1",
- "@opencut/db": "workspace:*"
+ "zod": "^4.0.5"
},
"devDependencies": {
"@types/node": "^22.10.2"
}
-} \ No newline at end of file
+} \ No newline at end of file
diff --git a/packages/auth/src/client.ts b/packages/auth/src/client.ts
index deda3928..2676fb0d 100644
--- a/packages/auth/src/client.ts
+++ b/packages/auth/src/client.ts
@@ -1,5 +1,8 @@
import { createAuthClient } from "better-auth/react";
+import { keys } from "./keys";
+
+const { NEXT_PUBLIC_BETTER_AUTH_URL } = keys();
export const { signIn, signUp, useSession } = createAuthClient({
- baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL!,
-}); \ No newline at end of file
+ baseURL: NEXT_PUBLIC_BETTER_AUTH_URL,
+});
diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts
index f0676f1f..a4f5fd44 100644
--- a/packages/auth/src/index.ts
+++ b/packages/auth/src/index.ts
@@ -2,4 +2,7 @@
export * from "./server";
// Re-export client auth
-export * from "./client"; \ No newline at end of file
+export * from "./client";
+
+// Re-export keys
+export * from "./keys"; \ No newline at end of file
diff --git a/packages/auth/src/keys.ts b/packages/auth/src/keys.ts
new file mode 100644
index 00000000..919eaccb
--- /dev/null
+++ b/packages/auth/src/keys.ts
@@ -0,0 +1,20 @@
+import { createEnv } from "@t3-oss/env-nextjs";
+import { z } from "zod";
+
+export const keys = () =>
+ createEnv({
+ server: {
+ BETTER_AUTH_SECRET: z.string(),
+ GOOGLE_CLIENT_ID: z.string(),
+ GOOGLE_CLIENT_SECRET: z.string(),
+ },
+ client: {
+ NEXT_PUBLIC_BETTER_AUTH_URL: z.string().url(),
+ },
+ runtimeEnv: {
+ NEXT_PUBLIC_BETTER_AUTH_URL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL,
+ BETTER_AUTH_SECRET: process.env.BETTER_AUTH_SECRET,
+ GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
+ GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
+ },
+ });
diff --git a/packages/auth/src/server.ts b/packages/auth/src/server.ts
index 668d27de..5872962c 100644
--- a/packages/auth/src/server.ts
+++ b/packages/auth/src/server.ts
@@ -1,13 +1,16 @@
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@opencut/db";
+import { keys } from "./keys";
+
+const { NEXT_PUBLIC_BETTER_AUTH_URL, BETTER_AUTH_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET } = keys()
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
usePlural: true,
}),
- secret: process.env.BETTER_AUTH_SECRET,
+ secret: BETTER_AUTH_SECRET,
user: {
deleteUser: {
enabled: true,
@@ -18,11 +21,11 @@ export const auth = betterAuth({
},
socialProviders: {
google: {
- clientId: process.env.GOOGLE_CLIENT_ID as string,
- clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
+ clientId: GOOGLE_CLIENT_ID,
+ clientSecret: GOOGLE_CLIENT_SECRET,
},
},
- baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL,
+ baseURL: NEXT_PUBLIC_BETTER_AUTH_URL,
appName: "OpenCut",
trustedOrigins: ["http://localhost:3000"],
});
diff --git a/packages/db/drizzle.config.ts b/packages/db/drizzle.config.ts
index b003e31a..d661c455 100644
--- a/packages/db/drizzle.config.ts
+++ b/packages/db/drizzle.config.ts
@@ -1,17 +1,16 @@
import type { Config } from "drizzle-kit";
import * as dotenv from "dotenv";
+import { keys } from "./src/keys";
+
+const { NODE_ENV, DATABASE_URL } = keys();
// Load the right env file based on environment
-if (process.env.NODE_ENV === "production") {
+if (NODE_ENV === "production") {
dotenv.config({ path: ".env.production" });
} else {
dotenv.config({ path: ".env.local" });
}
-if (!process.env.DATABASE_URL) {
- throw new Error("DATABASE_URL is not set");
-}
-
export default {
schema: "./src/schema.ts",
dialect: "postgresql",
@@ -19,8 +18,8 @@ export default {
table: "drizzle_migrations",
},
dbCredentials: {
- url: process.env.DATABASE_URL,
+ url: DATABASE_URL,
},
out: "./migrations",
- strict: process.env.NODE_ENV === "production",
-} satisfies Config; \ No newline at end of file
+ strict: NODE_ENV === "production",
+} satisfies Config;
diff --git a/packages/db/package.json b/packages/db/package.json
index 94990dc9..aebbbc90 100644
--- a/packages/db/package.json
+++ b/packages/db/package.json
@@ -7,7 +7,8 @@
"exports": {
".": "./src/index.ts",
"./schema": "./src/schema.ts",
- "./drizzle.config": "./drizzle.config.ts"
+ "./drizzle.config": "./drizzle.config.ts",
+ "./keys": "./src/keys.ts"
},
"scripts": {
"db:generate": "drizzle-kit generate",
@@ -16,8 +17,10 @@
"db:studio": "drizzle-kit studio"
},
"dependencies": {
+ "@t3-oss/env-nextjs": "^0.13.8",
"drizzle-orm": "^0.44.2",
- "postgres": "^3.4.5"
+ "postgres": "^3.4.5",
+ "zod": "^4.0.5"
},
"devDependencies": {
"drizzle-kit": "^0.31.1",
diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts
index b480f566..9b395ab6 100644
--- a/packages/db/src/index.ts
+++ b/packages/db/src/index.ts
@@ -1,17 +1,15 @@
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import * as schema from "./schema";
+import { keys } from "./keys";
+const { DATABASE_URL } = keys();
// Create a lazy database instance that only initializes when accessed
let _db: ReturnType<typeof drizzle> | null = null;
function getDb() {
- if (!process.env.DATABASE_URL) {
- throw new Error("DATABASE_URL is not set");
- }
-
if (!_db) {
- const client = postgres(process.env.DATABASE_URL);
+ const client = postgres(DATABASE_URL);
_db = drizzle(client, { schema });
}
diff --git a/packages/db/src/keys.ts b/packages/db/src/keys.ts
new file mode 100644
index 00000000..65983416
--- /dev/null
+++ b/packages/db/src/keys.ts
@@ -0,0 +1,19 @@
+import { createEnv } from "@t3-oss/env-nextjs";
+import { z } from "zod";
+
+export const keys = () =>
+ createEnv({
+ server: {
+ NODE_ENV: z
+ .enum(["development", "production", "test"])
+ .default("development"),
+ DATABASE_URL: z
+ .string()
+ .startsWith("postgres://")
+ .or(z.string().startsWith("postgresql://")),
+ },
+ runtimeEnv: {
+ NODE_ENV: process.env.NODE_ENV,
+ DATABASE_URL: process.env.DATABASE_URL,
+ },
+ });