diff --git a/website/components/OneDollarStats.tsx b/website/components/OneDollarStats.tsx index 1daeed3..7082260 100644 --- a/website/components/OneDollarStats.tsx +++ b/website/components/OneDollarStats.tsx @@ -211,6 +211,14 @@ export function initOneDollarStats(): void { const flags = readFlagsFromCookie(); + // Expose the active A/B flags on window.DECO.flags so app code and GTM can + // read the visitor's cohort (a read-only mirror of the deco_segment cookie). + // Kept off window.DECO.events, which is the event bus, not state. Cast to + // avoid coupling to the bus's Window typing (declared by the site runtime). + const deco = (window as unknown as { DECO?: { flags?: Record } }).DECO ?? {}; + deco.flags = flags; + (window as unknown as { DECO?: unknown }).DECO = deco; + // 1) Initial pageview + SPA nav tracking, with flag enrichment. whenReady( () => diff --git a/website/components/__tests__/OneDollarStats.test.ts b/website/components/__tests__/OneDollarStats.test.ts index ed6d7df..a1db2b8 100644 --- a/website/components/__tests__/OneDollarStats.test.ts +++ b/website/components/__tests__/OneDollarStats.test.ts @@ -125,6 +125,32 @@ describe("initOneDollarStats", () => { expect(view).toHaveBeenCalledWith({ abtest_a: true }); }); + it("exposes the active flags on window.DECO.flags", () => { + setStonks(); + document.cookie = `deco_segment=${btoa( + encodeURIComponent(JSON.stringify({ active: ["abtest_a"], inactiveDrawn: ["abtest_b"] })), + )}`; + + initOneDollarStats(); + + expect((window as Window & { DECO?: { flags?: unknown } }).DECO?.flags).toEqual({ + abtest_a: true, + abtest_b: false, + }); + }); + + it("preserves window.DECO.events when exposing flags", () => { + setStonks(); + setDeco(); + document.cookie = `deco_segment=${btoa(encodeURIComponent(JSON.stringify({ active: ["x"] })))}`; + + initOneDollarStats(); + + const deco = (window as Window & { DECO?: { flags?: unknown; events?: unknown } }).DECO; + expect(deco?.flags).toEqual({ x: true }); + expect(deco?.events).toBeDefined(); + }); + it("waits for stonks via polling when SDK loads late", () => { const view = vi.fn(); // Stonks NOT set yet.