File size: 4,501 Bytes
bd28470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c76b4a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd28470
 
 
 
 
 
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
import { z } from "zod";
import * as dotenv from "dotenv";

dotenv.config();

const envSchema = z.object({
  // ─── LLM (All on NVIDIA NIM β€” FREE) ────────────────────────
  NVIDIA_API_KEY: z.string().min(5),
  NVIDIA_NIM_BASE_URL: z.string().url().default("https://integrate.api.nvidia.com/v1"),

  // ─── Supabase ──────────────────────────────────────────────
  SUPABASE_URL: z.string().url(),
  SUPABASE_SERVICE_ROLE_KEY: z.string().min(10),

  // ─── Trigger.dev ───────────────────────────────────────────
  TRIGGER_DEV_API_KEY: z.string().min(5),
  TRIGGER_DEV_PROJECT_ID: z.string().min(3),

  // ─── Web Research ──────────────────────────────────────────
  SERPER_API_KEY: z.string().min(5),

  // ─── Email Finding ─────────────────────────────────────────
  HUNTER_API_KEY: z.string().min(5),

  // ─── Email Verification ────────────────────────────────────
  REOON_API_KEY: z.string().min(5),

  // ─── Slack ─────────────────────────────────────────────────
  SLACK_BOT_TOKEN: z.string().startsWith("xoxb-"),
  SLACK_SIGNING_SECRET: z.string().min(5),
  SLACK_ALERT_CHANNEL_ID: z.string(),
  SLACK_REVIEW_CHANNEL_ID: z.string(),

  // ─── Python AI Service ─────────────────────────────────────
  PYTHON_AI_SERVICE_URL: z.string().url().default("http://localhost:8000"),
  PYTHON_AI_SERVICE_SECRET: z.string().min(10),

  // ─── System Config ─────────────────────────────────────────
  NODE_ENV: z.enum(["development", "staging", "production"]).default("development"),
  LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
  DAILY_LEAD_QUOTA: z.coerce.number().default(10),
  QUALITY_SCORE_THRESHOLD: z.coerce.number().default(70),
  HUMAN_REVIEW_ENABLED: z.string().transform((v) => v === "true").default("true"),
  DAILY_EMAIL_LIMIT: z.coerce.number().default(50),
  DAILY_LINKEDIN_LIMIT: z.coerce.number().default(25),
  SCHEDULE_START_HOUR_UTC: z.coerce.number().default(4),
});

type Env = z.infer<typeof envSchema>;

let _env: Env;

export function getEnv(): Env {
  if (!_env) {
    const result = envSchema.safeParse(process.env);
    if (!result.success) {
      console.error("❌ Invalid environment configuration:");
      result.error.errors.forEach((e) => {
        console.error(`  ${e.path.join(".")}: ${e.message}`);
      });
      // If we are in build/indexing phase (SUPABASE_URL is missing during CLI build), bypass crash to allow deploy to succeed
      if (!process.env.SUPABASE_URL || process.env.TRIGGER_BUILD === "true") {
        console.warn("⚠️ Warning: Missing environment variables during build/indexing phase. Bypassing crash with mock defaults to allow deployment.");
        // We parse mock values with the schema to get all the default values!
        const parsedDefaults = envSchema.parse({
          NODE_ENV: "production", // Set to production to bypass pino-pretty build crash
          NVIDIA_API_KEY: "mock_nvidia_key",
          SUPABASE_URL: "https://mock.supabase.co",
          SUPABASE_SERVICE_ROLE_KEY: "mock_service_role_key_long_enough",
          TRIGGER_DEV_API_KEY: "mock_trigger_dev_api_key",
          TRIGGER_DEV_PROJECT_ID: "mock_proj_id",
          SERPER_API_KEY: "mock_serper_key",
          HUNTER_API_KEY: "mock_hunter_key",
          REOON_API_KEY: "mock_reoon_key",
          SLACK_BOT_TOKEN: "xoxb-mock-bot-token",
          SLACK_SIGNING_SECRET: "mock_signing_secret",
          SLACK_ALERT_CHANNEL_ID: "mock_channel",
          SLACK_REVIEW_CHANNEL_ID: "mock_channel",
          PYTHON_AI_SERVICE_SECRET: "mock_python_secret_key_long_enough",
        });
        _env = { ...parsedDefaults, ...process.env } as any;
        return _env;
      }
      process.exit(1);
    }
    _env = result.data;
  }
  return _env;
}