import 'rollup-plugin-inject-process-env'; /** * Event tracking types for form widget interaction events * * API Endpoint: POST /cms/widget/events * @see https://github.com/XappMedia/chat-widget/blob/master/docs/widget-events-api.md */ /** * Base metadata included in all events */ export interface WidgetEventMetadata { /** ISO 8601 timestamp of when the event occurred */ timestamp: string; /** Unique session identifier */ sessionId: string; /** Form identifier (form.name) */ formId: string; /** User identifier (if known) */ userId?: string; utm_source?: string; utm_medium?: string; utm_campaign?: string; utm_term?: string; utm_content?: string; /** Google Click ID */ gclid?: string; /** Facebook Click ID */ fbclid?: string; /** Microsoft Click ID */ msclkid?: string; /** Current page URL */ currentUrl?: string; /** Browser user agent */ userAgent?: string; [key: string]: string | undefined; } /** * @deprecated Use WidgetEventMetadata instead */ export type EventMetadata = WidgetEventMetadata; /** * Event data for form_open event - Form Widget Opened * Sent when the form widget is first displayed to the user. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_OPEN" */ export interface FormOpenEventData { /** Name of the form */ formName: string; /** Total number of steps in the form */ totalSteps: number; /** Name of the first step */ firstStepName?: string; /** * 0-based index of the step being displayed. Always 0 for form_open - the * form starts on its first step. Read generically by stentor-api's * StentorEventToEsConverter (lastStepIndex ?? completedStepIndex ?? finalStepIndex) * to populate the funnel step stage; the literal 0 is preserved by nullish coalescing. */ lastStepIndex: number; } export interface FormOpenEvent { eventType: "form_open"; metadata: WidgetEventMetadata; data: FormOpenEventData; } /** * What caused an `engaged` event to fire - the first genuine user action * taken after the form was displayed. */ export type EngagementTrigger = /** User manually opened the form (button/chip click or window.xafwControl.openForm) */ "manual_open" /** User clicked a suggestion chip */ | "chip_click" /** User completed the first step and moved to the next one */ | "step_transition"; /** * Event data for engaged event - Form Widget Genuine Engagement * Sent once per session, the first time a user takes a genuine action on the * form (as opposed to the form merely being rendered/opened - see form_open). * Additive to form_open; does not replace it, so form_open remains an * impression signal and this becomes the "did a human actually engage" signal. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_ENGAGED" */ export interface EngagedEventData { /** Name of the form */ formName: string; /** What triggered the engagement */ trigger: EngagementTrigger; /** Name of the first step of the form */ firstStepName?: string; } export interface EngagedEvent { eventType: "engaged"; metadata: WidgetEventMetadata; data: EngagedEventData; } /** * Event data for next_step event - Form Step Completed * Sent when a user completes a step in a multi-step form and moves to the next step. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_STEP" */ export interface NextStepEventData { /** Name of the step just completed */ completedStepName: string; /** 0-based index of completed step */ completedStepIndex: number; /** Name of the next step (if any) */ nextStepName?: string; /** Data collected in this step */ stepData?: Record; /** True if this was the final step before submit */ isLastStep?: boolean; } export interface NextStepEvent { eventType: "next_step"; metadata: WidgetEventMetadata; data: NextStepEventData; } /** * Event data for previous_step event - Form Step Back Navigation * Sent when a user navigates back to a previous step in a multi-step form. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_PREV_STEP" */ export interface PreviousStepEventData { /** Name of the step user was on before going back */ fromStepName: string; /** 0-based index of the step user was on */ fromStepIndex: number; /** Name of the step user navigated to */ toStepName: string; /** 0-based index of the step user navigated to */ toStepIndex: number; /** * 0-based index of the step being navigated to (mirrors toStepIndex). * Read generically by stentor-api's StentorEventToEsConverter to populate * the funnel step stage - see FormOpenEventData.lastStepIndex. */ lastStepIndex: number; /** Total number of steps in the form */ totalSteps: number; } export interface PreviousStepEvent { eventType: "previous_step"; metadata: WidgetEventMetadata; data: PreviousStepEventData; } /** * Event data for step_change event - Generic Step Navigation * Sent on any step change (forward or backward) for comprehensive tracking. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_STEP_CHANGE" */ export interface StepChangeEventData { /** Name of the step user was on */ fromStepName: string; /** 0-based index of the step user was on */ fromStepIndex: number; /** Name of the step user navigated to */ toStepName: string; /** 0-based index of the step user navigated to */ toStepIndex: number; /** Direction of navigation */ direction: "forward" | "backward"; /** * 0-based index of the step being navigated to (mirrors toStepIndex). * Read generically by stentor-api's StentorEventToEsConverter to populate * the funnel step stage - see FormOpenEventData.lastStepIndex. */ lastStepIndex: number; /** Total number of steps in the form */ totalSteps: number; } export interface StepChangeEvent { eventType: "step_change"; metadata: WidgetEventMetadata; data: StepChangeEventData; } /** * Event data for submit event - Form Submitted * Sent when a user successfully submits the complete form. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_SUBMIT" */ export interface SubmitEventData { /** Name of the final step */ finalStepName: string; /** 0-based index of final step */ finalStepIndex: number; /** Total number of steps in the form */ totalSteps: number; /** All collected form data */ completedData?: Record; } export interface SubmitEvent { eventType: "submit"; metadata: WidgetEventMetadata; data: SubmitEventData; } /** * Event data for submit_failure event - Form Submission Failed * Sent when the FORM_SUBMIT dispatch that creates the lead failed outright, after * retries. The submit event above is recorded on a different endpoint *before* that * dispatch, so this is the only signal distinguishing "submitted" from "lead created" * (issue #1373). * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_SUBMIT_FAILURE" */ export interface SubmitFailureEventData { /** Name of the step the submit was dispatched from */ finalStepName: string; /** 0-based index of that step */ finalStepIndex: number; /** Total number of steps in the form */ totalSteps: number; /** Error message from the failed dispatch */ reason: string; } export interface SubmitFailureEvent { eventType: "submit_failure"; metadata: WidgetEventMetadata; data: SubmitFailureEventData; } /** * Event data for close event - Form Widget Closed * Sent when a user explicitly closes the form widget (clicks X button). * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_CLOSE" */ export interface CloseEventData { /** Name of the step user was on when closing */ lastStepName: string; /** 0-based index of last step */ lastStepIndex: number; /** Number of steps fully completed */ totalStepsCompleted: number; /** Total number of steps in the form */ totalSteps: number; /** Data collected before closing (may be empty) */ formData?: Record; } export interface CloseEvent { eventType: "close"; metadata: WidgetEventMetadata; data: CloseEventData; } /** * Reason for form abandonment (used in partial_data events) */ export type AbandonmentReason = /** User closed browser tab or navigated away (beforeunload) */ "close_tab" /** Tab was hidden/inactive until midnight local time */ | "timeout" /** User explicitly closed the form widget (clicked X) */ | "widget_close"; /** * Event data for partial_data event - Form Abandoned * Sent when a user leaves the form without completing it (tab close or timeout). * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_ABANDON" */ export interface PartialDataEventData { /** Name of the last step the user was on */ lastStepName: string; /** 0-based index of last step */ lastStepIndex: number; /** Number of steps fully completed */ totalStepsCompleted: number; /** Total number of steps in the form */ totalSteps: number; /** Percentage of form completed (0-100) */ completionPercentage?: number; /** Data collected before abandonment */ partialData?: Record; /** Reason for abandonment (optional) */ abandonmentReason?: AbandonmentReason; } export interface PartialDataEvent { eventType: "partial_data"; metadata: WidgetEventMetadata; data: PartialDataEventData; } /** * Base data shared by all booking-widget handoff events: which step, and which * partner (derived from the embed script's hostname). formName/sessionId are * not repeated here -- they're already carried on every event via metadata. */ export interface HandoffEventData { /** Name of the external-widget handoff step */ stepName: string; /** Partner identifier, derived from externalWidget.scriptSrc's hostname */ provider: string; } /** * Event data for handoff_rendered event - Booking Widget Rendered * Sent when the handoff step's anchor gains child nodes within renderTimeoutMs. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_HANDOFF_RENDERED" */ export type HandoffRenderedEventData = HandoffEventData; export interface HandoffRenderedEvent { eventType: "handoff_rendered"; metadata: WidgetEventMetadata; data: HandoffRenderedEventData; } /** * Event data for handoff_no_render event - Booking Widget Failed To Render * Sent when renderTimeoutMs elapses with an empty anchor. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_HANDOFF_NO_RENDER" */ export type HandoffNoRenderEventData = HandoffEventData; export interface HandoffNoRenderEvent { eventType: "handoff_no_render"; metadata: WidgetEventMetadata; data: HandoffNoRenderEventData; } /** * Event data for handoff_scheduled event - Booking Widget Appointment Scheduled * Sent when the partner script invokes the configured successCallbackKey callback. * This is how the booking outcome reaches stentor_events -- it is joinable on * sessionId with the lead captured by the preceding crmSubmit step. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_HANDOFF_SCHEDULED" */ export interface HandoffScheduledEventData extends HandoffEventData { /** Whatever (if anything) the partner's success callback was invoked with */ payload?: unknown; } export interface HandoffScheduledEvent { eventType: "handoff_scheduled"; metadata: WidgetEventMetadata; data: HandoffScheduledEventData; } /** * Event data for handoff_error event - Booking Widget Script Error * Sent when the partner's embed script fails to load, or its scriptSrc is rejected. * Stored as: eventType: "AnalyticsEvent", eventName: "WIDGET_FORM_HANDOFF_ERROR" */ export type HandoffErrorEventData = HandoffEventData; export interface HandoffErrorEvent { eventType: "handoff_error"; metadata: WidgetEventMetadata; data: HandoffErrorEventData; } /** * Union type of all possible widget events */ export type WidgetEvent = FormOpenEvent | EngagedEvent | NextStepEvent | PreviousStepEvent | StepChangeEvent | SubmitEvent | SubmitFailureEvent | CloseEvent | PartialDataEvent | HandoffRenderedEvent | HandoffNoRenderEvent | HandoffScheduledEvent | HandoffErrorEvent; /** * @deprecated Use WidgetEvent instead */ export type FormWidgetEvent = WidgetEvent; /** * Event type strings */ export type WidgetEventType = "form_open" | "engaged" | "next_step" | "previous_step" | "step_change" | "submit" | "submit_failure" | "close" | "partial_data" | "handoff_rendered" | "handoff_no_render" | "handoff_scheduled" | "handoff_error"; /** * @deprecated Use WidgetEventType instead */ export type FormWidgetEventType = WidgetEventType; /** * Request body for the widget events API * POST /cms/widget/events * * Authentication uses the widget key in the request body (not headers), * making this endpoint compatible with navigator.sendBeacon(). */ export interface WidgetEventsRequest { /** Widget key from AppLink table (required for authentication) */ key: string; /** Array of events to track */ events: WidgetEvent[]; } /** * Response from the widget events API */ export interface WidgetEventsResponse { /** Number of events successfully queued for processing */ processed: number; }