From b71310245112c698c76e7c25dd62572385038e79 Mon Sep 17 00:00:00 2001 From: pandeymangg Date: Mon, 19 Oct 2026 16:33:02 +0530 Subject: [PATCH] feat: type the formbricks_debug event for on() --- packages/js/src/index.ts | 1 + packages/js/src/lib/load-formbricks.test.ts | 26 +++++++++++++++++++-- packages/js/src/types/formbricks.ts | 18 ++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/packages/js/src/index.ts b/packages/js/src/index.ts index f9a74fc..b5dc892 100644 --- a/packages/js/src/index.ts +++ b/packages/js/src/index.ts @@ -28,6 +28,7 @@ const formbricks: TFormbricks = { export type { 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 7550a6e..1527124 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; @@ -712,6 +720,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 7bae283..36f1cfc 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; +} + /** * What `setEmbeddedData` accepts. Mirrors js-core's `TEmbeddedDataInput` * (packages/js-core/src/lib/survey/embedded-data.ts in the formbricks monorepo): `null` removes a