diff --git a/src/app/functions/server/getExperiments.ts b/src/app/functions/server/getExperiments.ts index 205a036af4f..5286e799d0d 100644 --- a/src/app/functions/server/getExperiments.ts +++ b/src/app/functions/server/getExperiments.ts @@ -12,6 +12,14 @@ import { import { ExperimentationId } from "./getExperimentationId"; import { getEnabledFeatureFlags } from "../../../db/tables/featureFlags"; +/** + * After we removing the `CirrusV2` flag, we can return the full `ExperimentData`/ + * But until then, we can make the old experiment data object look like the new one, + * but we can't backfill the `Enrollments` property. + */ +export type ExperimentData_V2_Or_V2LikeV1 = Partial & + Required>; + /** * Call the Cirrus sidecar, which returns a list of eligible experiments for the current user. * @@ -28,7 +36,7 @@ export async function getExperiments(params: { locale: string; countryCode: string; previewMode: boolean; -}): Promise { +}): Promise { if (["local"].includes(process.env.APP_ENV ?? "local")) { return localExperimentData; } @@ -78,16 +86,22 @@ export async function getExperiments(params: { throw new Error(`Cirrus request failed: ${response.statusText}`); } - const json = await response.json(); + // With the `CirrusV2` flag enabled, the response is `ExperimentData`, + // otherwise, it's just `ExperimentData["Features"]`. + const json = (await response.json()) as + | ExperimentData + | ExperimentData["Features"]; - let experimentData; + let experimentData: ExperimentData_V2_Or_V2LikeV1; if (flags.includes("CirrusV2")) { - experimentData = json["Features"]; + experimentData = json as ExperimentData; } else { - experimentData = json; + experimentData = { + Features: json as ExperimentData["Features"], + }; } - return (experimentData as ExperimentData) ?? defaultExperimentData; + return experimentData ?? defaultExperimentData; } catch (ex) { logger.error("Could not connect to Cirrus", { serverUrl, diff --git a/src/app/hooks/useGlean.ts b/src/app/hooks/useGlean.ts index 4a966ddab58..a749280e21e 100644 --- a/src/app/hooks/useGlean.ts +++ b/src/app/hooks/useGlean.ts @@ -44,7 +44,10 @@ export const useGlean = () => { // Record the `nimbus_*` keys on all events. // `nimbus_*` is set on every metric, but it's too much work for TypeScript // to infer that — hence the type assertion. - if (experimentData) { + if ( + experimentData && + typeof experimentData["Enrollments"] !== "undefined" + ) { (data as GleanMetricMap["button"]["click"]).nimbus_user_id = experimentData["Enrollments"]["nimbus_user_id"]; (data as GleanMetricMap["button"]["click"]).nimbus_app_id = diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 223af998da0..1c22765a892 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -72,8 +72,11 @@ export default async function RootLayout({ previewMode: nimbusPreviewMode === "true", }); - const nimbus_user_id = experimentData["Enrollments"].nimbus_user_id; - if (nimbus_user_id !== experimentationId) { + const nimbus_user_id = experimentData["Enrollments"]?.nimbus_user_id; + if ( + typeof nimbus_user_id !== "undefined" && + nimbus_user_id !== experimentationId + ) { Sentry.captureMessage( `Nimbus user ID from Cirrus: [${nimbus_user_id}] did not match experimentationId: [${experimentationId}]`, ); diff --git a/src/contextProviders/experiments.tsx b/src/contextProviders/experiments.tsx index 0e9e5dcd35f..875dd555c17 100644 --- a/src/contextProviders/experiments.tsx +++ b/src/contextProviders/experiments.tsx @@ -5,14 +5,15 @@ "use client"; import { ReactNode, createContext, useContext } from "react"; -import { ExperimentData } from "../telemetry/generated/nimbus/experiments"; +import { ExperimentData_V2_Or_V2LikeV1 } from "../app/functions/server/getExperiments"; interface ExperimentsProviderProps { children: ReactNode; - experimentData: ExperimentData; + experimentData: ExperimentData_V2_Or_V2LikeV1; } -export const ExperimentsContext = createContext(null); +export const ExperimentsContext = + createContext(null); export const ExperimentsProvider = ({ children,