/** * isSplitEnabled() is the Wave-0 gate. The entire migration/routing/FK-drop family * MUST be unreachable when this returns false. Default is false (single-DB). Never * infer split-vs-single from URL string-equality — distinctness is proven by the * runtime sentinel. */ import { env } from "~/env.server"; import { logger } from "~/services/logger.server"; import { probeDistinctDatabases as defaultProbe } from "./distinctDbSentinel.server"; export type SplitModeConfig = { flagEnabled: boolean; legacyUrl?: string; newUrl?: string; }; export type SplitModeDeps = { probe?: typeof defaultProbe; logger?: { warn: (msg: string, meta?: Record) => void }; }; export async function computeSplitEnabled( config: SplitModeConfig, deps: SplitModeDeps = {} ): Promise { // Hard gate #1: explicit positive opt-in. OFF by default -> never probe. if (!config.flagEnabled) { return false; } // Both URLs are required to even consider a split. if (!config.legacyUrl || !config.newUrl) { deps.logger?.warn( "RUN_OPS_SPLIT_ENABLED is on but RUN_OPS_LEGACY_DATABASE_URL / RUN_OPS_DATABASE_URL are not both set; staying single-DB." ); return false; } // Hard gate #2: runtime sentinel must confirm physically-distinct DBs. const probe = deps.probe ?? defaultProbe; const result = await probe(config.legacyUrl, config.newUrl, { logger: deps.logger }); return result.distinct === true; } export type SplitRealtimeInterlockConfig = { splitEnabled: boolean; nativeRealtimeEnabled: boolean; }; /** * Boot-time realtime interlock (pure predicate). Split mode puts NEW-resident * (run-ops id) runs on the dedicated run-ops DB, but Electric replicates only from the * control-plane DB — with the native realtime backend OFF those runs are invisible * and every realtime subscription hangs. Refuse split unless native is on; split-off * is always allowed regardless of the realtime backend. */ export function assertSplitRealtimeInterlock(config: SplitRealtimeInterlockConfig): void { if (!config.splitEnabled) { return; } if (!config.nativeRealtimeEnabled) { throw new Error( "RUN_OPS_SPLIT_ENABLED is on but the native realtime backend (REALTIME_BACKEND_NATIVE_ENABLED) is not enabled — Electric cannot serve NEW-resident runs; refusing to enable split." ); } } let cached: Promise | undefined; export function isSplitEnabled(): Promise { if (!cached) { cached = computeSplitEnabled( { flagEnabled: env.RUN_OPS_SPLIT_ENABLED, legacyUrl: env.RUN_OPS_LEGACY_DATABASE_URL, newUrl: env.RUN_OPS_DATABASE_URL, }, { logger } ); } return cached; } export function __resetSplitModeCacheForTests(): void { cached = undefined; }