import { $replica } from "~/db.server"; import { env } from "~/env.server"; import { logger } from "~/services/logger.server"; import { BoundedTtlCache } from "~/services/realtime/boundedTtlCache"; import { singleton } from "~/utils/singleton"; import { FEATURE_FLAG } from "~/v3/featureFlags"; import { makeFlag } from "~/v3/featureFlags.server"; import { isSplitEnabled } from "./splitMode.server"; export type RunIdMintKind = "cuid" | "runOpsId"; type MintKindDeps = { masterEnabled: boolean; splitEnabled: () => Promise; // Receives the orgId + the (optional) already-loaded org feature flags. When // orgFeatureFlags is provided, the implementation must NOT read the DB for them. flag: (orgId: string, orgFeatureFlags: unknown | undefined) => Promise; }; // PURE CORE — no env import; tests drive this directly. Gate order is load-bearing: // master switch → split gate → per-org flag, short-circuiting at the first OFF. export async function computeRunIdMintKind( environment: { organizationId: string; id: string; orgFeatureFlags?: unknown }, deps: MintKindDeps ): Promise { if (!deps.masterEnabled) return "cuid"; if (!(await deps.splitEnabled())) return "cuid"; try { return await deps.flag(environment.organizationId, environment.orgFeatureFlags); } catch (error) { logger.error("[runOpsMintKind] flag read failed; minting cuid (fail-safe)", { error }); return "cuid"; } } // ENV-BOUND wrapper — the only place env/$replica/isSplitEnabled are read. const flagFn = singleton("runOpsMintFlag", () => makeFlag($replica)); const mintCache = singleton( "runOpsMintCache", () => new BoundedTtlCache( env.RUN_OPS_MINT_FLAG_CACHE_TTL_MS, env.RUN_OPS_MINT_FLAG_CACHE_MAX_ENTRIES ) ); export async function resolveRunIdMintKind(environment: { organizationId: string; id: string; // Pass environment.organization.featureFlags from the trigger call site. orgFeatureFlags?: unknown; }): Promise { return computeRunIdMintKind(environment, { masterEnabled: env.RUN_OPS_MINT_ENABLED, splitEnabled: isSplitEnabled, flag: async (orgId, orgFeatureFlags) => { // The cache stores only "cuid"|"runOpsId" (never undefined), so the cache's // "stored-undefined == miss" caveat never applies here. const cached = mintCache.get(orgId); if (cached !== undefined) return cached; // Hot-path pass-through: use the org flags the authenticated environment already // carries; only fall back to a DB read when the caller did NOT pass them (non-trigger // callers). The trigger path always passes them, so it never issues this findFirst. const overrides = orgFeatureFlags !== undefined ? orgFeatureFlags : ( await $replica.organization.findFirst({ where: { id: orgId }, select: { featureFlags: true }, }) )?.featureFlags; const kind = await flagFn({ key: FEATURE_FLAG.runOpsMintKind, defaultValue: "cuid", overrides: (overrides as Record) ?? {}, }); mintCache.set(orgId, kind); return kind; }, }); }