From ee15c98d6532c767d92ee09aa2a92ace8dafe03b Mon Sep 17 00:00:00 2001 From: Etienne Latendresse Date: Mon, 24 Aug 2026 14:31:37 -0400 Subject: [PATCH] log: export optableMessage, the wrapper debug logger --- lib/core/flags.md | 28 ++++++++++++++-------------- lib/core/log.test.ts | 31 ++++++++++++++++++++++++++++++- lib/core/log.ts | 10 +++++++++- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/lib/core/flags.md b/lib/core/flags.md index 115eafee..07270ae0 100644 --- a/lib/core/flags.md +++ b/lib/core/flags.md @@ -54,20 +54,20 @@ if (controlGroup === "1") { ## Available flags -| Flag | Read by | Effect | -| --------------------------- | ---------------------- | ------------------------------------------------------------------------------------- | -| `optableDebug` | `debugLog`, RTD module | Verbose logging. | -| `optableDisableConsent` | `getConsent` | Bypass the CMP and treat all permissions as granted. | -| `optableControlGroup` | `setupAB` | `1` forces the control variant, `0` forces treatment. Two-state — read the raw value. | -| `optableForceTargeting` | wrapper code | Re-run targeting even when a session guard says it already ran. | -| `optableForceTokenize` | wrapper code | Re-run tokenize even when a session guard says it already ran. | -| `optableForceGlobalRouting` | `buildRTD` | Route every EID to `global` instead of per-bidder. | -| `optableForceSkipMerge` | `buildRTD` | Skip merging EIDs into the auction entirely. | -| `optableResolve1P` | wrapper code | Resolve using a first-party test identifier. | -| `optableResolve3P` | wrapper code | Resolve using a third-party test IP. | -| `optableEnableAnalytics` | wrapper code | Force analytics on, ignoring the sampling rate. | -| `optableResolveId5` | wrapper code | Return a placeholder ID5 value without loading the ID5 API. | -| `optableResolveID5ID` | wrapper code | Return a specific ID5 value without loading the ID5 API. | +| Flag | Read by | Effect | +| --------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------- | +| `optableDebug` | `debugLog`, `optableMessage`, RTD module | Verbose logging. | +| `optableDisableConsent` | `getConsent` | Bypass the CMP and treat all permissions as granted. | +| `optableControlGroup` | `setupAB` | `1` forces the control variant, `0` forces treatment. Two-state — read the raw value. | +| `optableForceTargeting` | wrapper code | Re-run targeting even when a session guard says it already ran. | +| `optableForceTokenize` | wrapper code | Re-run tokenize even when a session guard says it already ran. | +| `optableForceGlobalRouting` | `buildRTD` | Route every EID to `global` instead of per-bidder. | +| `optableForceSkipMerge` | `buildRTD` | Skip merging EIDs into the auction entirely. | +| `optableResolve1P` | wrapper code | Resolve using a first-party test identifier. | +| `optableResolve3P` | wrapper code | Resolve using a third-party test IP. | +| `optableEnableAnalytics` | wrapper code | Force analytics on, ignoring the sampling rate. | +| `optableResolveId5` | wrapper code | Return a placeholder ID5 value without loading the ID5 API. | +| `optableResolveID5ID` | wrapper code | Return a specific ID5 value without loading the ID5 API. | "Wrapper code" means the flag is recognised and persisted by the SDK, but acted on by the bundle built around it. Unknown query parameters are ignored — only the keys above are parsed. diff --git a/lib/core/log.test.ts b/lib/core/log.test.ts index 6a985b31..f524b813 100644 --- a/lib/core/log.test.ts +++ b/lib/core/log.test.ts @@ -1,4 +1,4 @@ -import { consoleLog, debugLog } from "./log"; +import { consoleLog, debugLog, optableMessage } from "./log"; import { resetFlags } from "./flags"; beforeEach(() => { @@ -45,6 +45,35 @@ describe("debugLog", () => { }); }); +describe("optableMessage", () => { + it("is silent when optableDebug is not set", () => { + const spy = jest.spyOn(console, "log").mockImplementation(() => {}); + optableMessage("hello"); + expect(spy).not.toHaveBeenCalled(); + spy.mockRestore(); + }); + + it("logs with the wrapper prefix and passes arguments through", () => { + sessionStorage.setItem("optableDebug", "1"); + resetFlags(); + + const spy = jest.spyOn(console, "log").mockImplementation(() => {}); + optableMessage("hello", { detail: 1 }); + expect(spy).toHaveBeenCalledWith("[OPTABLE WRAPPER]", "hello", { detail: 1 }); + spy.mockRestore(); + }); + + it("stays silent when optableDebug is explicitly disabled", () => { + sessionStorage.setItem("optableDebug", "0"); + resetFlags(); + + const spy = jest.spyOn(console, "log").mockImplementation(() => {}); + optableMessage("hello"); + expect(spy).not.toHaveBeenCalled(); + spy.mockRestore(); + }); +}); + describe("consoleLog", () => { it("writes unconditionally with the given prefix", () => { const spy = jest.spyOn(console, "warn").mockImplementation(() => {}); diff --git a/lib/core/log.ts b/lib/core/log.ts index af543e3a..4bc2d62e 100644 --- a/lib/core/log.ts +++ b/lib/core/log.ts @@ -14,4 +14,12 @@ function debugLog(level: string, message: string, ...args: any[]): void { } } -export { consoleLog, debugLog }; +// Debug logger for wrapper bundles, gated on the optableDebug flag. The +// "[OPTABLE WRAPPER]" prefix is what QA filters on. +function optableMessage(...args: any[]): void { + if (flagEnabled("optableDebug")) { + console.log("[OPTABLE WRAPPER]", ...args); // eslint-disable-line no-console + } +} + +export { consoleLog, debugLog, optableMessage };