diff --git a/apps/web/.env b/apps/web/.env deleted file mode 120000 index c7360fb82d..0000000000 --- a/apps/web/.env +++ /dev/null @@ -1 +0,0 @@ -../../.env \ No newline at end of file diff --git a/apps/web/app/(app)/components/FormbricksClient.tsx b/apps/web/app/(app)/components/FormbricksClient.tsx index fdc54de3b4..4b50e91034 100644 --- a/apps/web/app/(app)/components/FormbricksClient.tsx +++ b/apps/web/app/(app)/components/FormbricksClient.tsx @@ -1,6 +1,6 @@ "use client"; -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; import { formbricksEnabled } from "@/app/lib/formbricks"; import formbricks from "@formbricks/js"; import { useEffect } from "react"; diff --git a/apps/web/app/(app)/components/PosthogIdentify.tsx b/apps/web/app/(app)/components/PosthogIdentify.tsx index dc055535d5..57444b192f 100644 --- a/apps/web/app/(app)/components/PosthogIdentify.tsx +++ b/apps/web/app/(app)/components/PosthogIdentify.tsx @@ -1,5 +1,5 @@ "use client"; -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; import type { Session } from "next-auth"; import { usePostHog } from "posthog-js/react"; import { useEffect } from "react"; diff --git a/apps/web/app/(app)/onboarding/components/Objective.tsx b/apps/web/app/(app)/onboarding/components/Objective.tsx index 269dc067d3..28ae4c978a 100644 --- a/apps/web/app/(app)/onboarding/components/Objective.tsx +++ b/apps/web/app/(app)/onboarding/components/Objective.tsx @@ -1,7 +1,7 @@ "use client"; import { updateProfileAction } from "@/app/(app)/onboarding/actions"; -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; import { formbricksEnabled, updateResponse } from "@/app/lib/formbricks"; import { cn } from "@formbricks/lib/cn"; import { TProfileObjective } from "@formbricks/types/profile"; diff --git a/apps/web/app/(app)/onboarding/components/Role.tsx b/apps/web/app/(app)/onboarding/components/Role.tsx index 54e71481a9..fa31635058 100644 --- a/apps/web/app/(app)/onboarding/components/Role.tsx +++ b/apps/web/app/(app)/onboarding/components/Role.tsx @@ -1,8 +1,8 @@ "use client"; import { updateProfileAction } from "@/app/(app)/onboarding/actions"; +import { env } from "@formbricks/lib/env.mjs"; import { createResponse, formbricksEnabled } from "@/app/lib/formbricks"; -import { env } from "@/env.mjs"; import { cn } from "@formbricks/lib/cn"; import { Button } from "@formbricks/ui/Button"; import { useEffect, useRef, useState } from "react"; diff --git a/apps/web/app/(auth)/invite/page.tsx b/apps/web/app/(auth)/invite/page.tsx index 3b0de3a184..a6df22805c 100644 --- a/apps/web/app/(auth)/invite/page.tsx +++ b/apps/web/app/(auth)/invite/page.tsx @@ -10,7 +10,7 @@ import { UsedContent, RightAccountContent, } from "./components/InviteContentComponents"; -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; export default async function JoinTeam({ searchParams }) { const currentUser = await getServerSession(authOptions); diff --git a/apps/web/app/api/v1/client/[environmentId]/storage/local/route.ts b/apps/web/app/api/v1/client/[environmentId]/storage/local/route.ts index 1e60f7c520..1dbb88e718 100644 --- a/apps/web/app/api/v1/client/[environmentId]/storage/local/route.ts +++ b/apps/web/app/api/v1/client/[environmentId]/storage/local/route.ts @@ -6,7 +6,7 @@ import { NextRequest, NextResponse } from "next/server"; import { headers } from "next/headers"; import { putFileToLocalStorage } from "@formbricks/lib/storage/service"; import { UPLOADS_DIR } from "@formbricks/lib/constants"; -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; import { getSurvey } from "@formbricks/lib/survey/service"; import { getTeamByEnvironmentId } from "@formbricks/lib/team/service"; import { validateLocalSignedUrl } from "@formbricks/lib/crypto"; diff --git a/apps/web/app/api/v1/management/storage/local/route.ts b/apps/web/app/api/v1/management/storage/local/route.ts index 20b1ed1e08..55d8bafdc4 100644 --- a/apps/web/app/api/v1/management/storage/local/route.ts +++ b/apps/web/app/api/v1/management/storage/local/route.ts @@ -10,7 +10,7 @@ import { authOptions } from "@formbricks/lib/authOptions"; import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth"; import { UPLOADS_DIR } from "@formbricks/lib/constants"; import { validateLocalSignedUrl } from "@formbricks/lib/crypto"; -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; export async function POST(req: NextRequest): Promise { const accessType = "public"; // public files are accessible by anyone diff --git a/apps/web/app/lib/formbricks.ts b/apps/web/app/lib/formbricks.ts index e56580f8a8..805af77660 100644 --- a/apps/web/app/lib/formbricks.ts +++ b/apps/web/app/lib/formbricks.ts @@ -1,5 +1,5 @@ import formbricks from "@formbricks/js"; -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; export const formbricksEnabled = typeof env.NEXT_PUBLIC_FORMBRICKS_API_HOST && env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID; diff --git a/apps/web/app/lib/singleUseSurveys.ts b/apps/web/app/lib/singleUseSurveys.ts index c1b076c021..5c3e9e14a5 100644 --- a/apps/web/app/lib/singleUseSurveys.ts +++ b/apps/web/app/lib/singleUseSurveys.ts @@ -1,4 +1,4 @@ -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; import { decryptAES128, symmetricDecrypt, symmetricEncrypt } from "@formbricks/lib/crypto"; import cuid2 from "@paralleldrive/cuid2"; diff --git a/apps/web/app/storage/[environmentId]/[accessType]/[fileName]/lib/getFile.ts b/apps/web/app/storage/[environmentId]/[accessType]/[fileName]/lib/getFile.ts index 025f03fc3d..aa2bb82f78 100644 --- a/apps/web/app/storage/[environmentId]/[accessType]/[fileName]/lib/getFile.ts +++ b/apps/web/app/storage/[environmentId]/[accessType]/[fileName]/lib/getFile.ts @@ -1,4 +1,4 @@ -import { env } from "@/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; import { responses } from "@/app/lib/api/response"; import { UPLOADS_DIR } from "@formbricks/lib/constants"; import { getLocalFile, getS3File } from "@formbricks/lib/storage/service"; diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index f534c1b24c..e397a0ea4a 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -1,6 +1,6 @@ import { createId } from "@paralleldrive/cuid2"; import { withSentryConfig } from "@sentry/nextjs"; -import "./env.mjs"; +import "@formbricks/lib/env.mjs"; /** @type {import('next').NextConfig} */ diff --git a/apps/web/package.json b/apps/web/package.json index 5fc34ce7f0..d56e372975 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -28,9 +28,9 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@react-email/components": "^0.0.9", "@sentry/nextjs": "^7.77.0", - "@t3-oss/env-nextjs": "^0.7.1", "@vercel/og": "^0.5.20", "bcryptjs": "^2.4.3", + "dotenv": "^16.3.1", "encoding": "^0.1.13", "framer-motion": "10.16.4", "googleapis": "^128.0.0", diff --git a/packages/lib/authOptions.ts b/packages/lib/authOptions.ts index 6e57fda7fc..d8dc76b5fc 100644 --- a/packages/lib/authOptions.ts +++ b/packages/lib/authOptions.ts @@ -1,4 +1,4 @@ -import { env } from "../../apps/web/env.mjs"; +import { env } from "./env.mjs"; import { verifyPassword } from "@/app/lib/auth"; import { prisma } from "@formbricks/database"; import { EMAIL_VERIFICATION_DISABLED } from "./constants"; diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts index 4ab78d2d02..22d19b559b 100644 --- a/packages/lib/constants.ts +++ b/packages/lib/constants.ts @@ -1,61 +1,59 @@ import "server-only"; import path from "path"; - -export const IS_FORMBRICKS_CLOUD = process.env.IS_FORMBRICKS_CLOUD === "1"; +import { env } from "./env.mjs"; +export const IS_FORMBRICKS_CLOUD = env.IS_FORMBRICKS_CLOUD === "1"; export const REVALIDATION_INTERVAL = 0; //TODO: find a good way to cache and revalidate data when it changes export const SERVICES_REVALIDATION_INTERVAL = 60 * 30; // 30 minutes export const MAU_LIMIT = IS_FORMBRICKS_CLOUD ? 9000 : 1000000; // URLs export const WEBAPP_URL = - process.env.WEBAPP_URL || - (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : false) || - "http://localhost:3000"; + env.WEBAPP_URL || (env.VERCEL_URL ? `https://${env.VERCEL_URL}` : false) || "http://localhost:3000"; -export const SHORT_URL_BASE = process.env.SHORT_URL_BASE ? process.env.SHORT_URL_BASE : WEBAPP_URL; +export const SHORT_URL_BASE = env.SHORT_URL_BASE ? env.SHORT_URL_BASE : WEBAPP_URL; // encryption keys -export const FORMBRICKS_ENCRYPTION_KEY = process.env.FORMBRICKS_ENCRYPTION_KEY || undefined; -export const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; +export const FORMBRICKS_ENCRYPTION_KEY = env.FORMBRICKS_ENCRYPTION_KEY || undefined; +export const ENCRYPTION_KEY = env.ENCRYPTION_KEY; // Other export const INTERNAL_SECRET = process.env.INTERNAL_SECRET || ""; -export const CRON_SECRET = process.env.CRON_SECRET; +export const CRON_SECRET = env.CRON_SECRET; export const DEFAULT_BRAND_COLOR = "#64748b"; -export const PRIVACY_URL = process.env.PRIVACY_URL; -export const TERMS_URL = process.env.TERMS_URL; -export const IMPRINT_URL = process.env.IMPRINT_URL; +export const PRIVACY_URL = env.PRIVACY_URL; +export const TERMS_URL = env.TERMS_URL; +export const IMPRINT_URL = env.IMPRINT_URL; -export const PASSWORD_RESET_DISABLED = process.env.PASSWORD_RESET_DISABLED === "1"; -export const EMAIL_VERIFICATION_DISABLED = process.env.EMAIL_VERIFICATION_DISABLED === "1"; -export const GOOGLE_OAUTH_ENABLED = process.env.GOOGLE_AUTH_ENABLED === "1"; -export const GITHUB_OAUTH_ENABLED = process.env.GITHUB_AUTH_ENABLED === "1"; -export const AZURE_OAUTH_ENABLED = process.env.AZUREAD_AUTH_ENABLED === "1"; +export const PASSWORD_RESET_DISABLED = env.PASSWORD_RESET_DISABLED === "1"; +export const EMAIL_VERIFICATION_DISABLED = env.EMAIL_VERIFICATION_DISABLED === "1"; +export const GOOGLE_OAUTH_ENABLED = env.GOOGLE_AUTH_ENABLED === "1"; +export const GITHUB_OAUTH_ENABLED = env.GITHUB_AUTH_ENABLED === "1"; +export const AZURE_OAUTH_ENABLED = env.AZUREAD_AUTH_ENABLED === "1"; -export const GITHUB_ID = process.env.GITHUB_ID; -export const GITHUB_SECRET = process.env.GITHUB_SECRET; -export const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID; -export const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET; +export const GITHUB_ID = env.GITHUB_ID; +export const GITHUB_SECRET = env.GITHUB_SECRET; +export const GOOGLE_CLIENT_ID = env.GOOGLE_CLIENT_ID; +export const GOOGLE_CLIENT_SECRET = env.GOOGLE_CLIENT_SECRET; -export const SIGNUP_ENABLED = process.env.SIGNUP_DISABLED !== "1"; -export const INVITE_DISABLED = process.env.INVITE_DISABLED === "1"; +export const SIGNUP_ENABLED = env.SIGNUP_DISABLED !== "1"; +export const INVITE_DISABLED = env.INVITE_DISABLED === "1"; -export const GOOGLE_SHEETS_CLIENT_ID = process.env.GOOGLE_SHEETS_CLIENT_ID; -export const GOOGLE_SHEETS_CLIENT_SECRET = process.env.GOOGLE_SHEETS_CLIENT_SECRET; -export const GOOGLE_SHEETS_REDIRECT_URL = process.env.GOOGLE_SHEETS_REDIRECT_URL; +export const GOOGLE_SHEETS_CLIENT_ID = env.GOOGLE_SHEETS_CLIENT_ID; +export const GOOGLE_SHEETS_CLIENT_SECRET = env.GOOGLE_SHEETS_CLIENT_SECRET; +export const GOOGLE_SHEETS_REDIRECT_URL = env.GOOGLE_SHEETS_REDIRECT_URL; -export const AIRTABLE_CLIENT_ID = process.env.AIRTABLE_CLIENT_ID; +export const AIRTABLE_CLIENT_ID = env.AIRTABLE_CLIENT_ID; -export const SMTP_HOST = process.env.SMTP_HOST; -export const SMTP_PORT = process.env.SMTP_PORT; -export const SMTP_SECURE_ENABLED = process.env.SMTP_SECURE_ENABLED === "1"; -export const SMTP_USER = process.env.SMTP_USER; -export const SMTP_PASSWORD = process.env.SMTP_PASSWORD; -export const MAIL_FROM = process.env.MAIL_FROM; +export const SMTP_HOST = env.SMTP_HOST; +export const SMTP_PORT = env.SMTP_PORT; +export const SMTP_SECURE_ENABLED = env.SMTP_SECURE_ENABLED === "1"; +export const SMTP_USER = env.SMTP_USER; +export const SMTP_PASSWORD = env.SMTP_PASSWORD; +export const MAIL_FROM = env.MAIL_FROM; -export const NEXTAUTH_SECRET = process.env.NEXTAUTH_SECRET; -export const NEXTAUTH_URL = process.env.NEXTAUTH_URL; +export const NEXTAUTH_SECRET = env.NEXTAUTH_SECRET; +export const NEXTAUTH_URL = env.NEXTAUTH_URL; export const ITEMS_PER_PAGE = 50; export const RESPONSES_PER_PAGE = 10; export const TEXT_RESPONSES_PER_PAGE = 5; @@ -68,12 +66,7 @@ export const MAX_SIZES = { pro: 1024 * 1024 * 1024, // 1GB } as const; export const IS_S3_CONFIGURED: boolean = - process.env.S3_ACCESS_KEY && - process.env.S3_SECRET_KEY && - process.env.S3_REGION && - process.env.S3_BUCKET_NAME - ? true - : false; + env.S3_ACCESS_KEY && env.S3_SECRET_KEY && env.S3_REGION && env.S3_BUCKET_NAME ? true : false; export const LOCAL_UPLOAD_URL = { public: new URL(`${WEBAPP_URL}/api/v1/management/storage/local`).href, private: new URL(`${WEBAPP_URL}/api/v1/client/storage/local`).href, @@ -83,4 +76,4 @@ export const LOCAL_UPLOAD_URL = { export const PRICING_USERTARGETING_FREE_MTU = 2500; export const PRICING_APPSURVEYS_FREE_RESPONSES = 250; // Enterprise License constant -export const ENTERPRISE_LICENSE_KEY = process.env.ENTERPRISE_LICENSE_KEY; +export const ENTERPRISE_LICENSE_KEY = env.ENTERPRISE_LICENSE_KEY; diff --git a/apps/web/env.mjs b/packages/lib/env.mjs similarity index 98% rename from apps/web/env.mjs rename to packages/lib/env.mjs index e7358258f4..d2dee28f84 100644 --- a/apps/web/env.mjs +++ b/packages/lib/env.mjs @@ -1,5 +1,7 @@ import { createEnv } from "@t3-oss/env-nextjs"; import { z } from "zod"; +import { config } from 'dotenv'; +config({ path: '../../.env' }); export const env = createEnv({ /* diff --git a/packages/lib/jwt.ts b/packages/lib/jwt.ts index e701f200b4..dcc6a9076f 100644 --- a/packages/lib/jwt.ts +++ b/packages/lib/jwt.ts @@ -1,6 +1,6 @@ import jwt, { JwtPayload } from "jsonwebtoken"; import { prisma } from "@formbricks/database"; -import { env } from "@/env.mjs"; +import { env } from "./env.mjs"; export function createToken(userId: string, userEmail: string, options = {}): string { return jwt.sign({ id: userId }, env.NEXTAUTH_SECRET + userEmail, options); diff --git a/packages/lib/package.json b/packages/lib/package.json index e2a7191bff..17b00f814b 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -15,6 +15,7 @@ "@formbricks/api": "*", "@aws-sdk/client-s3": "3.433.0", "@aws-sdk/s3-request-presigner": "3.433.0", + "@t3-oss/env-nextjs": "^0.7.1", "mime": "3.0.0", "@formbricks/database": "*", "@formbricks/types": "*", diff --git a/packages/lib/storage/service.ts b/packages/lib/storage/service.ts index 45b684b3dd..8f9a6597b2 100644 --- a/packages/lib/storage/service.ts +++ b/packages/lib/storage/service.ts @@ -10,7 +10,7 @@ import { createPresignedPost, PresignedPostOptions } from "@aws-sdk/s3-presigned import { access, mkdir, writeFile, readFile, unlink, rmdir } from "fs/promises"; import { join } from "path"; import mime from "mime"; -import { env } from "@/env.mjs"; +import { env } from "../env.mjs"; import { IS_S3_CONFIGURED, LOCAL_UPLOAD_URL, MAX_SIZES, UPLOADS_DIR, WEBAPP_URL } from "../constants"; import { unstable_cache } from "next/cache"; import { storageCache } from "./cache"; diff --git a/packages/ui/PostHogClient/index.tsx b/packages/ui/PostHogClient/index.tsx index 079f80fc29..5f3e20477a 100644 --- a/packages/ui/PostHogClient/index.tsx +++ b/packages/ui/PostHogClient/index.tsx @@ -1,6 +1,6 @@ "use client"; -import { env } from "../../../apps/web/env.mjs"; +import { env } from "@formbricks/lib/env.mjs"; import { usePathname, useSearchParams } from "next/navigation"; import posthog from "posthog-js"; import { PostHogProvider } from "posthog-js/react"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eaa0463eec..3ad29bd63b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + importers: .: @@ -328,15 +332,15 @@ importers: '@sentry/nextjs': specifier: ^7.77.0 version: 7.77.0(encoding@0.1.13)(next@13.5.6)(react@18.2.0)(webpack@5.89.0) - '@t3-oss/env-nextjs': - specifier: ^0.7.1 - version: 0.7.1(zod@3.22.4) '@vercel/og': specifier: ^0.5.20 version: 0.5.20 bcryptjs: specifier: ^2.4.3 version: 2.4.3 + dotenv: + specifier: ^16.3.1 + version: 16.3.1 encoding: specifier: ^0.1.13 version: 0.1.13 @@ -522,7 +526,7 @@ importers: version: 9.0.0(eslint@8.52.0) eslint-config-turbo: specifier: latest - version: 1.10.16(eslint@8.52.0) + version: 1.8.8(eslint@8.52.0) eslint-plugin-react: specifier: 7.33.2 version: 7.33.2(eslint@8.52.0) @@ -622,6 +626,9 @@ importers: '@paralleldrive/cuid2': specifier: ^2.2.2 version: 2.2.2 + '@t3-oss/env-nextjs': + specifier: ^0.7.1 + version: 0.7.1(zod@3.22.4) aws-crt: specifier: ^1.18.1 version: 1.18.3 @@ -12836,13 +12843,13 @@ packages: resolution: {integrity: sha512-NB/L/1Y30qyJcG5xZxCJKW/+bqyj+llbcCwo9DEz8bESIP0SLTOQ8T1DWCCFc+wJ61AMEstj4511PSScqMMfCw==} dev: true - /eslint-config-turbo@1.10.16(eslint@8.52.0): - resolution: {integrity: sha512-O3NQI72bQHV7FvSC6lWj66EGx8drJJjuT1kuInn6nbMLOHdMBhSUX/8uhTAlHRQdlxZk2j9HtgFCIzSc93w42g==} + /eslint-config-turbo@1.8.8(eslint@8.52.0): + resolution: {integrity: sha512-+yT22sHOT5iC1sbBXfLIdXfbZuiv9bAyOXsxTxFCWelTeFFnANqmuKB3x274CFvf7WRuZ/vYP/VMjzU9xnFnxA==} peerDependencies: eslint: '>6.6.0' dependencies: eslint: 8.52.0 - eslint-plugin-turbo: 1.10.16(eslint@8.52.0) + eslint-plugin-turbo: 1.8.8(eslint@8.52.0) dev: true /eslint-import-resolver-node@0.3.9: @@ -13044,12 +13051,11 @@ packages: - typescript dev: true - /eslint-plugin-turbo@1.10.16(eslint@8.52.0): - resolution: {integrity: sha512-ZjrR88MTN64PNGufSEcM0tf+V1xFYVbeiMeuIqr0aiABGomxFLo4DBkQ7WI4WzkZtWQSIA2sP+yxqSboEfL9MQ==} + /eslint-plugin-turbo@1.8.8(eslint@8.52.0): + resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==} peerDependencies: eslint: '>6.6.0' dependencies: - dotenv: 16.0.3 eslint: 8.52.0 dev: true @@ -23726,7 +23732,3 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false