diff --git a/packages/js/src/index.ts b/packages/js/src/index.ts index 4980151..9315394 100644 --- a/packages/js/src/index.ts +++ b/packages/js/src/index.ts @@ -36,6 +36,7 @@ const formbricks: TFormbricks = { export type { TAppearance, TEmbeddedDataInput, + TFormbricksDebugEvent, TFormbricksEventName, TFormbricksEventPayloads, } from "./types/formbricks"; diff --git a/packages/js/src/lib/load-formbricks.test.ts b/packages/js/src/lib/load-formbricks.test.ts index 7c1cabc..055ae83 100644 --- a/packages/js/src/lib/load-formbricks.test.ts +++ b/packages/js/src/lib/load-formbricks.test.ts @@ -1,5 +1,13 @@ -import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; -import type { TSetupConfig } from "../types/formbricks"; +import { + afterEach, + beforeEach, + describe, + expect, + expectTypeOf, + test, + vi, +} from "vitest"; +import type { TFormbricksDebugEvent, TSetupConfig } from "../types/formbricks"; // We need to import the module after each reset let setup: (config: TSetupConfig) => Promise; @@ -714,6 +722,20 @@ describe("load-formbricks", () => { ); }); + // Debug mode's event. The wrapper forwards it like any other; the SDK decides when it fires. + test("formbricks_debug passes through to the SDK, with its own payload type", async () => { + const instance = createEmittingInstance(); + await runSetupWith(instance); + + const handler = vi.fn((event: TFormbricksDebugEvent) => { + expectTypeOf(event.type).toEqualTypeOf<"survey" | "visit">(); + expectTypeOf(event.at).toEqualTypeOf(); + }); + on("formbricks_debug", handler); + + expect(instance.on).toHaveBeenCalledWith("formbricks_debug", handler); + }); + test("an older self-hosted SDK without events warns instead of crashing", async () => { const consoleWarnSpy = createConsoleWarnSpy(); const legacyInstance = { ...mockFormbricks }; // no on/off diff --git a/packages/js/src/types/formbricks.ts b/packages/js/src/types/formbricks.ts index 5376322..146d180 100644 --- a/packages/js/src/types/formbricks.ts +++ b/packages/js/src/types/formbricks.ts @@ -13,10 +13,28 @@ export interface TFormbricksEventPayloads { finished: boolean; }; formbricks_survey_closed: { surveyId: string }; + /** + * Debug mode only (`?formbricksDebug=true`): why each survey on a fired trigger did or did not + * show, with every show condition's result, and the visitor's visit. A new subscriber first gets + * what already happened on the page. Never pushed to the GTM dataLayer. Instances without show + * conditions never send it. + */ + formbricks_debug: TFormbricksDebugEvent; } export type TFormbricksEventName = keyof TFormbricksEventPayloads; +/** + * The `formbricks_debug` payload. Typed loosely on purpose: its shape may change between versions, + * so read it to debug, not to build on. `type` tells a survey decision from a visit update. + */ +export interface TFormbricksDebugEvent { + type: "survey" | "visit"; + /** When it happened, in milliseconds since the Unix epoch. */ + at: number; + [key: string]: unknown; +} + /** * How surveys render. Mirrors js-core's `TAppearance` (packages/js-core/src/lib/common/appearance.ts * in the formbricks monorepo). "system" follows the browser's color scheme.