This repository was archived by the owner on Mar 24, 2026. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathenv.ts
More file actions
162 lines (147 loc) · 6.48 KB
/
env.ts
File metadata and controls
162 lines (147 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import { createEnv } from '@t3-oss/env-nextjs';
import { z } from 'zod';
/**
* Environment variable configuration using T3 Env
* @see https://env.t3.gg/docs/nextjs
*
* This configuration works with both Next.js and Cloudflare Workers.
* - For local development, use .env.local file
* - For Wrangler development, use .dev.vars file
* - For Cloudflare deployment, secrets are uploaded via environment-specific files:
* - Dev environment: .env.secrets.dev (sandbox credentials)
* - Prod environment: .env.secrets.prod (production credentials)
*/
// Helper to detect deployment environment (now static per worker)
// Each worker environment is hardcoded since we use separate workers
function getDeploymentEnvironment(): 'dev' | 'prod' {
// Since we now use separate workers for dev/prod, we can hardcode this
// The build process will set the appropriate value based on the worker environment
return process.env.NODE_ENV === 'production' ? 'prod' : 'dev';
}
// Helper to get environment variable
// With separate workers (dev/prod), secrets are set directly without prefixes
function getEnvVar(baseName: string): string | undefined {
return process.env[baseName];
}
// Helper to determine QuickBooks environment with auto-detection
const getQuickBooksEnvironment = (): 'sandbox' | 'production' | undefined => {
const explicitEnv = process.env.QUICKBOOKS_ENVIRONMENT as
| 'sandbox'
| 'production'
| undefined;
if (explicitEnv) {
return explicitEnv;
}
// Auto-detect: prod deployment → production QuickBooks, dev → sandbox
const deploymentEnv = getDeploymentEnvironment();
return deploymentEnv === 'prod' ? 'production' : 'sandbox';
};
export const env = createEnv({
/**
* Server-side environment variables (not exposed to browser)
*/
server: {
// Private API tokens and keys
GITHUB_TOKEN: z.string().optional(),
MONDAY_API_KEY: z.string().optional(),
MONDAY_BOARD_ID: z.string().optional(),
DISCORD_WEBHOOK_URL: z.string().url().optional(),
TRIGGER_SECRET_KEY: z.string().optional(),
// QuickBooks API
QUICKBOOKS_CLIENT_ID: z.string().optional(),
QUICKBOOKS_CLIENT_SECRET: z.string().optional(),
QUICKBOOKS_REFRESH_TOKEN: z.string().optional(),
QUICKBOOKS_REALM_ID: z.string().optional(),
// QuickBooks Environment: 'sandbox' for development/testing, 'production' for live data
// Defaults to 'sandbox' in development, 'production' in production (handled in runtimeEnv)
QUICKBOOKS_ENVIRONMENT: z.enum(['sandbox', 'production']).optional(),
// Admin key for QuickBooks API operations (token refresh, etc.)
QUICKBOOKS_ADMIN_KEY: z.string().optional(),
// Server configuration
NODE_ENV: z
.enum(['development', 'production', 'test'])
.default('development'),
},
/**
* Client-side variables (accessible in browser)
*/
client: {
// Application URLs and public configuration
NEXT_PUBLIC_URL: z.string().url().default('https://allthingslinux.org'),
NEXT_PUBLIC_API_URL: z
.string()
.url()
.default('https://allthingslinux.org/api'),
// Public repository information (no tokens, just public identifiers)
NEXT_PUBLIC_GITHUB_REPO_OWNER: z.string().default('allthingslinux'),
NEXT_PUBLIC_GITHUB_REPO_NAME: z.string().default('applications'),
},
/**
* Map environment variables to the schemas
*/
runtimeEnv: {
// Server variables
NODE_ENV: process.env.NODE_ENV,
GITHUB_TOKEN: process.env.GITHUB_TOKEN,
MONDAY_API_KEY: process.env.MONDAY_API_KEY,
MONDAY_BOARD_ID: process.env.MONDAY_BOARD_ID,
DISCORD_WEBHOOK_URL: process.env.DISCORD_WEBHOOK_URL,
TRIGGER_SECRET_KEY: process.env.TRIGGER_SECRET_KEY,
QUICKBOOKS_CLIENT_ID: process.env.QUICKBOOKS_CLIENT_ID,
QUICKBOOKS_CLIENT_SECRET: process.env.QUICKBOOKS_CLIENT_SECRET,
QUICKBOOKS_REFRESH_TOKEN: process.env.QUICKBOOKS_REFRESH_TOKEN,
QUICKBOOKS_REALM_ID: process.env.QUICKBOOKS_REALM_ID,
QUICKBOOKS_ENVIRONMENT: getQuickBooksEnvironment(),
QUICKBOOKS_ADMIN_KEY: process.env.QUICKBOOKS_ADMIN_KEY,
// Client variables
NEXT_PUBLIC_URL: process.env.NEXT_PUBLIC_URL,
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
NEXT_PUBLIC_GITHUB_REPO_OWNER: process.env.NEXT_PUBLIC_GITHUB_REPO_OWNER,
NEXT_PUBLIC_GITHUB_REPO_NAME: process.env.NEXT_PUBLIC_GITHUB_REPO_NAME,
},
/**
* Configuration options
*/
skipValidation: process.env.SKIP_ENV_VALIDATION === 'true',
emptyStringAsUndefined: true,
onValidationError: (error) => {
console.error('❌ Invalid environment variables:', error);
throw new Error('Invalid environment variables, check server logs');
},
});
/**
* Cloudflare Workers environment fallback
* This provides direct access to environment variables when running in Cloudflare Workers
* since the t3-env validation may not work correctly in that environment
*
* Uses prefixed secrets (DEV_*, PROD_*) based on runtime environment detection
* Falls back to non-prefixed for local development
*/
export const cloudflareEnv = {
// Server variables (secrets are set directly in each environment worker)
NODE_ENV: process.env.NODE_ENV,
GITHUB_TOKEN: getEnvVar('GITHUB_TOKEN'),
MONDAY_API_KEY: getEnvVar('MONDAY_API_KEY'),
MONDAY_BOARD_ID: getEnvVar('MONDAY_BOARD_ID'),
DISCORD_WEBHOOK_URL: getEnvVar('DISCORD_WEBHOOK_URL') as string | undefined,
TRIGGER_SECRET_KEY: process.env.TRIGGER_SECRET_KEY, // Not prefixed (Trigger.dev handles separately)
QUICKBOOKS_CLIENT_ID: getEnvVar('QUICKBOOKS_CLIENT_ID'),
QUICKBOOKS_CLIENT_SECRET: getEnvVar('QUICKBOOKS_CLIENT_SECRET'),
QUICKBOOKS_REFRESH_TOKEN: getEnvVar('QUICKBOOKS_REFRESH_TOKEN'),
QUICKBOOKS_REALM_ID: getEnvVar('QUICKBOOKS_REALM_ID'),
QUICKBOOKS_ENVIRONMENT: getQuickBooksEnvironment(),
QUICKBOOKS_ADMIN_KEY: getEnvVar('QUICKBOOKS_ADMIN_KEY'),
// Client variables (not prefixed - these are public anyway)
NEXT_PUBLIC_URL: process.env.NEXT_PUBLIC_URL,
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
NEXT_PUBLIC_GITHUB_REPO_OWNER: process.env.NEXT_PUBLIC_GITHUB_REPO_OWNER,
NEXT_PUBLIC_GITHUB_REPO_NAME: process.env.NEXT_PUBLIC_GITHUB_REPO_NAME,
};
// Helper function to detect if running in Cloudflare Workers environment
export const isCloudflareWorker = () =>
typeof process !== 'undefined' &&
typeof process.env !== 'undefined' &&
(process.env.CLOUDFLARE_WORKER === 'true' ||
typeof globalThis.caches !== 'undefined');
// Combined environment that automatically selects the right source
export const runtimeEnv = isCloudflareWorker() ? cloudflareEnv : env;