export type JsonPrimitive = string | number | boolean | null; export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue; }; export type FeedbackSeverity = "low" | "medium" | "high" | "blocking"; export type FeedbackCategory = "bug" | "ux" | "content" | "performance" | "accessibility" | "other"; export interface FeedbackUser { id?: string; email?: string; name?: string; [key: string]: JsonValue | undefined; } export interface ElementSummary { tagName: string; role?: string; label?: string; href?: string; id?: string; className?: string; testId?: string; } export interface NavigationEvent { type: "navigation"; url: string; title?: string; source?: string; referrer?: string; timestamp: string; } export interface InteractionEvent { type: "click"; url: string; target: ElementSummary; timestamp: string; } export interface RuntimeErrorEvent { type: "error" | "unhandledrejection"; url: string; message: string; stack?: string; timestamp: string; } export type FeedbackTimelineEvent = NavigationEvent | InteractionEvent | RuntimeErrorEvent; export interface BrowserContext { url?: string; title?: string; referrer?: string; userAgent?: string; language?: string; timezone?: string; viewport?: { width: number; height: number; devicePixelRatio: number; }; screen?: { width: number; height: number; }; } export interface FeedbackScreenshot { dataUrl: string; mediaType: string; width?: number; height?: number; capturedAt: string; source: "display-media" | "html2canvas" | "custom" | string; } export interface FeedbackDraft { message: string; expected?: string; severity: FeedbackSeverity; category: FeedbackCategory; userEmail?: string; includeScreenshot?: boolean; tags?: string[]; metadata?: Record; } export interface FeedbackReport { id: string; appId?: string; createdAt: string; url?: string; title?: string; user?: FeedbackUser; browser: BrowserContext; feedback: { message: string; expected?: string; severity: FeedbackSeverity; category: FeedbackCategory; userEmail?: string; tags: string[]; }; navigation: NavigationEvent[]; recentActivity: FeedbackTimelineEvent[]; screenshot?: FeedbackScreenshot; metadata: Record; developerPrompt: string; } export interface ScreenshotCaptureContext { currentUrl?: string; title?: string; draft: FeedbackDraft; } export type ScreenshotCapture = (context: ScreenshotCaptureContext) => Promise | FeedbackScreenshot | null; export type FeedbackSubmitHandler = (report: FeedbackReport) => Promise | void; export interface FeedbackSessionOptions { appId?: string; endpoint?: string; user?: FeedbackUser | (() => FeedbackUser | undefined); metadata?: Record; onSubmit?: FeedbackSubmitHandler; captureScreenshot?: ScreenshotCapture; captureClicks?: boolean; captureErrors?: boolean; maxEvents?: number; fetcher?: typeof fetch; /** * Transform every captured URL (navigation, clicks, errors, report url, * browser context url/referrer) before it is stored. Use it to strip * query strings or tokens. Return the URL to record. */ scrubUrl?: (url: string) => string; }