env.ts46 lines · main
1import { loadEnv } from '@briven/shared';
2import { z } from 'zod';
3
4const envSchema = z.object({
5 BRIVEN_ENV: z.enum(['development', 'staging', 'production']).default('development'),
6 BRIVEN_REALTIME_PORT: z.coerce.number().int().positive().default(3004),
7 BRIVEN_LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
8
9 // Where to dispatch invokes — same internal apps/api hostname the runtime
10 // hits. Realtime never talks to the runtime directly; the api owns the
11 // auth + project resolution chain.
12 BRIVEN_API_INTERNAL_URL: z.string().url().default('http://localhost:3001'),
13
14 // Shared with apps/api so realtime can call internal endpoints; also used
15 // to validate the bearer token on the WebSocket upgrade.
16 BRIVEN_RUNTIME_SHARED_SECRET: z.string().min(32).optional(),
17
18 // @README-BRIVEN ADR 0001 — DoltGres data-plane DSN (postgres:// wire).
19 // The shared data-plane cluster where each project lives in its own
20 // DoltGres database (proj_<id>). Phase 1 stubs out LISTEN/NOTIFY;
21 // Phase 2 PollManager opens a per-project postgres.js client against
22 // this DSN for commit-diff polling. Mirrors apps/api's
23 // BRIVEN_DATA_PLANE_URL — optional so local dev can boot without a
24 // data plane; polling stays disabled until it is set.
25 BRIVEN_DATA_PLANE_URL: z.string().url().optional(),
26
27 // Poll interval in ms for commit-diff change detection. Lower = less
28 // latency but more database load. Default 500 ms, floor 100 ms, cap 5000 ms.
29 BRIVEN_REALTIME_POLL_MS: z.coerce.number().int().min(100).max(5000).default(500),
30
31 // Per-WebSocket subscription cap. A single client opening more than
32 // this many concurrent subs gets `error: subscription_limit_ws`. Sized
33 // so a normal app (one page, ~dozens of useQuery hooks) is well under,
34 // but a bug or malicious loop is bounded before it OOMs realtime.
35 BRIVEN_REALTIME_MAX_SUBS_PER_WS: z.coerce.number().int().positive().default(200),
36
37 // Per-project hard cap on concurrent subs across all WS connections.
38 // Defaults to the team-tier cap from services/tiers.ts so a misconfig
39 // doesn't accidentally clamp Team customers. Tier-aware enforcement
40 // (free=100/pro=1000/team=10000) waits for the realtime → api tier
41 // RPC; this single ceiling is the Phase 1 backstop.
42 BRIVEN_REALTIME_MAX_SUBS_PER_PROJECT: z.coerce.number().int().positive().default(10_000),
43});
44
45export type Env = z.infer<typeof envSchema>;
46export const env = loadEnv(envSchema);