sistema-de-chamados/src/lib/env.ts
2025-12-10 14:43:13 -03:00

88 lines
3.7 KiB
TypeScript

import { z } from "zod"
const urlField = () =>
z.preprocess(
(value) => (typeof value === "string" ? value.trim() || undefined : value),
z.string().url().optional()
)
const stringField = () =>
z.preprocess(
(value) => (typeof value === "string" ? value.trim() || undefined : value),
z.string().min(1).optional()
)
const envSchema = z.object({
BETTER_AUTH_SECRET: stringField().or(z.literal("")).optional(),
BETTER_AUTH_URL: urlField().or(z.literal("")).optional(),
NEXT_PUBLIC_CONVEX_URL: urlField().or(z.literal("")).optional(),
CONVEX_INTERNAL_URL: urlField().or(z.literal("")).optional(),
DATABASE_URL: stringField().or(z.literal("")).optional(),
NEXT_PUBLIC_APP_URL: urlField().or(z.literal("")).optional(),
MACHINE_PROVISIONING_SECRET: z.string().optional(),
MACHINE_TOKEN_TTL_MS: z.coerce.number().optional(),
FLEET_SYNC_SECRET: z.string().optional(),
SMTP_ADDRESS: z.string().optional(),
SMTP_PORT: z.coerce.number().optional(),
SMTP_DOMAIN: z.string().optional(),
SMTP_USERNAME: z.string().optional(),
SMTP_PASSWORD: z.string().optional(),
SMTP_AUTHENTICATION: z.string().optional(),
SMTP_ENABLE_STARTTLS_AUTO: z.string().optional(),
SMTP_TLS: z.string().optional(),
MAILER_SENDER_EMAIL: z.string().optional(),
REPORTS_CRON_SECRET: z.string().optional(),
INTERNAL_HEALTH_TOKEN: z.string().optional(),
REPORTS_CRON_BASE_URL: urlField().or(z.literal("")).optional(),
ARCHIVE_DIR: stringField().or(z.literal("")).optional(),
})
const parsed = envSchema.safeParse(process.env)
if (!parsed.success) {
console.error("Failed to parse environment variables", parsed.error.flatten().fieldErrors)
throw new Error("Invalid environment configuration")
}
const isBuildPhase = process.env.NEXT_PHASE === "phase-production-build"
function resolveSecret(value: string | undefined, key: string) {
if (value && value.length > 0) return value
const fallback = isBuildPhase ? `build-placeholder-${key.toLowerCase()}` : `dev-${key.toLowerCase()}`
if (process.env.NODE_ENV === "production" && !isBuildPhase) {
throw new Error(`${key} must be set in production runtime environment`)
}
if (!isBuildPhase) {
console.warn(`ENV ${key} not set; using fallback value only for development.`)
}
return fallback
}
export const env = {
BETTER_AUTH_SECRET: resolveSecret(parsed.data.BETTER_AUTH_SECRET, "BETTER_AUTH_SECRET"),
BETTER_AUTH_URL: parsed.data.BETTER_AUTH_URL ?? parsed.data.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000",
NEXT_PUBLIC_CONVEX_URL: parsed.data.NEXT_PUBLIC_CONVEX_URL,
CONVEX_INTERNAL_URL: parsed.data.CONVEX_INTERNAL_URL,
DATABASE_URL: parsed.data.DATABASE_URL,
NEXT_PUBLIC_APP_URL: parsed.data.NEXT_PUBLIC_APP_URL,
MACHINE_PROVISIONING_SECRET: parsed.data.MACHINE_PROVISIONING_SECRET,
MACHINE_TOKEN_TTL_MS: parsed.data.MACHINE_TOKEN_TTL_MS,
FLEET_SYNC_SECRET: parsed.data.FLEET_SYNC_SECRET,
REPORTS_CRON_SECRET: parsed.data.REPORTS_CRON_SECRET,
INTERNAL_HEALTH_TOKEN: parsed.data.INTERNAL_HEALTH_TOKEN,
REPORTS_CRON_BASE_URL: parsed.data.REPORTS_CRON_BASE_URL,
ARCHIVE_DIR: parsed.data.ARCHIVE_DIR ?? "./archives",
SMTP: parsed.data.SMTP_ADDRESS && parsed.data.SMTP_USERNAME && parsed.data.SMTP_PASSWORD
? {
host: parsed.data.SMTP_ADDRESS,
port: parsed.data.SMTP_PORT ?? 465,
domain: parsed.data.SMTP_DOMAIN,
username: parsed.data.SMTP_USERNAME,
password: parsed.data.SMTP_PASSWORD,
tls: (parsed.data.SMTP_TLS ?? "true").toLowerCase() === "true",
starttls: (parsed.data.SMTP_ENABLE_STARTTLS_AUTO ?? "false").toLowerCase() === "true",
auth: parsed.data.SMTP_AUTHENTICATION ?? "login",
from: parsed.data.MAILER_SENDER_EMAIL ?? "no-reply@example.com",
}
: null,
}