/** * §3.5 / §6.1. Which product features this build contains, and which of them a * deployment is allowed to switch off. * * Two different questions, deliberately answered by two different inputs: * * - **Installed** is a build-time decision. `VITE_PRODUCT_FEATURES` selects * from the features this source tree declares; a feature left out contributes * no route, no operation, no schema, no codec and no adapter, so nothing can * reach it. It does *not* shrink the bundle: a static import cannot be undone * by a value, and building the import graph from a configuration string is * exactly what §3.5 forbids. Physical removal is FE-GATE-020's job — delete * the feature directory and rebuild, which that gate proves still works. * - **Active** is a runtime decision. `FEATURE_OVERRIDES` in the runtime config * may take an installed feature out of service without a rebuild. * * Both directions are subtractive, and that is the invariant this module * exists to hold: neither input can ever turn on a feature whose source is * absent. A configuration document that could name a feature into existence * would be a configuration document that chooses which code runs, and no * dynamic import path is ever built from one. */ export type ProductFeatureOverride = "DEFAULT" | "DISABLED"; export type ProductFeatureState = /** Compiled in and not disabled: the feature serves traffic. */ | "ACTIVE" /** Compiled in, switched off by the runtime document. */ | "DISABLED_BY_CONFIG" /** Not selected at build time; not in the bundle. */ | "NOT_INSTALLED"; export type ProductFeatureOverrideMap = Readonly< Record >; export type ProductFeatureStatus = Readonly<{ featureId: string; state: ProductFeatureState; }>; /** The shape every feature contract exposes to the manifest. */ export type SelectableProductFeature = Readonly<{ featureId: string }>; /** * The explicit "no product features" selection. * * A blank value cannot mean it: an unset CI variable expands to a blank string * far too easily, and a build that silently shipped no features would be a very * expensive way to learn that. Selecting nothing has to be something you typed. */ export const NO_PRODUCT_FEATURES = "none"; /** * Applies the build-time selection to the features this source tree declares. * * An empty or absent declaration keeps everything, so an ordinary build needs * no environment at all. A declaration naming something that is not compiled is * refused rather than ignored: silently accepting it would let a deployment * believe it had enabled a feature that does not exist. */ export function selectCompiledProductFeatures< Feature extends SelectableProductFeature, >( compiled: readonly Feature[], declared: string | undefined, ): readonly Feature[] { const compiledIds = compiled.map((feature) => feature.featureId); assertUniqueFeatureIds(compiledIds); if (declared === undefined || declared.trim() === "") { return Object.freeze([...compiled]); } if (declared.trim() === NO_PRODUCT_FEATURES) return Object.freeze([]); const requested = declared .split(",") .map((entry) => entry.trim()) .filter((entry) => entry.length > 0); if (requested.length === 0) { throw new Error( `VITE_PRODUCT_FEATURES is set to ${JSON.stringify(declared)}, which names ` + `no feature. Use "${NO_PRODUCT_FEATURES}" to select none, or leave it ` + `unset to keep ${compiledIds.join(", ")}.`, ); } const unknown = requested.filter((id) => !compiledIds.includes(id)); if (unknown.length > 0) { throw new Error( `VITE_PRODUCT_FEATURES names features this build does not contain: ${unknown.join( ", ", )}. Selection can only remove from ${compiledIds.join(", ")}.`, ); } return Object.freeze( compiled.filter((feature) => requested.includes(feature.featureId)), ); } /** * The state of every feature the source tree declares, given what was compiled * and what the runtime document says. * * `compiledIds` is the full declared set rather than the installed one so a * build that dropped a feature still reports it as `NOT_INSTALLED` instead of * omitting it. An operator looking at the platform overview needs to see the * difference between "off" and "never heard of it". */ export function resolveProductFeatures( compiledIds: readonly string[], installedIds: readonly string[], overrides: ProductFeatureOverrideMap = {}, ): readonly ProductFeatureStatus[] { assertUniqueFeatureIds(compiledIds); return Object.freeze( [...compiledIds].sort().map((featureId) => Object.freeze({ featureId, state: !installedIds.includes(featureId) ? ("NOT_INSTALLED" as const) : overrides[featureId] === "DISABLED" ? ("DISABLED_BY_CONFIG" as const) : ("ACTIVE" as const), }), ), ); } /** The feature ids serving traffic right now. */ export function activeProductFeatureIds( statuses: readonly ProductFeatureStatus[], ): readonly string[] { return Object.freeze( statuses .filter((status) => status.state === "ACTIVE") .map((status) => status.featureId), ); } function assertUniqueFeatureIds(ids: readonly string[]): void { if (new Set(ids).size !== ids.length) { throw new Error(`duplicate product feature id: ${ids.join(", ")}`); } }