import { Q as QaStatusArtifact } from './types-CRbb2Pp0.js'; type FeedbackEnv = 'dev' | 'staging' | 'prod' | (string & {}); declare global { var __MFB_VERSION__: string | undefined; } type FeedbackType = 'bug' | 'feature' | 'question' | 'praise' | 'typo'; type FeedbackSeverity = 'blocker' | 'high' | 'medium' | 'low'; type CaptureMethod = 'html2canvas' | 'display_media' | 'manual' | 'none'; interface UserIdentity { id?: string | number; email?: string; name?: string; /** * v0.13 — host-computed HMAC over `v1\x00{project_id}\x00{external_id} * \x00{email}\x00{exp}` using the project's signing secret. When * present together with `exp`, the widget forwards both as * `X-Mhosaic-User-Hmac` + `X-Mhosaic-User-Exp` headers and the * backend rejects unsigned requests for projects that have opted in. * Hosts compute this server-side; the secret never leaves the host's * backend. Omit both fields for the legacy unsigned path. */ userHash?: string; /** Unix-seconds expiry of the signature, e.g. `Math.floor(Date.now()/1000) + 3600`. */ exp?: number; } /** Opt-in QA Meter (second FAB) configuration. Presence of `source` is what * enables the FAB. The host serves its own `qa-status.json` (built by * `mhosaic-feedback qa refresh`); no backend involved. */ interface QaMeterConfig { /** URL string | inline artifact | async loader. */ source: string | QaStatusArtifact | (() => Promise); /** Defaults to the feedback widget's resolved locale. */ locale?: 'fr' | 'en'; /** Override the auto-stack offset (px from the viewport edges). */ position?: { right?: number; bottom?: number; }; /** Pastille size. Defaults to 'sm' in the integrated path. */ size?: 'sm' | 'md'; /** Router-aware page override; defaults to the routerless resolver. */ getCurrentPage?: () => string | null; } interface FeedbackConfig { apiKey: string; /** * Required. Base URL of your mhosaic-feedback backend * (e.g. "https://feedback.example.com"). The widget will POST reports * to `${endpoint}/api/feedback/v1/reports/`. There is no silent * fallback — a missing endpoint throws at init time. */ endpoint: string; env?: FeedbackEnv; user?: UserIdentity; metadata?: Record; beforeSend?: (payload: ReportPayload) => ReportPayload | false | Promise; onSubmitSuccess?: (report: SubmittedReport) => void; onError?: (err: Error) => void; maskAllInputs?: boolean; sanitizeUrl?: (url: string) => string; showFAB?: boolean; /** Phase 4: gate the FAB on a per-end-user server visibility check. Normally * set automatically by the loader from the manifest's * `requires_visibility_check`; rarely set by hosts directly. */ requiresVisibilityCheck?: boolean; attachTo?: string | Element; locale?: string; translations?: Record; theme?: 'light' | 'dark' | 'auto' | 'none'; /** Opt-in QA Meter second FAB. Set `qaMeter.source` to enable it. */ qaMeter?: QaMeterConfig; } interface ConsoleEntry { level: string; message: string; ts: number; stack?: string; } interface NetworkEntry { url: string; method: string; status: number; durationMs: number; ts: number; error?: string; } interface ErrorEntry { message: string; stack?: string; ts: number; source: 'window.error' | 'unhandledrejection'; } interface DeviceContext { viewport: { w: number; h: number; dpr: number; }; screen?: { w: number; h: number; }; platform?: string; language?: string; timezone?: string; timezoneOffset?: number; connection?: string; online?: boolean; deviceMemory?: number; hardwareConcurrency?: number; referrer?: string; title?: string; pathname?: string; } interface WebVitalEntry { name: 'CLS' | 'INP' | 'LCP' | 'FCP' | 'TTFB'; value: number; rating: 'good' | 'needs-improvement' | 'poor'; attribution?: unknown; } interface ReplayBlob { events: unknown[]; durationMs: number; } interface CapturedContext { consoleLogs: ConsoleEntry[]; networkRequests: NetworkEntry[]; errors: ErrorEntry[]; device: DeviceContext; capturedAt: number; webVitals?: WebVitalEntry[]; replay?: ReplayBlob; /** * Identity supplied via `identify()` — surfaces on the operator side so a * stack trace isn't anonymous. Stored inside technical_context so it * inherits the existing 512 KiB cap and serializer-free contract. */ user?: UserIdentity; /** Free-form host-supplied metadata via `setMetadata()`. */ metadata?: Record; } interface ReportPayload { description: string; feedback_type: FeedbackType; severity: FeedbackSeverity; env: FeedbackEnv; page_url: string; user_agent: string; capture_method: CaptureMethod; technical_context: CapturedContext; screenshot?: Blob; /** v0.7.3: build-time stamp from package.json so the backend can show * per-customer "currently running v0.7.x" on the operator Companies * page. Always set automatically; consumers don't pass this. */ widget_version?: string; /** * The host-supplied identity from `fb.identify({...})`. The backend * uses `id` as the stable cross-session key for "this user's * history of reports on this project" — last-write-wins on email/name. */ user?: { id: string; email?: string; name?: string; }; /** * Set to `true` by `withErrorTracking()` for auto-captured runtime * errors. The backend hides synthetic reports from the default operator * list view; the SPA toggle exposes them grouped by fingerprint. Manual * submissions never set this. */ synthetic?: boolean; } interface SubmittedReport { id: string; status: string; created_at: string; } interface FeedbackApi { show(): void; hide(): void; open(options?: { type?: FeedbackType; description?: string; }): void; submit(partial: Partial & { description: string; }): Promise; identify(user: UserIdentity): void; setMetadata(kv: Record): void; shutdown(): void; } type ReportTransformer = (payload: ReportPayload) => ReportPayload | Promise; export type { CapturedContext as C, FeedbackApi as F, QaMeterConfig as Q, ReportTransformer as R, SubmittedReport as S, UserIdentity as U, FeedbackConfig as a, FeedbackEnv as b, FeedbackSeverity as c, FeedbackType as d, ReportPayload as e };