mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
feat: integrate @t3-oss/env for environment variable management across the application
This commit is contained in:
@@ -1,23 +1,20 @@
|
|||||||
import type { Config } from "drizzle-kit";
|
import type { Config } from "drizzle-kit";
|
||||||
import * as dotenv from "dotenv";
|
import * as dotenv from "dotenv";
|
||||||
|
import { env } from "@/env";
|
||||||
|
|
||||||
// Load the right env file based on environment
|
// Load the right env file based on environment
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (env.NODE_ENV === "production") {
|
||||||
dotenv.config({ path: ".env.production" });
|
dotenv.config({ path: ".env.production" });
|
||||||
} else {
|
} else {
|
||||||
dotenv.config({ path: ".env.local" });
|
dotenv.config({ path: ".env.local" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process.env.DATABASE_URL) {
|
|
||||||
throw new Error("DATABASE_URL is not set");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
schema: "../../packages/db/src/schema.ts",
|
schema: "../../packages/db/src/schema.ts",
|
||||||
dialect: "postgresql",
|
dialect: "postgresql",
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
url: process.env.DATABASE_URL,
|
url: env.DATABASE_URL,
|
||||||
},
|
},
|
||||||
out: "./migrations",
|
out: "./migrations",
|
||||||
strict: process.env.NODE_ENV === "production",
|
strict: env.NODE_ENV === "production",
|
||||||
} satisfies Config;
|
} satisfies Config;
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
"@hookform/resolvers": "^3.9.1",
|
"@hookform/resolvers": "^3.9.1",
|
||||||
"@opencut/auth": "workspace:*",
|
"@opencut/auth": "workspace:*",
|
||||||
"@opencut/db": "workspace:*",
|
"@opencut/db": "workspace:*",
|
||||||
|
"@t3-oss/env-core": "^0.13.8",
|
||||||
|
"@t3-oss/env-nextjs": "^0.13.8",
|
||||||
"@upstash/ratelimit": "^2.0.5",
|
"@upstash/ratelimit": "^2.0.5",
|
||||||
"@upstash/redis": "^1.35.0",
|
"@upstash/redis": "^1.35.0",
|
||||||
"@vercel/analytics": "^1.4.1",
|
"@vercel/analytics": "^1.4.1",
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ import { usePlaybackStore } from "@/stores/playback-store";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import type { TimelineElement } from "@/types/timeline";
|
import type { TimelineElement } from "@/types/timeline";
|
||||||
|
import { env } from "@/env";
|
||||||
|
|
||||||
// Only show in development
|
// Only show in development
|
||||||
const SHOW_DEBUG_INFO = process.env.NODE_ENV === "development";
|
const SHOW_DEBUG_INFO = env.NODE_ENV === "development";
|
||||||
|
|
||||||
interface ActiveElement {
|
interface ActiveElement {
|
||||||
element: TimelineElement;
|
element: TimelineElement;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useSession } from "@opencut/auth/client";
|
|||||||
import { getStars } from "@/lib/fetch-github-stars";
|
import { getStars } from "@/lib/fetch-github-stars";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import { env } from "@/env";
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
@@ -40,7 +41,7 @@ export function Header() {
|
|||||||
Contributors
|
Contributors
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{process.env.NODE_ENV === "development" ? (
|
{env.NODE_ENV === "development" ? (
|
||||||
<Link href="/projects">
|
<Link href="/projects">
|
||||||
<Button size="sm" className="text-sm ml-4">
|
<Button size="sm" className="text-sm ml-4">
|
||||||
Projects
|
Projects
|
||||||
|
|||||||
@@ -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,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
// lib/rate-limit.ts
|
// lib/rate-limit.ts
|
||||||
import { Ratelimit } from "@upstash/ratelimit";
|
import { Ratelimit } from "@upstash/ratelimit";
|
||||||
import { Redis } from "@upstash/redis";
|
import { Redis } from "@upstash/redis";
|
||||||
|
import { env } from "@/env";
|
||||||
|
|
||||||
const redis = new Redis({
|
const redis = new Redis({
|
||||||
url: process.env.UPSTASH_REDIS_REST_URL!,
|
url: env.UPSTASH_REDIS_REST_URL,
|
||||||
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
token: env.UPSTASH_REDIS_REST_TOKEN,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const waitlistRateLimit = new Ratelimit({
|
export const waitlistRateLimit = new Ratelimit({
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import type { NextRequest } from "next/server";
|
import type { NextRequest } from "next/server";
|
||||||
|
import { env } from "./env";
|
||||||
|
|
||||||
export async function middleware(request: NextRequest) {
|
export async function middleware(request: NextRequest) {
|
||||||
// Handle fuckcapcut.com domain redirect
|
// Handle fuckcapcut.com domain redirect
|
||||||
@@ -9,7 +10,7 @@ export async function middleware(request: NextRequest) {
|
|||||||
|
|
||||||
const path = request.nextUrl.pathname;
|
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);
|
const homeUrl = new URL("/", request.url);
|
||||||
homeUrl.searchParams.set("redirect", request.url);
|
homeUrl.searchParams.set("redirect", request.url);
|
||||||
return NextResponse.redirect(homeUrl);
|
return NextResponse.redirect(homeUrl);
|
||||||
|
|||||||
@@ -7,13 +7,16 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./client": "./src/client.ts",
|
"./client": "./src/client.ts",
|
||||||
"./server": "./src/server.ts"
|
"./server": "./src/server.ts",
|
||||||
|
"./keys": "./src/keys.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@opencut/db": "workspace:*",
|
||||||
|
"@t3-oss/env-nextjs": "^0.13.8",
|
||||||
"better-auth": "^1.1.1",
|
"better-auth": "^1.1.1",
|
||||||
"@opencut/db": "workspace:*"
|
"zod": "^4.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.10.2"
|
"@types/node": "^22.10.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import { createAuthClient } from "better-auth/react";
|
import { createAuthClient } from "better-auth/react";
|
||||||
|
import { keys } from "./keys";
|
||||||
|
|
||||||
|
const { NEXT_PUBLIC_BETTER_AUTH_URL } = keys();
|
||||||
|
|
||||||
export const { signIn, signUp, useSession } = createAuthClient({
|
export const { signIn, signUp, useSession } = createAuthClient({
|
||||||
baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL!,
|
baseURL: NEXT_PUBLIC_BETTER_AUTH_URL,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,4 +2,7 @@
|
|||||||
export * from "./server";
|
export * from "./server";
|
||||||
|
|
||||||
// Re-export client auth
|
// Re-export client auth
|
||||||
export * from "./client";
|
export * from "./client";
|
||||||
|
|
||||||
|
// Re-export keys
|
||||||
|
export * from "./keys";
|
||||||
@@ -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,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
import { betterAuth } from "better-auth";
|
import { betterAuth } from "better-auth";
|
||||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||||
import { db } from "@opencut/db";
|
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({
|
export const auth = betterAuth({
|
||||||
database: drizzleAdapter(db, {
|
database: drizzleAdapter(db, {
|
||||||
provider: "pg",
|
provider: "pg",
|
||||||
usePlural: true,
|
usePlural: true,
|
||||||
}),
|
}),
|
||||||
secret: process.env.BETTER_AUTH_SECRET,
|
secret: BETTER_AUTH_SECRET,
|
||||||
user: {
|
user: {
|
||||||
deleteUser: {
|
deleteUser: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -18,11 +21,11 @@ export const auth = betterAuth({
|
|||||||
},
|
},
|
||||||
socialProviders: {
|
socialProviders: {
|
||||||
google: {
|
google: {
|
||||||
clientId: process.env.GOOGLE_CLIENT_ID as string,
|
clientId: GOOGLE_CLIENT_ID,
|
||||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
|
clientSecret: GOOGLE_CLIENT_SECRET,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL,
|
baseURL: NEXT_PUBLIC_BETTER_AUTH_URL,
|
||||||
appName: "OpenCut",
|
appName: "OpenCut",
|
||||||
trustedOrigins: ["http://localhost:3000"],
|
trustedOrigins: ["http://localhost:3000"],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import type { Config } from "drizzle-kit";
|
import type { Config } from "drizzle-kit";
|
||||||
import * as dotenv from "dotenv";
|
import * as dotenv from "dotenv";
|
||||||
|
import { keys } from "./src/keys";
|
||||||
|
|
||||||
|
const { NODE_ENV, DATABASE_URL } = keys();
|
||||||
|
|
||||||
// Load the right env file based on environment
|
// Load the right env file based on environment
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (NODE_ENV === "production") {
|
||||||
dotenv.config({ path: ".env.production" });
|
dotenv.config({ path: ".env.production" });
|
||||||
} else {
|
} else {
|
||||||
dotenv.config({ path: ".env.local" });
|
dotenv.config({ path: ".env.local" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process.env.DATABASE_URL) {
|
|
||||||
throw new Error("DATABASE_URL is not set");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
schema: "./src/schema.ts",
|
schema: "./src/schema.ts",
|
||||||
dialect: "postgresql",
|
dialect: "postgresql",
|
||||||
@@ -19,8 +18,8 @@ export default {
|
|||||||
table: "drizzle_migrations",
|
table: "drizzle_migrations",
|
||||||
},
|
},
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
url: process.env.DATABASE_URL,
|
url: DATABASE_URL,
|
||||||
},
|
},
|
||||||
out: "./migrations",
|
out: "./migrations",
|
||||||
strict: process.env.NODE_ENV === "production",
|
strict: NODE_ENV === "production",
|
||||||
} satisfies Config;
|
} satisfies Config;
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./schema": "./src/schema.ts",
|
"./schema": "./src/schema.ts",
|
||||||
"./drizzle.config": "./drizzle.config.ts"
|
"./drizzle.config": "./drizzle.config.ts",
|
||||||
|
"./keys": "./src/keys.ts"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
@@ -16,8 +17,10 @@
|
|||||||
"db:studio": "drizzle-kit studio"
|
"db:studio": "drizzle-kit studio"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@t3-oss/env-nextjs": "^0.13.8",
|
||||||
"drizzle-orm": "^0.44.2",
|
"drizzle-orm": "^0.44.2",
|
||||||
"postgres": "^3.4.5"
|
"postgres": "^3.4.5",
|
||||||
|
"zod": "^4.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"drizzle-kit": "^0.31.1",
|
"drizzle-kit": "^0.31.1",
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import { drizzle } from "drizzle-orm/postgres-js";
|
import { drizzle } from "drizzle-orm/postgres-js";
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
import * as schema from "./schema";
|
import * as schema from "./schema";
|
||||||
|
import { keys } from "./keys";
|
||||||
|
|
||||||
|
const { DATABASE_URL } = keys();
|
||||||
// Create a lazy database instance that only initializes when accessed
|
// Create a lazy database instance that only initializes when accessed
|
||||||
let _db: ReturnType<typeof drizzle> | null = null;
|
let _db: ReturnType<typeof drizzle> | null = null;
|
||||||
|
|
||||||
function getDb() {
|
function getDb() {
|
||||||
if (!process.env.DATABASE_URL) {
|
|
||||||
throw new Error("DATABASE_URL is not set");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_db) {
|
if (!_db) {
|
||||||
const client = postgres(process.env.DATABASE_URL);
|
const client = postgres(DATABASE_URL);
|
||||||
_db = drizzle(client, { schema });
|
_db = drizzle(client, { schema });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user