Skip to content

Commit 2023a07

Browse files
Self hosting environment & error improvements (#14)
2 parents 50004a1 + 687a747 commit 2023a07

File tree

18 files changed

+203
-220
lines changed

18 files changed

+203
-220
lines changed

.env.example

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,64 @@
1-
# Uncomment according to src/lib/env.ts
1+
# =================================
2+
# REQUIRED SERVER ENVIRONMENT VARIABLES
3+
# =================================
4+
# Supabase service role key for admin operations
5+
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
26

3-
# KV_URL=
4-
# KV_REST_API_READ_ONLY_TOKEN=
5-
# KV_REST_API_TOKEN=
6-
# KV_REST_API_URL=
7-
# SUPABASE_SERVICE_ROLE_KEY=
8-
# COOKIE_ENCRYPTION_KEY=
7+
# Key for encrypting cookies - must be at least 32 characters long
8+
COOKIE_ENCRYPTION_KEY=your_secure_cookie_encryption_key_here
99

10-
BILLING_API_URL=https://billing.e2b.dev
10+
# KV database configuration
11+
KV_URL=
12+
KV_REST_API_READ_ONLY_TOKEN=
13+
KV_REST_API_TOKEN=
14+
KV_REST_API_URL=
1115

12-
# NEXT_PUBLIC_POSTHOG_KEY=
13-
# NEXT_PUBLIC_SUPABASE_URL=
14-
# NEXT_PUBLIC_SUPABASE_ANON_KEY=
15-
# NEXT_PUBLIC_STRIPE_BILLING_URL=
16+
# =================================
17+
# REQUIRED CLIENT ENVIRONMENT VARIABLES
18+
# =================================
19+
# Supabase URL and anon key for client-side operations
20+
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
21+
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
22+
23+
# API domain for your application
1624
NEXT_PUBLIC_DEFAULT_API_DOMAIN=e2b.dev
1725

18-
# Set to 1 to expose
19-
NEXT_PUBLIC_EXPOSE_STORYBOOK=0
20-
NEXT_PUBLIC_SCAN=0
21-
NEXT_PUBLIC_MOCK_DATA=0
26+
# =================================
27+
# OPTIONAL SERVER ENVIRONMENT VARIABLES
28+
# =================================
29+
# Billing API URL (Required if NEXT_PUBLIC_INCLUDE_BILLING=1)
30+
# BILLING_API_URL=https://billing.e2b.dev
31+
32+
# Vercel URL (automatically set in Vercel deployments)
33+
# VERCEL_URL=
34+
35+
# Development infrastructure API domain
36+
# DEVELOPMENT_INFRA_API_DOMAIN=
37+
38+
# Sentry authentication token for error reporting
39+
# SENTRY_AUTH_TOKEN=
40+
41+
# ZeroBounce API key for email validation
42+
# ZEROBOUNCE_API_KEY=
43+
44+
# =================================
45+
# OPTIONAL CLIENT ENVIRONMENT VARIABLES
46+
# =================================
47+
# PostHog analytics key
48+
# NEXT_PUBLIC_POSTHOG_KEY=
49+
50+
# Enable billing features: set to 1 to enable
51+
# When enabled, both BILLING_API_URL and NEXT_PUBLIC_STRIPE_BILLING_URL must be provided
52+
# NEXT_PUBLIC_INCLUDE_BILLING=0
53+
54+
# Stripe billing URL (Required if NEXT_PUBLIC_INCLUDE_BILLING=1)
55+
# NEXT_PUBLIC_STRIPE_BILLING_URL=https://billing.stripe.com/your-path
56+
57+
# Set to 1 to expose Storybook
58+
# NEXT_PUBLIC_EXPOSE_STORYBOOK=0
59+
60+
# Set to 1 to enable scanning
61+
# NEXT_PUBLIC_SCAN=0
2262

23-
# For applying migrations
24-
# POSTGRES_CONNECTION_STRING=
63+
# Set to 1 to use mock data
64+
# NEXT_PUBLIC_MOCK_DATA=0

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"<<<<<< Development": "",
2727
"storybook": "storybook dev -p 6006",
2828
"shad": "bunx shadcn@canary",
29-
"prebuild": "bun scripts:build-storybook",
29+
"prebuild": "bun scripts:check-app-env && bun scripts:build-storybook",
3030
"postinstall": "fumadocs-mdx",
3131
"<<<<<< Testing": "",
3232
"test:run": "bun scripts:check-all-env && vitest run",

scripts/check-app-env.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,19 @@ import { loadEnvConfig } from '@next/env'
44
const projectDir = process.cwd()
55
loadEnvConfig(projectDir)
66

7-
validateEnv(serverSchema.merge(clientSchema))
7+
const schema = serverSchema.merge(clientSchema).refine(
8+
(data) => {
9+
if (data.NEXT_PUBLIC_INCLUDE_BILLING === '1') {
10+
return !!data.BILLING_API_URL && !!data.NEXT_PUBLIC_STRIPE_BILLING_URL
11+
}
12+
13+
return true
14+
},
15+
{
16+
message:
17+
'NEXT_PUBLIC_INCLUDE_BILLING is enabled, but either BILLING_API_URL or NEXT_PUBLIC_STRIPE_BILLING_URL is missing',
18+
path: ['BILLING_API_URL', 'NEXT_PUBLIC_STRIPE_BILLING_URL'],
19+
}
20+
)
21+
22+
validateEnv(schema)

src/app/dashboard/[teamIdOrSlug]/usage/page.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,7 @@ async function UsagePageContent({ teamId }: { teamId: string }) {
3030
const res = await getUsage({ teamId })
3131

3232
if (!res?.data || res.serverError || res.validationErrors) {
33-
return (
34-
<ErrorIndicator
35-
description={'Could not load usage'}
36-
message={res?.serverError || 'Unknown error'}
37-
className="col-span-1 min-h-[360px] border-b lg:col-span-12"
38-
/>
39-
)
33+
throw new Error(res?.serverError || 'Failed to load usage')
4034
}
4135

4236
const data = res.data

src/app/dashboard/error.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
'use client'
22

3-
import { UnknownError } from '@/types/errors'
43
import ErrorBoundary from '@/ui/error'
54

6-
export default function DashboardError() {
5+
export default function DashboardError({
6+
error,
7+
}: {
8+
error: Error & { digest?: string }
9+
}) {
710
return (
811
<ErrorBoundary
9-
error={UnknownError()}
12+
error={error}
1013
description={'An Unexpected Error Occurred'}
1114
className="min-h-svh"
1215
/>

src/app/error.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
'use client'
22

3-
import { createErrorBoundary } from '@/lib/create-error-boundary'
3+
import ErrorBoundary from '@/ui/error'
44

5-
export default createErrorBoundary({
6-
title: 'Something went wrong',
7-
description: 'An unexpected error occurred',
8-
})
5+
export default function Error({
6+
error,
7+
}: {
8+
error: Error & { digest?: string }
9+
}) {
10+
return (
11+
<ErrorBoundary
12+
description="Sorry, something went wrong with the application."
13+
error={error}
14+
/>
15+
)
16+
}

src/app/global-error.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
'use client'
22

3-
import { SentryErrorBoundary } from '@/ui/sentry-error-boundary'
3+
import ErrorBoundary from '@/ui/error'
44

55
export default function GlobalError({
66
error,
77
}: {
88
error: Error & { digest?: string }
99
}) {
1010
return (
11-
<SentryErrorBoundary
12-
error={error}
13-
title="Application Error"
11+
<ErrorBoundary
1412
description="Sorry, something went wrong with the application."
15-
preserveLayout={false}
13+
error={error}
1614
/>
1715
)
1816
}

src/configs/dashboard-navs.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Users,
1010
} from 'lucide-react'
1111
import { ForwardRefExoticComponent, RefAttributes } from 'react'
12+
import { INCLUDE_BILLING } from './flags'
1213

1314
type DashboardNavLinkArgs = {
1415
teamIdOrSlug?: string
@@ -35,11 +36,16 @@ export const MAIN_DASHBOARD_LINKS: DashboardNavLink[] = [
3536
href: (args) => `/dashboard/${args.teamIdOrSlug}/templates`,
3637
icon: Container,
3738
},
38-
{
39-
label: 'Usage',
40-
href: (args) => `/dashboard/${args.teamIdOrSlug}/usage`,
41-
icon: Activity,
42-
},
39+
...(INCLUDE_BILLING
40+
? [
41+
{
42+
label: 'Usage',
43+
href: (args: DashboardNavLinkArgs) =>
44+
`/dashboard/${args.teamIdOrSlug}/usage`,
45+
icon: Activity,
46+
},
47+
]
48+
: []),
4349

4450
{
4551
label: 'Team',
@@ -53,16 +59,23 @@ export const MAIN_DASHBOARD_LINKS: DashboardNavLink[] = [
5359
icon: Key,
5460
group: 'manage',
5561
},
56-
{
57-
label: 'Billing',
58-
href: (args) => `/dashboard/${args.teamIdOrSlug}/billing`,
59-
icon: CreditCard,
60-
group: 'expenses',
61-
},
62-
{
63-
label: 'Budget',
64-
href: (args) => `/dashboard/${args.teamIdOrSlug}/budget`,
65-
group: 'expenses',
66-
icon: DollarSign,
67-
},
62+
63+
...(INCLUDE_BILLING
64+
? [
65+
{
66+
label: 'Billing',
67+
href: (args: DashboardNavLinkArgs) =>
68+
`/dashboard/${args.teamIdOrSlug}/billing`,
69+
icon: CreditCard,
70+
group: 'expenses',
71+
},
72+
{
73+
label: 'Budget',
74+
href: (args: DashboardNavLinkArgs) =>
75+
`/dashboard/${args.teamIdOrSlug}/budget`,
76+
group: 'expenses',
77+
icon: DollarSign,
78+
},
79+
]
80+
: []),
6881
]

src/configs/flags.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const INCLUDE_BILLING = process.env.NEXT_PUBLIC_INCLUDE_BILLING === '1'

src/features/client-providers.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ export default function ClientProviders({ children }: ClientProvidersProps) {
3232

3333
export function PostHogProvider({ children }: { children: React.ReactNode }) {
3434
useEffect(() => {
35+
if (!process.env.NEXT_PUBLIC_POSTHOG_KEY) {
36+
return
37+
}
38+
3539
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
3640
// Note that PostHog will automatically capture page views and common events
3741
//

0 commit comments

Comments
 (0)