Skip to content

Commit

Permalink
Composable environment variables (#332)
Browse files Browse the repository at this point in the history
* Extend Vercel preset

* Move VERCEL_PROJECT_PRODUCTION_URL to Server

* Remove duplicate keys

* Install zod and t3-env in relevant packages

* Migrate auth keys

* Migrate AI keys

* Rename key exports

* Migrate Analytics keys

* Migrate Core keys

* Migrate CMS keys

* Migrate Collaboration keys

* Migrate Flags keys

* Migrate Email keys

* Migrate Database keys

* Migrate Observability keys

* Migrate Payments keys

* Migrate Security keys

* Migrate Webhooks keys

* Migrate more core keys

* Migrate Storage keys

* Update index.ts

* Update index.tsx

* Start breaking apart mono-env

* Migrate API env

* Migrate Web env

* Remove Toolbar from Design System and Next Config

* Re-implement Vercel Toolbar

* Remove repo/env from design-system

* Fix typo

* Co-locate observability handlers

* Switch to loose env mode

* Update pnpm-lock.yaml

* Fix rate limit keys

* Misc fixes

* Remove unused web deps

* Remove next-secure-headers

* Co-locate sentry client config

* Remove unused dep

* Fix typo

* Update client.ts

* Update middleware.ts

* Build fixes

* Start working on app-level documentation

* Rework to Apps and Packages

* Add next.js config page

* Draft Tailwind Config page

* Cleanup email

* Update email.mdx

* Update mint.json

* Fix broken links

* Draft structure

* Cleanup images

* Restore structure

* Move deployment tips to each page

* Start building out app documentation

* Split philosophy to new page

* More docs updates

* More docs updates

* Move remaining env vars to next-config package

* Update env.ts

* Move env to root

* More work on env

* Finish env docs

* Finish "Getting started"

* Finish API

* Pass in basehub token manually

* Build fixes

* Update overview.mdx

* Finish drafting app docs
  • Loading branch information
haydenbleasel authored Dec 31, 2024
1 parent 7efa757 commit cac47cb
Show file tree
Hide file tree
Showing 168 changed files with 1,205 additions and 1,592 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ jobs:
echo "SVIX_TOKEN=testsk_test" >> apps/app/.env.local
echo "LIVEBLOCKS_SECRET=sk_test" >> apps/app/.env.local
echo "BASEHUB_TOKEN=${{ secrets.BASEHUB_TOKEN }}" >> apps/app/.env.local
echo "VERCEL_PROJECT_PRODUCTION_URL=http://localhost:3002" >> apps/app/.env.local
echo "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_JA==" >> apps/app/.env.local
echo "NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in" >> apps/app/.env.local
Expand All @@ -74,7 +75,6 @@ jobs:
echo "NEXT_PUBLIC_APP_URL=http://localhost:3000" >> apps/app/.env.local
echo "NEXT_PUBLIC_WEB_URL=http://localhost:3001" >> apps/app/.env.local
echo "NEXT_PUBLIC_DOCS_URL=http://localhost:3004" >> apps/app/.env.local
echo "NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL=http://localhost:3002" >> apps/app/.env.local
- name: Copy .env.local file
run: |
Expand Down
4 changes: 2 additions & 2 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ARCJET_KEY=""
SVIX_TOKEN=""
LIVEBLOCKS_SECRET=""
BASEHUB_TOKEN=""
VERCEL_PROJECT_PRODUCTION_URL="http://localhost:3002"

# Client
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=""
Expand All @@ -25,5 +26,4 @@ NEXT_PUBLIC_POSTHOG_KEY=""
NEXT_PUBLIC_POSTHOG_HOST=""
NEXT_PUBLIC_DOCS_URL="http://localhost:3004"
NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_WEB_URL="http://localhost:3001"
NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL="http://localhost:3002"
NEXT_PUBLIC_WEB_URL="http://localhost:3001"
2 changes: 1 addition & 1 deletion apps/api/app/webhooks/clerk/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { env } from '@/env';
import { analytics } from '@repo/analytics/posthog/server';
import type {
DeletedObjectJSON,
Expand All @@ -6,7 +7,6 @@ import type {
UserJSON,
WebhookEvent,
} from '@repo/auth/server';
import { env } from '@repo/env';
import { log } from '@repo/observability/log';
import { headers } from 'next/headers';
import { NextResponse } from 'next/server';
Expand Down
2 changes: 1 addition & 1 deletion apps/api/app/webhooks/stripe/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { env } from '@/env';
import { analytics } from '@repo/analytics/posthog/server';
import { clerkClient } from '@repo/auth/server';
import { env } from '@repo/env';
import { parseError } from '@repo/observability/error';
import { log } from '@repo/observability/log';
import { stripe } from '@repo/payments';
Expand Down
23 changes: 23 additions & 0 deletions apps/api/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { keys as analytics } from '@repo/analytics/keys';
import { keys as auth } from '@repo/auth/keys';
import { keys as database } from '@repo/database/keys';
import { keys as email } from '@repo/email/keys';
import { keys as core } from '@repo/next-config/keys';
import { keys as observability } from '@repo/observability/keys';
import { keys as payments } from '@repo/payments/keys';
import { createEnv } from '@t3-oss/env-nextjs';

export const env = createEnv({
extends: [
auth(),
analytics(),
core(),
database(),
email(),
observability(),
payments(),
],
server: {},
client: {},
runtimeEnv: {},
});
2 changes: 1 addition & 1 deletion apps/api/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { initializeSentry } from '@repo/next-config/instrumentation';
import { initializeSentry } from '@repo/observability/instrumentation';

export const register = initializeSentry();
7 changes: 4 additions & 3 deletions apps/api/next.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { env } from '@repo/env';
import { config, withAnalyzer, withSentry } from '@repo/next-config';
import { env } from '@/env';
import { config, withAnalyzer } from '@repo/next-config';
import { withLogtail, withSentry } from '@repo/observability/next-config';
import type { NextConfig } from 'next';

let nextConfig: NextConfig = { ...config };
let nextConfig: NextConfig = withLogtail({ ...config });

if (env.VERCEL) {
nextConfig = withSentry(nextConfig);
Expand Down
7 changes: 4 additions & 3 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@
"@repo/auth": "workspace:*",
"@repo/database": "workspace:*",
"@repo/design-system": "workspace:*",
"@repo/env": "workspace:*",
"@repo/next-config": "workspace:*",
"@repo/observability": "workspace:*",
"@repo/payments": "workspace:*",
"@sentry/nextjs": "^8.43.0",
"@repo/next-config": "workspace:*",
"@t3-oss/env-nextjs": "^0.11.1",
"next": "15.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"svix": "^1.43.0"
"svix": "^1.43.0",
"zod": "^3.23.8"
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
Expand Down
35 changes: 2 additions & 33 deletions apps/api/sentry.client.config.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,3 @@
/*
* This file configures the initialization of Sentry on the client.
* The config you add here will be used whenever a users loads a page in their browser.
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
*/
import { initializeSentry } from '@repo/observability/client';

import { init, replayIntegration } from '@sentry/nextjs';

init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1,

// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,

replaysOnErrorSampleRate: 1,

/*
* This sets the sample rate to be 10%. You may want this to be 100% while
* in development and sample at a lower rate in production
*/
replaysSessionSampleRate: 0.1,

// You can remove this option if you're not planning to use the Sentry Session Replay feature:
integrations: [
replayIntegration({
// Additional Replay configuration goes in here, for example:
maskAllText: true,
blockAllMedia: true,
}),
],
});
initializeSentry();
4 changes: 2 additions & 2 deletions apps/app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ARCJET_KEY=""
SVIX_TOKEN=""
LIVEBLOCKS_SECRET=""
BASEHUB_TOKEN=""
VERCEL_PROJECT_PRODUCTION_URL="http://localhost:3000"

# Client
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=""
Expand All @@ -25,5 +26,4 @@ NEXT_PUBLIC_POSTHOG_KEY=""
NEXT_PUBLIC_POSTHOG_HOST=""
NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_WEB_URL="http://localhost:3001"
NEXT_PUBLIC_DOCS_URL="http://localhost:3004"
NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL="http://localhost:3000"
NEXT_PUBLIC_DOCS_URL="http://localhost:3004"
2 changes: 1 addition & 1 deletion apps/app/app/(authenticated)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { env } from '@/env';
import { auth, currentUser } from '@repo/auth/server';
import { SidebarProvider } from '@repo/design-system/components/ui/sidebar';
import { env } from '@repo/env';
import { showBetaFeature } from '@repo/feature-flags';
import { secure } from '@repo/security';
import type { ReactNode } from 'react';
Expand Down
2 changes: 1 addition & 1 deletion apps/app/app/(authenticated)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { env } from '@/env';
import { auth } from '@repo/auth/server';
import { database } from '@repo/database';
import { env } from '@repo/env';
import type { Metadata } from 'next';
import dynamic from 'next/dynamic';
import { notFound } from 'next/navigation';
Expand Down
2 changes: 1 addition & 1 deletion apps/app/app/(unauthenticated)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { env } from '@/env';
import { ModeToggle } from '@repo/design-system/components/mode-toggle';
import { env } from '@repo/env';
import { CommandIcon } from 'lucide-react';
import Link from 'next/link';
import type { ReactNode } from 'react';
Expand Down
2 changes: 2 additions & 0 deletions apps/app/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import '@repo/design-system/styles/globals.css';
import { DesignSystemProvider } from '@repo/design-system';
import { fonts } from '@repo/design-system/lib/fonts';
import { Toolbar } from '@repo/feature-flags/components/toolbar';
import type { ReactNode } from 'react';

type RootLayoutProperties = {
Expand All @@ -11,6 +12,7 @@ const RootLayout = ({ children }: RootLayoutProperties) => (
<html lang="en" className={fonts} suppressHydrationWarning>
<body>
<DesignSystemProvider>{children}</DesignSystemProvider>
<Toolbar />
</body>
</html>
);
Expand Down
29 changes: 29 additions & 0 deletions apps/app/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { keys as analytics } from '@repo/analytics/keys';
import { keys as auth } from '@repo/auth/keys';
import { keys as collaboration } from '@repo/collaboration/keys';
import { keys as database } from '@repo/database/keys';
import { keys as email } from '@repo/email/keys';
import { keys as flags } from '@repo/feature-flags/keys';
import { keys as core } from '@repo/next-config/keys';
import { keys as observability } from '@repo/observability/keys';
import { keys as security } from '@repo/security/keys';
import { keys as webhooks } from '@repo/webhooks/keys';
import { createEnv } from '@t3-oss/env-nextjs';

export const env = createEnv({
extends: [
auth(),
analytics(),
collaboration(),
core(),
database(),
email(),
flags(),
observability(),
security(),
webhooks(),
],
server: {},
client: {},
runtimeEnv: {},
});
2 changes: 1 addition & 1 deletion apps/app/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { initializeSentry } from '@repo/next-config/instrumentation';
import { initializeSentry } from '@repo/observability/instrumentation';

export const register = initializeSentry();
11 changes: 9 additions & 2 deletions apps/app/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { authMiddleware } from '@repo/auth/middleware';
import { noseconeConfig, noseconeMiddleware } from '@repo/security/middleware';
import {
noseconeMiddleware,
noseconeOptions,
noseconeOptionsWithToolbar,
} from '@repo/security/middleware';
import { env } from './env';

const securityHeaders = noseconeMiddleware(noseconeConfig);
const securityHeaders = env.FLAGS_SECRET
? noseconeMiddleware(noseconeOptionsWithToolbar)
: noseconeMiddleware(noseconeOptions);

export default authMiddleware(() => securityHeaders());

Expand Down
8 changes: 5 additions & 3 deletions apps/app/next.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { env } from '@repo/env';
import { config, withAnalyzer, withSentry } from '@repo/next-config';
import { env } from '@/env';
import { withToolbar } from '@repo/feature-flags/lib/toolbar';
import { config, withAnalyzer } from '@repo/next-config';
import { withLogtail, withSentry } from '@repo/observability/next-config';
import type { NextConfig } from 'next';

let nextConfig: NextConfig = { ...config };
let nextConfig: NextConfig = withToolbar(withLogtail({ ...config }));

if (env.VERCEL) {
nextConfig = withSentry(nextConfig);
Expand Down
6 changes: 4 additions & 2 deletions apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,24 @@
"@repo/collaboration": "workspace:*",
"@repo/database": "workspace:*",
"@repo/design-system": "workspace:*",
"@repo/env": "workspace:*",
"@repo/feature-flags": "workspace:*",
"@repo/next-config": "workspace:*",
"@repo/observability": "workspace:*",
"@repo/security": "workspace:*",
"@repo/seo": "workspace:*",
"@repo/tailwind-config": "workspace:*",
"@repo/webhooks": "workspace:*",
"@sentry/nextjs": "^8.43.0",
"@t3-oss/env-nextjs": "^0.11.1",
"fuse.js": "^7.0.0",
"import-in-the-middle": "^1.11.3",
"lucide-react": "^0.468.0",
"next": "15.1.0",
"next-themes": "^0.4.4",
"react": "19.0.0",
"react-dom": "19.0.0",
"require-in-the-middle": "^7.4.0"
"require-in-the-middle": "^7.4.0",
"zod": "^3.23.8"
},
"devDependencies": {
"@repo/testing": "workspace:*",
Expand Down
35 changes: 2 additions & 33 deletions apps/app/sentry.client.config.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,3 @@
/*
* This file configures the initialization of Sentry on the client.
* The config you add here will be used whenever a users loads a page in their browser.
* https://docs.sentry.io/platforms/javascript/guides/nextjs/
*/
import { initializeSentry } from '@repo/observability/client';

import { init, replayIntegration } from '@sentry/nextjs';

init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,

// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1,

// Setting this option to true will print useful information to the console while you're setting up Sentry.
debug: false,

replaysOnErrorSampleRate: 1,

/*
* This sets the sample rate to be 10%. You may want this to be 100% while
* in development and sample at a lower rate in production
*/
replaysSessionSampleRate: 0.1,

// You can remove this option if you're not planning to use the Sentry Session Replay feature:
integrations: [
replayIntegration({
// Additional Replay configuration goes in here, for example:
maskAllText: true,
blockAllMedia: true,
}),
],
});
initializeSentry();
4 changes: 2 additions & 2 deletions apps/web/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ARCJET_KEY=""
SVIX_TOKEN=""
LIVEBLOCKS_SECRET=""
BASEHUB_TOKEN=""
VERCEL_PROJECT_PRODUCTION_URL="http://localhost:3001"

# Client
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=""
Expand All @@ -26,5 +27,4 @@ NEXT_PUBLIC_POSTHOG_HOST=""
NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_WEB_URL="http://localhost:3001"
NEXT_PUBLIC_API_URL="http://localhost:3002"
NEXT_PUBLIC_DOCS_URL="http://localhost:3004"
NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL="http://localhost:3001"
NEXT_PUBLIC_DOCS_URL="http://localhost:3004"
2 changes: 1 addition & 1 deletion apps/web/app/(home)/components/cta.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { env } from '@/env';
import { Button } from '@repo/design-system/components/ui/button';
import { env } from '@repo/env';
import { MoveRight, PhoneCall } from 'lucide-react';
import Link from 'next/link';

Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/(home)/components/hero.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { env } from '@/env';
import { blog } from '@repo/cms';
import { Feed } from '@repo/cms/components/feed';
import { Button } from '@repo/design-system/components/ui/button';
import { env } from '@repo/env';
import { MoveRight, PhoneCall } from 'lucide-react';
import { draftMode } from 'next/headers';
import Link from 'next/link';
Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Sidebar } from '@/components/sidebar';
import { env } from '@/env';
import { ArrowLeftIcon } from '@radix-ui/react-icons';
import { blog } from '@repo/cms';
import { Body } from '@repo/cms/components/body';
import { Feed } from '@repo/cms/components/feed';
import { Image } from '@repo/cms/components/image';
import { TableOfContents } from '@repo/cms/components/toc';
import { env } from '@repo/env';
import { JsonLd } from '@repo/seo/json-ld';
import { createMetadata } from '@repo/seo/metadata';
import type { Metadata } from 'next';
Expand Down Expand Up @@ -71,7 +71,7 @@ const BlogPost = async ({ params }: BlogPostProperties) => {
'@type': 'WebPage',
'@id': new URL(
`/blog/${slug}`,
env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL
env.VERCEL_PROJECT_PRODUCTION_URL
).toString(),
},
headline: page._title,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { env } from '@repo/env';
import { env } from '@/env';
import { Status } from '@repo/observability/status';
import Link from 'next/link';

Expand Down
Loading

0 comments on commit cac47cb

Please sign in to comment.