mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-18 02:57:47 +00:00
feat: config + codegen env handling (#242)
* feat: better INLINE & PROD env handling * chore: bump server version * feat: refactor config ts better
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@browseros/server",
|
||||
"version": "0.0.41",
|
||||
"version": "0.0.42",
|
||||
"description": "BrowserOS server",
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
|
||||
@@ -11,6 +11,7 @@ import { MCPServerConfig } from '@google/gemini-cli-core'
|
||||
import type { HonoSSEStream } from '../../agent/provider-adapter/types'
|
||||
import type { SessionManager } from '../../agent/session'
|
||||
import type { ProviderConfig, ResolvedAgentConfig } from '../../agent/types'
|
||||
import { INLINED_ENV } from '../../env'
|
||||
import {
|
||||
fetchBrowserOSConfig,
|
||||
getLLMConfigFromProvider,
|
||||
@@ -106,7 +107,7 @@ export class ChatService {
|
||||
request: ChatRequest,
|
||||
): Promise<ProviderConfig> {
|
||||
if (request.provider === LLM_PROVIDERS.BROWSEROS) {
|
||||
const configUrl = process.env.BROWSEROS_CONFIG_URL
|
||||
const configUrl = INLINED_ENV.BROWSEROS_CONFIG_URL
|
||||
if (!configUrl) {
|
||||
throw new Error(
|
||||
'BROWSEROS_CONFIG_URL environment variable is required for BrowserOS provider',
|
||||
|
||||
@@ -11,6 +11,7 @@ import path from 'node:path'
|
||||
import { Command, InvalidArgumentError } from 'commander'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { INLINED_ENV, REQUIRED_FOR_PRODUCTION } from './env'
|
||||
import { VERSION } from './version'
|
||||
|
||||
const portSchema = z.number().int()
|
||||
@@ -32,52 +33,47 @@ export const ServerConfigSchema = z.object({
|
||||
|
||||
export type ServerConfig = z.infer<typeof ServerConfigSchema>
|
||||
|
||||
type PartialConfig = {
|
||||
cdpPort?: number | null
|
||||
serverPort?: number
|
||||
agentPort?: number
|
||||
extensionPort?: number
|
||||
resourcesDir?: string
|
||||
executionDir?: string
|
||||
mcpAllowRemote?: boolean
|
||||
codegenServiceUrl?: string
|
||||
instanceClientId?: string
|
||||
instanceInstallId?: string
|
||||
instanceBrowserosVersion?: string
|
||||
instanceChromiumVersion?: string
|
||||
}
|
||||
type PartialConfig = Partial<z.input<typeof ServerConfigSchema>>
|
||||
|
||||
export type ConfigResult<T> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: string }
|
||||
|
||||
interface ParsedCliArgs {
|
||||
configPath?: string
|
||||
cwd: string
|
||||
overrides: PartialConfig
|
||||
}
|
||||
|
||||
export function loadServerConfig(
|
||||
argv: string[] = process.argv,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): ConfigResult<ServerConfig> {
|
||||
// 1. Parse CLI (commander with exitOverride - throws instead of exit)
|
||||
const cli = parseCli(argv)
|
||||
// 1. Parse CLI args
|
||||
const cli = parseCliArgs(argv)
|
||||
if (!cli.ok) return cli
|
||||
|
||||
// 2. Load config file (only if --config provided)
|
||||
const file = loadConfigFile(cli.value.configPath)
|
||||
// 2. Parse config file (only if --config provided)
|
||||
const file = parseConfigFile(cli.value.configPath)
|
||||
if (!file.ok) return file
|
||||
|
||||
// 3. Load from environment
|
||||
const envConfig = loadEnv(env)
|
||||
// 3. Parse runtime environment variables
|
||||
const runtimeEnv = parseRuntimeEnv()
|
||||
|
||||
// 4. Merge: Defaults < Env < File < CLI
|
||||
const merged = merge(
|
||||
defaults(cli.value.cwd),
|
||||
envConfig,
|
||||
const merged = mergeConfigs(
|
||||
getDefaults(cli.value.cwd),
|
||||
runtimeEnv,
|
||||
file.value,
|
||||
cli.value.overrides,
|
||||
)
|
||||
|
||||
// 5. agentPort is deprecated - always use serverPort
|
||||
// 5. Add build-time inlined values
|
||||
merged.codegenServiceUrl = INLINED_ENV.CODEGEN_SERVICE_URL
|
||||
|
||||
// 6. agentPort is deprecated - always equals serverPort
|
||||
merged.agentPort = merged.serverPort
|
||||
|
||||
// 6. Validate with Zod (single source of truth)
|
||||
// 7. Validate with Zod
|
||||
const result = ServerConfigSchema.safeParse(merged)
|
||||
if (!result.success) {
|
||||
const errors = result.error.issues
|
||||
@@ -89,16 +85,14 @@ export function loadServerConfig(
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Validate required inlined env vars for production
|
||||
const inlinedValidation = validateInlinedEnv()
|
||||
if (!inlinedValidation.ok) return inlinedValidation
|
||||
|
||||
return { ok: true, value: result.data }
|
||||
}
|
||||
|
||||
interface CliResult {
|
||||
configPath?: string
|
||||
cwd: string
|
||||
overrides: PartialConfig
|
||||
}
|
||||
|
||||
function parseCli(argv: string[]): ConfigResult<CliResult> {
|
||||
function parseCliArgs(argv: string[]): ConfigResult<ParsedCliArgs> {
|
||||
const program = new Command()
|
||||
|
||||
try {
|
||||
@@ -179,15 +173,15 @@ function parseCli(argv: string[]): ConfigResult<CliResult> {
|
||||
value: {
|
||||
configPath: opts.config,
|
||||
cwd,
|
||||
overrides: filterUndefined({
|
||||
overrides: omitUndefined({
|
||||
cdpPort: opts.cdpPort,
|
||||
serverPort: opts.serverPort ?? opts.httpMcpPort,
|
||||
extensionPort: opts.extensionPort,
|
||||
resourcesDir: opts.resourcesDir
|
||||
? resolvePath(opts.resourcesDir, cwd)
|
||||
? toAbsolutePath(opts.resourcesDir, cwd)
|
||||
: undefined,
|
||||
executionDir: opts.executionDir
|
||||
? resolvePath(opts.executionDir, cwd)
|
||||
? toAbsolutePath(opts.executionDir, cwd)
|
||||
: undefined,
|
||||
mcpAllowRemote: opts.allowRemoteInMcp || undefined,
|
||||
}),
|
||||
@@ -203,14 +197,14 @@ function parsePortArg(value: string): number {
|
||||
return port
|
||||
}
|
||||
|
||||
function loadConfigFile(explicitPath?: string): ConfigResult<PartialConfig> {
|
||||
if (!explicitPath) {
|
||||
function parseConfigFile(filePath?: string): ConfigResult<PartialConfig> {
|
||||
if (!filePath) {
|
||||
return { ok: true, value: {} }
|
||||
}
|
||||
|
||||
const absPath = path.isAbsolute(explicitPath)
|
||||
? explicitPath
|
||||
: path.resolve(process.cwd(), explicitPath)
|
||||
const absPath = path.isAbsolute(filePath)
|
||||
? filePath
|
||||
: path.resolve(process.cwd(), filePath)
|
||||
|
||||
if (!fs.existsSync(absPath)) {
|
||||
return { ok: false, error: `Config file not found: ${absPath}` }
|
||||
@@ -223,18 +217,12 @@ function loadConfigFile(explicitPath?: string): ConfigResult<PartialConfig> {
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
value: filterUndefined({
|
||||
value: omitUndefined({
|
||||
cdpPort: cfg.ports?.cdp,
|
||||
serverPort: cfg.ports?.server ?? cfg.ports?.http_mcp,
|
||||
extensionPort: cfg.ports?.extension,
|
||||
resourcesDir: resolvePathIfString(
|
||||
cfg.directories?.resources,
|
||||
configDir,
|
||||
),
|
||||
executionDir: resolvePathIfString(
|
||||
cfg.directories?.execution,
|
||||
configDir,
|
||||
),
|
||||
resourcesDir: parseAbsolutePath(cfg.directories?.resources, configDir),
|
||||
executionDir: parseAbsolutePath(cfg.directories?.execution, configDir),
|
||||
mcpAllowRemote:
|
||||
cfg.flags?.allow_remote_in_mcp === true ? true : undefined,
|
||||
instanceClientId:
|
||||
@@ -261,36 +249,52 @@ function loadConfigFile(explicitPath?: string): ConfigResult<PartialConfig> {
|
||||
}
|
||||
}
|
||||
|
||||
function loadEnv(env: NodeJS.ProcessEnv): PartialConfig {
|
||||
function parseRuntimeEnv(): PartialConfig {
|
||||
const cwd = process.cwd()
|
||||
return filterUndefined({
|
||||
cdpPort: env.BROWSEROS_CDP_PORT
|
||||
? safeParseInt(env.BROWSEROS_CDP_PORT)
|
||||
return omitUndefined({
|
||||
cdpPort: process.env.BROWSEROS_CDP_PORT
|
||||
? safeParseInt(process.env.BROWSEROS_CDP_PORT)
|
||||
: undefined,
|
||||
serverPort: env.BROWSEROS_SERVER_PORT
|
||||
? safeParseInt(env.BROWSEROS_SERVER_PORT)
|
||||
serverPort: process.env.BROWSEROS_SERVER_PORT
|
||||
? safeParseInt(process.env.BROWSEROS_SERVER_PORT)
|
||||
: undefined,
|
||||
extensionPort: env.BROWSEROS_EXTENSION_PORT
|
||||
? safeParseInt(env.BROWSEROS_EXTENSION_PORT)
|
||||
extensionPort: process.env.BROWSEROS_EXTENSION_PORT
|
||||
? safeParseInt(process.env.BROWSEROS_EXTENSION_PORT)
|
||||
: undefined,
|
||||
resourcesDir: env.BROWSEROS_RESOURCES_DIR
|
||||
? resolvePath(env.BROWSEROS_RESOURCES_DIR, cwd)
|
||||
resourcesDir: process.env.BROWSEROS_RESOURCES_DIR
|
||||
? toAbsolutePath(process.env.BROWSEROS_RESOURCES_DIR, cwd)
|
||||
: undefined,
|
||||
executionDir: env.BROWSEROS_EXECUTION_DIR
|
||||
? resolvePath(env.BROWSEROS_EXECUTION_DIR, cwd)
|
||||
executionDir: process.env.BROWSEROS_EXECUTION_DIR
|
||||
? toAbsolutePath(process.env.BROWSEROS_EXECUTION_DIR, cwd)
|
||||
: undefined,
|
||||
codegenServiceUrl: env.CODEGEN_SERVICE_URL,
|
||||
instanceInstallId: env.BROWSEROS_INSTALL_ID,
|
||||
instanceClientId: env.BROWSEROS_CLIENT_ID,
|
||||
instanceInstallId: process.env.BROWSEROS_INSTALL_ID,
|
||||
instanceClientId: process.env.BROWSEROS_CLIENT_ID,
|
||||
})
|
||||
}
|
||||
|
||||
function safeParseInt(value: string): number | undefined {
|
||||
const num = parseInt(value, 10)
|
||||
return Number.isNaN(num) ? undefined : num
|
||||
function validateInlinedEnv(): ConfigResult<void> {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
return { ok: true, value: undefined }
|
||||
}
|
||||
|
||||
const missing: string[] = []
|
||||
for (const varName of REQUIRED_FOR_PRODUCTION) {
|
||||
if (!INLINED_ENV[varName]) {
|
||||
missing.push(varName)
|
||||
}
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
return {
|
||||
ok: false,
|
||||
error: `Missing required environment variables for production:\n${missing.map((v) => ` - ${v}`).join('\n')}`,
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: true, value: undefined }
|
||||
}
|
||||
|
||||
function defaults(cwd: string): PartialConfig {
|
||||
function getDefaults(cwd: string): PartialConfig {
|
||||
return {
|
||||
cdpPort: null,
|
||||
resourcesDir: cwd,
|
||||
@@ -299,7 +303,7 @@ function defaults(cwd: string): PartialConfig {
|
||||
}
|
||||
}
|
||||
|
||||
function merge(...configs: PartialConfig[]): PartialConfig {
|
||||
function mergeConfigs(...configs: PartialConfig[]): PartialConfig {
|
||||
const result: PartialConfig = {}
|
||||
for (const config of configs) {
|
||||
for (const [key, value] of Object.entries(config)) {
|
||||
@@ -311,22 +315,22 @@ function merge(...configs: PartialConfig[]): PartialConfig {
|
||||
return result
|
||||
}
|
||||
|
||||
function filterUndefined<T extends Record<string, unknown>>(
|
||||
obj: T,
|
||||
): Partial<T> {
|
||||
function safeParseInt(value: string): number | undefined {
|
||||
const num = parseInt(value, 10)
|
||||
return Number.isNaN(num) ? undefined : num
|
||||
}
|
||||
|
||||
function omitUndefined<T extends Record<string, unknown>>(obj: T): Partial<T> {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).filter(([_, v]) => v !== undefined),
|
||||
) as Partial<T>
|
||||
}
|
||||
|
||||
function resolvePath(target: string, baseDir: string): string {
|
||||
function toAbsolutePath(target: string, baseDir: string): string {
|
||||
return path.isAbsolute(target) ? target : path.resolve(baseDir, target)
|
||||
}
|
||||
|
||||
function resolvePathIfString(
|
||||
val: unknown,
|
||||
baseDir: string,
|
||||
): string | undefined {
|
||||
function parseAbsolutePath(val: unknown, baseDir: string): string | undefined {
|
||||
if (typeof val !== 'string') return undefined
|
||||
return resolvePath(val, baseDir)
|
||||
return toAbsolutePath(val, baseDir)
|
||||
}
|
||||
|
||||
29
apps/server/src/env.ts
Normal file
29
apps/server/src/env.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 BrowserOS
|
||||
*
|
||||
* Build-time inlined environment variables.
|
||||
*
|
||||
* IMPORTANT: Values here are replaced at build time by Bun's `--env inline` flag.
|
||||
* The `process.env.X` access MUST be direct (not via a variable) for inlining to work.
|
||||
*
|
||||
* These variables are:
|
||||
* - Replaced with literal strings in production builds
|
||||
* - Read from actual env vars during development
|
||||
*
|
||||
* For runtime-only env vars (like BROWSEROS_CDP_PORT), use process.env directly.
|
||||
*/
|
||||
|
||||
export const INLINED_ENV = {
|
||||
SENTRY_DSN: process.env.SENTRY_DSN,
|
||||
CODEGEN_SERVICE_URL: process.env.CODEGEN_SERVICE_URL,
|
||||
POSTHOG_API_KEY: process.env.POSTHOG_API_KEY,
|
||||
BROWSEROS_CONFIG_URL: process.env.BROWSEROS_CONFIG_URL,
|
||||
} as const
|
||||
|
||||
export const REQUIRED_FOR_PRODUCTION = [
|
||||
'SENTRY_DSN',
|
||||
'CODEGEN_SERVICE_URL',
|
||||
'POSTHOG_API_KEY',
|
||||
'BROWSEROS_CONFIG_URL',
|
||||
] as const satisfies readonly (keyof typeof INLINED_ENV)[]
|
||||
@@ -17,6 +17,7 @@ if (typeof Bun === 'undefined') {
|
||||
|
||||
// Import polyfills first
|
||||
import './lib/polyfill'
|
||||
import { EXIT_CODES } from '@browseros/shared/constants/exit-codes'
|
||||
import { CommanderError } from 'commander'
|
||||
import { loadServerConfig } from './config'
|
||||
import { Sentry } from './lib/sentry'
|
||||
@@ -27,7 +28,7 @@ const configResult = loadServerConfig()
|
||||
if (!configResult.ok) {
|
||||
Sentry.captureException(new Error(configResult.error))
|
||||
console.error(configResult.error)
|
||||
process.exit(1)
|
||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
||||
}
|
||||
|
||||
const app = new Application(configResult.value)
|
||||
@@ -40,7 +41,7 @@ try {
|
||||
}
|
||||
Sentry.captureException(error)
|
||||
console.error('Failed to start server:', error)
|
||||
process.exit(1)
|
||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
||||
}
|
||||
|
||||
process.on('SIGINT', () => app.stop())
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import { LLM_PROVIDERS, type LLMConfig } from '@browseros/shared/schemas/llm'
|
||||
import { INLINED_ENV } from '../../../env'
|
||||
import { logger } from '../../logger'
|
||||
import { fetchBrowserOSConfig, getLLMConfigFromProvider } from '../gateway'
|
||||
import type { ResolvedLLMConfig } from './types'
|
||||
@@ -22,7 +23,7 @@ export async function resolveLLMConfig(
|
||||
return config as ResolvedLLMConfig
|
||||
}
|
||||
|
||||
const configUrl = process.env.BROWSEROS_CONFIG_URL
|
||||
const configUrl = INLINED_ENV.BROWSEROS_CONFIG_URL
|
||||
if (!configUrl) {
|
||||
throw new Error(
|
||||
'BROWSEROS_CONFIG_URL environment variable is required for BrowserOS provider',
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
import { EXTERNAL_URLS } from '@browseros/shared/constants/urls'
|
||||
import { PostHog } from 'posthog-node'
|
||||
|
||||
const POSTHOG_API_KEY = process.env.POSTHOG_API_KEY
|
||||
import { INLINED_ENV } from '../env'
|
||||
|
||||
const POSTHOG_API_KEY = INLINED_ENV.POSTHOG_API_KEY
|
||||
const EVENT_PREFIX = 'browseros.server.'
|
||||
|
||||
export interface MetricsConfig {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import { RATE_LIMITS } from '@browseros/shared/constants/limits'
|
||||
|
||||
import { INLINED_ENV } from '../../env'
|
||||
import { fetchBrowserOSConfig } from '../clients/gateway'
|
||||
import { logger } from '../logger'
|
||||
|
||||
@@ -26,7 +27,7 @@ export async function fetchDailyRateLimit(
|
||||
return RATE_LIMITS.DEV_DAILY
|
||||
}
|
||||
|
||||
const configUrl = process.env.BROWSEROS_CONFIG_URL
|
||||
const configUrl = INLINED_ENV.BROWSEROS_CONFIG_URL
|
||||
if (!configUrl) {
|
||||
logger.info('No BROWSEROS_CONFIG_URL, using default rate limit', {
|
||||
dailyRateLimit: RATE_LIMITS.DEFAULT_DAILY,
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
*/
|
||||
import * as Sentry from '@sentry/bun'
|
||||
|
||||
import { INLINED_ENV } from '../env'
|
||||
import { VERSION } from '../version'
|
||||
|
||||
const SENTRY_ENVIRONMENT = process.env.NODE_ENV || 'development'
|
||||
|
||||
// Ensure to call this before importing any other modules!
|
||||
Sentry.init({
|
||||
dsn: process.env.SENTRY_DSN,
|
||||
dsn: INLINED_ENV.SENTRY_DSN,
|
||||
// Adds request headers and IP for users, for more info visit:
|
||||
// https://docs.sentry.io/platforms/javascript/guides/bun/configuration/options/#sendDefaultPii
|
||||
sendDefaultPii: true,
|
||||
|
||||
@@ -18,6 +18,7 @@ import { McpContext } from './browser/cdp/context'
|
||||
import { ControllerBridge } from './browser/extension/bridge'
|
||||
import { ControllerContext } from './browser/extension/context'
|
||||
import type { ServerConfig } from './config'
|
||||
import { INLINED_ENV } from './env'
|
||||
import { initializeDb } from './lib/db'
|
||||
import { identity } from './lib/identity'
|
||||
import { logger } from './lib/logger'
|
||||
@@ -139,7 +140,7 @@ export class Application {
|
||||
logger.warn('Metrics disabled: missing POSTHOG_API_KEY')
|
||||
}
|
||||
|
||||
if (!process.env.SENTRY_DSN) {
|
||||
if (!INLINED_ENV.SENTRY_DSN) {
|
||||
logger.warn('Sentry disabled: missing SENTRY_DSN')
|
||||
}
|
||||
|
||||
|
||||
@@ -84,11 +84,11 @@ describe('loadServerConfig', () => {
|
||||
|
||||
describe('environment variables', () => {
|
||||
it('reads from env when CLI not provided', () => {
|
||||
const result = loadServerConfig(['bun', 'src/index.ts'], {
|
||||
BROWSEROS_CDP_PORT: '9222',
|
||||
BROWSEROS_SERVER_PORT: '9223',
|
||||
BROWSEROS_EXTENSION_PORT: '9224',
|
||||
})
|
||||
process.env.BROWSEROS_CDP_PORT = '9222'
|
||||
process.env.BROWSEROS_SERVER_PORT = '9223'
|
||||
process.env.BROWSEROS_EXTENSION_PORT = '9224'
|
||||
|
||||
const result = loadServerConfig(['bun', 'src/index.ts'])
|
||||
|
||||
assert.strictEqual(result.ok, true)
|
||||
if (!result.ok) return
|
||||
@@ -100,13 +100,15 @@ describe('loadServerConfig', () => {
|
||||
})
|
||||
|
||||
it('CLI takes precedence over env', () => {
|
||||
const result = loadServerConfig(
|
||||
['bun', 'src/index.ts', '--server-port=1111', '--extension-port=3333'],
|
||||
{
|
||||
BROWSEROS_SERVER_PORT: '9999',
|
||||
BROWSEROS_EXTENSION_PORT: '9999',
|
||||
},
|
||||
)
|
||||
process.env.BROWSEROS_SERVER_PORT = '9999'
|
||||
process.env.BROWSEROS_EXTENSION_PORT = '9999'
|
||||
|
||||
const result = loadServerConfig([
|
||||
'bun',
|
||||
'src/index.ts',
|
||||
'--server-port=1111',
|
||||
'--extension-port=3333',
|
||||
])
|
||||
|
||||
assert.strictEqual(result.ok, true)
|
||||
if (!result.ok) return
|
||||
@@ -188,10 +190,13 @@ describe('loadServerConfig', () => {
|
||||
}),
|
||||
)
|
||||
|
||||
const result = loadServerConfig(
|
||||
['bun', 'src/index.ts', `--config=${configPath}`],
|
||||
{ BROWSEROS_SERVER_PORT: '9999' },
|
||||
)
|
||||
process.env.BROWSEROS_SERVER_PORT = '9999'
|
||||
|
||||
const result = loadServerConfig([
|
||||
'bun',
|
||||
'src/index.ts',
|
||||
`--config=${configPath}`,
|
||||
])
|
||||
|
||||
assert.strictEqual(result.ok, true)
|
||||
if (!result.ok) return
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
export const EXTERNAL_URLS = {
|
||||
KLAVIS_PROXY: 'https://llm.browseros.com/klavis',
|
||||
POSTHOG_DEFAULT: 'https://us.i.posthog.com',
|
||||
CODEGEN_SERVICE: 'https://browseros-codegen.fly.dev',
|
||||
CODEGEN_SERVICE: 'https://graph.browseros.com',
|
||||
} as const
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* bun scripts/build/server.ts --mode=dev [--target=all]
|
||||
*
|
||||
* Modes:
|
||||
* prod - Clean environment build using only .env.prod
|
||||
* dev - Normal build using shell environment + .env.dev
|
||||
* prod - Clean environment build using only .env.production
|
||||
* dev - Normal build using shell environment + .env.development
|
||||
*
|
||||
* Targets:
|
||||
* linux-x64, linux-arm64, windows-x64, darwin-arm64, darwin-x64, all
|
||||
@@ -135,7 +135,7 @@ function validateProdEnv(envVars: Record<string, string>): void {
|
||||
for (const varName of missing) {
|
||||
console.error(` - ${varName}`)
|
||||
}
|
||||
console.error(`\n Please set these in .env.prod`)
|
||||
console.error(`\n Please set these in .env.production`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
@@ -283,7 +283,7 @@ async function main() {
|
||||
`\n Tip: bun run version:server [patch|minor|major] to bump version`,
|
||||
)
|
||||
|
||||
const envFile = mode === 'prod' ? '.env.prod' : '.env.dev'
|
||||
const envFile = mode === 'prod' ? '.env.production' : '.env.development'
|
||||
const envPath = join(rootDir, envFile)
|
||||
|
||||
console.log(`\n📄 Loading environment from ${envFile}...`)
|
||||
|
||||
Reference in New Issue
Block a user