Files
2026-07-13 13:32:57 +08:00

85 lines
3.2 KiB
TypeScript

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<boolean>;
// 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<RunIdMintKind>;
};
// 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<RunIdMintKind> {
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<RunIdMintKind>(
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<RunIdMintKind> {
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<string, unknown>) ?? {},
});
mintCache.set(orgId, kind);
return kind;
},
});
}