@mhosaic/feedback 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,12 @@ var SCALAR_FIELDS = [
9
9
  "capture_method"
10
10
  ];
11
11
  function createApiClient(options) {
12
- const endpoint = options.endpoint ?? "https://core.mhosaic.com";
12
+ const endpoint = (options.endpoint ?? "").replace(/\/+$/, "");
13
+ if (!endpoint) {
14
+ throw new Error(
15
+ '[mhosaic-feedback] `endpoint` is required (e.g. "https://feedback.example.com").'
16
+ );
17
+ }
13
18
  const fetcher = options.fetch ?? globalThis.fetch;
14
19
  async function submitReport(input) {
15
20
  let payload = input;
@@ -369,8 +374,43 @@ var DEFAULT_STRINGS = {
369
374
  "severity.medium": "Medium",
370
375
  "severity.low": "Low"
371
376
  };
372
- function resolveStrings(overrides) {
373
- return { ...DEFAULT_STRINGS, ...overrides };
377
+ var FRENCH_STRINGS = {
378
+ "fab.label": "Envoyer un commentaire",
379
+ "form.title": "Envoyer un commentaire",
380
+ "form.description.label": "Qu\u2019est-il arriv\xE9 ?",
381
+ "form.description.placeholder": "D\xE9crivez le probl\xE8me ou l\u2019id\xE9e en une ou deux phrases.",
382
+ "form.type.label": "Type",
383
+ "form.severity.label": "S\xE9v\xE9rit\xE9",
384
+ "form.submit": "Envoyer",
385
+ "form.cancel": "Annuler",
386
+ "form.submitting": "Envoi\u2026",
387
+ "form.success": "Merci \u2014 votre commentaire a \xE9t\xE9 envoy\xE9.",
388
+ "form.error": "\xC9chec d\u2019envoi. Veuillez r\xE9essayer.",
389
+ "type.bug": "Bogue",
390
+ "type.feature": "Suggestion",
391
+ "type.question": "Question",
392
+ "type.praise": "Compliment",
393
+ "type.typo": "Coquille",
394
+ "severity.blocker": "Bloquant",
395
+ "severity.high": "\xC9lev\xE9e",
396
+ "severity.medium": "Moyenne",
397
+ "severity.low": "Faible"
398
+ };
399
+ var LOCALE_PACKS = {
400
+ fr: FRENCH_STRINGS
401
+ };
402
+ function packFor(locale) {
403
+ if (!locale) return null;
404
+ const tag = locale.toLowerCase().split(/[-_]/)[0];
405
+ return LOCALE_PACKS[tag] ?? null;
406
+ }
407
+ function resolveStrings(overrides, options = {}) {
408
+ const localePack = packFor(options.locale) ?? {};
409
+ return {
410
+ ...DEFAULT_STRINGS,
411
+ ...localePack,
412
+ ...overrides
413
+ };
374
414
  }
375
415
 
376
416
  // src/widget/mount.tsx
@@ -647,13 +687,17 @@ function mountWidget(options) {
647
687
  // src/core.ts
648
688
  function createFeedback(config) {
649
689
  const env = config.env ?? "prod";
650
- const strings = resolveStrings(config.translations ?? {});
690
+ const locale = config.locale ?? (typeof navigator !== "undefined" ? navigator.language : void 0);
691
+ const strings = resolveStrings(
692
+ config.translations ?? {},
693
+ locale !== void 0 ? { locale } : {}
694
+ );
651
695
  const capture = installCapture({
652
696
  ...config.sanitizeUrl !== void 0 && { sanitizeUrl: config.sanitizeUrl }
653
697
  });
654
698
  const api = createApiClient({
655
699
  apiKey: config.apiKey,
656
- ...config.endpoint !== void 0 && { endpoint: config.endpoint },
700
+ endpoint: config.endpoint,
657
701
  ...config.fetchImpl !== void 0 && { fetch: config.fetchImpl },
658
702
  ...config.beforeSend !== void 0 && { beforeSend: config.beforeSend }
659
703
  });
@@ -702,7 +746,7 @@ function createFeedback(config) {
702
746
  await buildAndSubmit(values);
703
747
  }
704
748
  });
705
- return {
749
+ const instance = {
706
750
  show() {
707
751
  handle.open();
708
752
  },
@@ -732,14 +776,20 @@ function createFeedback(config) {
732
776
  handle.dispose();
733
777
  capture.dispose();
734
778
  host.remove();
779
+ const w = window;
780
+ if (w.mhosaicFeedback === instance) {
781
+ delete w.mhosaicFeedback;
782
+ }
735
783
  },
736
784
  _registerTransformer(fn) {
737
785
  transformers.push(fn);
738
786
  }
739
787
  };
788
+ window.mhosaicFeedback = instance;
789
+ return instance;
740
790
  }
741
791
 
742
792
  export {
743
793
  createFeedback
744
794
  };
745
- //# sourceMappingURL=chunk-RSBFN26C.mjs.map
795
+ //# sourceMappingURL=chunk-PT4HC4CI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/client.ts","../src/capture/urlSanitizer.ts","../src/capture/device.ts","../src/capture/console.ts","../src/capture/network.ts","../src/capture/errors.ts","../src/capture/performance.ts","../src/capture/ringBuffer.ts","../src/capture/index.ts","../src/screenshot/index.ts","../src/widget/i18n.ts","../src/widget/mount.tsx","../src/widget/Fab.tsx","../src/widget/Form.tsx","../src/widget/Modal.tsx","../src/widget/styles.ts","../src/core.ts"],"sourcesContent":["import type { ReportPayload, SubmittedReport } from '../types'\n\nexport interface ApiClientOptions {\n apiKey: string\n endpoint: string\n fetch?: typeof fetch\n beforeSend?: (payload: ReportPayload) => ReportPayload | false | Promise<ReportPayload | false>\n}\n\nexport interface ApiClient {\n submitReport(payload: ReportPayload): Promise<SubmittedReport>\n}\n\nconst SCALAR_FIELDS: Array<keyof ReportPayload> = [\n 'description', 'feedback_type', 'severity', 'env', 'page_url', 'user_agent', 'capture_method',\n]\n\nexport function createApiClient(options: ApiClientOptions): ApiClient {\n // No silent fallback to a hardcoded host — a misconfigured deploy used\n // to leak reports to https://core.mhosaic.com (which doesn't even\n // resolve). Failing fast at construction makes the misconfig obvious.\n const endpoint = (options.endpoint ?? '').replace(/\\/+$/, '')\n if (!endpoint) {\n throw new Error(\n '[mhosaic-feedback] `endpoint` is required (e.g. \"https://feedback.example.com\").',\n )\n }\n const fetcher = options.fetch ?? globalThis.fetch\n\n async function submitReport(input: ReportPayload): Promise<SubmittedReport> {\n let payload: ReportPayload | false = input\n if (options.beforeSend) payload = await options.beforeSend(input)\n if (payload === false) throw new Error('Submission cancelled by beforeSend')\n\n const form = new FormData()\n for (const field of SCALAR_FIELDS) {\n form.append(field, String(payload[field]))\n }\n form.append('technical_context', JSON.stringify(payload.technical_context))\n if (payload.screenshot) form.append('screenshot', payload.screenshot, 'screenshot.png')\n\n const response = await fetcher(`${endpoint}/api/feedback/v1/reports/`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${options.apiKey}` },\n body: form,\n })\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n throw new Error(`Feedback submit failed: ${response.status} ${text}`)\n }\n return response.json() as Promise<SubmittedReport>\n }\n\n return { submitReport }\n}\n","const SENSITIVE = /token|key|password|secret|auth|session|sig/i\n\nexport function sanitizeUrl(url: string): string {\n try {\n // Accept absolute URLs or root-relative paths; reject everything else\n const isAbsolute = /^https?:\\/\\//i.test(url)\n const isRootRelative = url.startsWith('/')\n if (!isAbsolute && !isRootRelative) return url\n\n const base = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'\n const u = new URL(url, base)\n const clean = new URLSearchParams()\n u.searchParams.forEach((value, name) => {\n clean.set(name, SENSITIVE.test(name) ? '[redacted]' : value)\n })\n u.search = clean.toString()\n return u.toString()\n } catch {\n return url\n }\n}\n","import type { DeviceContext } from '../types'\n\nexport function collectDevice(): DeviceContext {\n const nav = navigator as Navigator & { connection?: { effectiveType?: string }; deviceMemory?: number }\n const connection = nav.connection?.effectiveType\n const deviceMemory = nav.deviceMemory\n const referrer = document.referrer || undefined\n return {\n viewport: { w: window.innerWidth, h: window.innerHeight, dpr: window.devicePixelRatio || 1 },\n screen: { w: window.screen.width, h: window.screen.height },\n platform: nav.platform,\n language: nav.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n timezoneOffset: new Date().getTimezoneOffset(),\n ...(connection !== undefined && { connection }),\n online: nav.onLine,\n ...(deviceMemory !== undefined && { deviceMemory }),\n hardwareConcurrency: nav.hardwareConcurrency,\n ...(referrer !== undefined && { referrer }),\n title: document.title,\n pathname: window.location.pathname,\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { ConsoleEntry } from '../types'\n\ntype ConsoleLevel = 'log' | 'info' | 'warn' | 'error' | 'debug'\n\nfunction safeStringify(arg: unknown): string {\n if (arg == null) return String(arg)\n if (typeof arg === 'string') return arg\n if (typeof arg === 'number' || typeof arg === 'boolean') return String(arg)\n if (arg instanceof Error) return `${arg.name}: ${arg.message}`\n if (arg instanceof Element) return `<${arg.tagName.toLowerCase()}>`\n try {\n return JSON.stringify(arg, (_k, v) => (typeof v === 'bigint' ? v.toString() : v))\n } catch {\n try { return String(arg) } catch { return '[unserializable]' }\n }\n}\n\nexport function installConsolePatch(buffer: RingBuffer<ConsoleEntry>): () => void {\n const levels: ConsoleLevel[] = ['log', 'info', 'warn', 'error', 'debug']\n const originals: Partial<Record<ConsoleLevel, (...args: unknown[]) => void>> = {}\n for (const level of levels) {\n const original = console[level] as ((...args: unknown[]) => void) | undefined\n if (typeof original !== 'function') continue\n originals[level] = original\n console[level] = function patched(...args: unknown[]) {\n try {\n const message = args.map(safeStringify).join(' ').slice(0, 2000)\n const entry: ConsoleEntry = { level, message, ts: Date.now() }\n if (level === 'error') {\n const stack = new Error().stack\n if (stack) entry.stack = stack.split('\\n').slice(2, 8).join('\\n')\n }\n buffer.push(entry)\n } catch { /* never break console */ }\n original.apply(console, args)\n }\n }\n return () => {\n for (const [level, fn] of Object.entries(originals)) {\n (console as unknown as Record<string, (...args: unknown[]) => void>)[level] = fn\n }\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { NetworkEntry } from '../types'\n\nexport function installFetchPatch(buffer: RingBuffer<NetworkEntry>, sanitize: (url: string) => string): () => void {\n if (typeof window === 'undefined' || typeof window.fetch !== 'function') return () => {}\n const original = window.fetch.bind(window)\n window.fetch = async function patched(input: RequestInfo | URL, init?: RequestInit) {\n const start = performance.now()\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url\n const method = (init?.method || (input instanceof Request ? input.method : 'GET')).toUpperCase()\n try {\n const response = await original(input, init)\n buffer.push({ url: sanitize(url), method, status: response.status, durationMs: Math.round(performance.now() - start), ts: Date.now() })\n return response\n } catch (err) {\n buffer.push({\n url: sanitize(url), method, status: 0,\n durationMs: Math.round(performance.now() - start),\n ts: Date.now(),\n error: err instanceof Error ? err.message : String(err),\n })\n throw err\n }\n }\n return () => { window.fetch = original }\n}\n\nexport function installXhrPatch(buffer: RingBuffer<NetworkEntry>, sanitize: (url: string) => string): () => void {\n if (typeof window === 'undefined' || typeof window.XMLHttpRequest !== 'function') return () => {}\n const Original = window.XMLHttpRequest\n const originalOpen = Original.prototype.open\n const originalSend = Original.prototype.send\n\n Original.prototype.open = function patchedOpen(this: XMLHttpRequest & { __mfb?: { method: string; url: string; start: number } }, method: string, url: string | URL) {\n this.__mfb = { method: method.toUpperCase(), url: typeof url === 'string' ? url : url.toString(), start: performance.now() }\n return originalOpen.apply(this, arguments as unknown as Parameters<typeof originalOpen>)\n }\n\n Original.prototype.send = function patchedSend(this: XMLHttpRequest & { __mfb?: { method: string; url: string; start: number } }, body?: Document | XMLHttpRequestBodyInit | null) {\n this.addEventListener('loadend', () => {\n try {\n const ctx = this.__mfb\n if (!ctx) return\n buffer.push({\n url: sanitize(ctx.url),\n method: ctx.method,\n status: this.status,\n durationMs: Math.round(performance.now() - ctx.start),\n ts: Date.now(),\n })\n } catch { /* noop */ }\n })\n return originalSend.call(this, body ?? null)\n }\n\n return () => {\n Original.prototype.open = originalOpen\n Original.prototype.send = originalSend\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { ErrorEntry } from '../types'\n\nexport function installErrorHandlers(buffer: RingBuffer<ErrorEntry>): () => void {\n if (typeof window === 'undefined') return () => {}\n const onError = (e: ErrorEvent) => {\n const stack = e.error instanceof Error ? e.error.stack : undefined\n buffer.push({\n message: e.message || 'Unknown error',\n ...(stack !== undefined && { stack }),\n ts: Date.now(),\n source: 'window.error',\n })\n }\n const onRejection = (e: PromiseRejectionEvent) => {\n const reason = e.reason\n const message =\n reason instanceof Error ? reason.message :\n typeof reason === 'string' ? reason :\n (() => { try { return JSON.stringify(reason) } catch { return String(reason) } })()\n const stack = reason instanceof Error ? reason.stack : undefined\n buffer.push({\n message,\n ...(stack !== undefined && { stack }),\n ts: Date.now(),\n source: 'unhandledrejection',\n })\n }\n window.addEventListener('error', onError)\n window.addEventListener('unhandledrejection', onRejection)\n return () => {\n window.removeEventListener('error', onError)\n window.removeEventListener('unhandledrejection', onRejection)\n }\n}\n","export interface PerformanceSnapshot {\n navigation?: { type: string; duration: number }\n longTasks: { duration: number; startTime: number }[]\n slowResources: { name: string; duration: number; initiatorType: string }[]\n}\n\nexport function createPerformanceCollector(slowResourceMs = 1000) {\n const longTasks: PerformanceSnapshot['longTasks'] = []\n const slowResources: PerformanceSnapshot['slowResources'] = []\n let observer: PerformanceObserver | null = null\n\n if (typeof PerformanceObserver !== 'undefined') {\n try {\n observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.entryType === 'longtask') {\n longTasks.push({ duration: entry.duration, startTime: entry.startTime })\n while (longTasks.length > 20) longTasks.shift()\n } else if (entry.entryType === 'resource') {\n const e = entry as PerformanceResourceTiming\n if (e.duration > slowResourceMs) {\n slowResources.push({ name: e.name, duration: e.duration, initiatorType: e.initiatorType })\n while (slowResources.length > 20) slowResources.shift()\n }\n }\n }\n })\n observer.observe({ entryTypes: ['longtask', 'resource'] })\n } catch { /* unsupported */ }\n }\n\n return {\n snapshot(): PerformanceSnapshot {\n const nav = typeof performance !== 'undefined' ? performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined : undefined\n const navigation = nav ? { type: nav.type, duration: nav.duration } : undefined\n return {\n ...(navigation !== undefined && { navigation }),\n longTasks: longTasks.slice(),\n slowResources: slowResources.slice(),\n }\n },\n dispose() { observer?.disconnect() },\n }\n}\n","export class RingBuffer<T> {\n private items: T[] = []\n constructor(private readonly max: number) {}\n\n push(item: T): void {\n this.items.push(item)\n while (this.items.length > this.max) this.items.shift()\n }\n\n snapshot(): T[] {\n return this.items.slice()\n }\n\n clear(): void {\n this.items.length = 0\n }\n}\n","import { sanitizeUrl } from './urlSanitizer'\nimport { collectDevice } from './device'\nimport { installConsolePatch } from './console'\nimport { installFetchPatch, installXhrPatch } from './network'\nimport { installErrorHandlers } from './errors'\nimport { createPerformanceCollector } from './performance'\nimport { RingBuffer } from './ringBuffer'\nimport type { CapturedContext, ConsoleEntry, ErrorEntry, NetworkEntry } from '../types'\n\nexport interface CaptureOptions {\n sanitizeUrl?: (url: string) => string\n maxConsole?: number\n maxNetwork?: number\n maxErrors?: number\n}\n\nexport interface CaptureHandle {\n snapshot(): CapturedContext\n clear(): void\n dispose(): void\n}\n\nexport function installCapture(options: CaptureOptions = {}): CaptureHandle {\n const { maxConsole = 50, maxNetwork = 50, maxErrors = 20 } = options\n const sanitize = options.sanitizeUrl ?? sanitizeUrl\n\n const consoleBuf = new RingBuffer<ConsoleEntry>(maxConsole)\n const networkBuf = new RingBuffer<NetworkEntry>(maxNetwork)\n const errorBuf = new RingBuffer<ErrorEntry>(maxErrors)\n\n const uninstallConsole = installConsolePatch(consoleBuf)\n const uninstallFetch = installFetchPatch(networkBuf, sanitize)\n const uninstallXhr = installXhrPatch(networkBuf, sanitize)\n const uninstallErrors = installErrorHandlers(errorBuf)\n const perf = createPerformanceCollector()\n\n return {\n snapshot(): CapturedContext {\n return {\n consoleLogs: consoleBuf.snapshot(),\n networkRequests: networkBuf.snapshot(),\n errors: errorBuf.snapshot(),\n device: collectDevice(),\n capturedAt: Date.now(),\n }\n },\n clear() {\n consoleBuf.clear(); networkBuf.clear(); errorBuf.clear()\n },\n dispose() {\n uninstallConsole(); uninstallFetch(); uninstallXhr(); uninstallErrors()\n perf.dispose()\n },\n }\n}\n","export function isMaskedElement(el: Element): boolean {\n return el.hasAttribute('data-mfb-mask') || el.classList.contains('mfb-mask')\n}\n\nexport function prepareMaskMatcher(selectors: string[]): (el: Element) => boolean {\n const joined = selectors.join(',').trim()\n if (!joined) return isMaskedElement\n return (el: Element) => isMaskedElement(el) || el.matches(joined)\n}\n\nexport interface ScreenshotOptions {\n mask?: string[]\n maxBytes?: number\n}\n\nexport async function takeScreenshot(target: Element, options: ScreenshotOptions = {}): Promise<Blob | null> {\n if (typeof document === 'undefined') return null\n try {\n const html2canvas = (await import('html2canvas-pro')).default\n const matcher = prepareMaskMatcher(options.mask ?? [])\n const canvas = await html2canvas(target as HTMLElement, {\n ignoreElements: (el) => matcher(el),\n useCORS: true,\n logging: false,\n backgroundColor: null,\n })\n return await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, 'image/png'))\n } catch {\n return null\n }\n}\n","export const DEFAULT_STRINGS = {\n 'fab.label': 'Send feedback',\n 'form.title': 'Send feedback',\n 'form.description.label': 'What happened?',\n 'form.description.placeholder': 'Describe the issue or idea in one or two sentences.',\n 'form.type.label': 'Type',\n 'form.severity.label': 'Severity',\n 'form.submit': 'Send',\n 'form.cancel': 'Cancel',\n 'form.submitting': 'Sending…',\n 'form.success': 'Thanks — your feedback was sent.',\n 'form.error': 'Could not send. Please try again.',\n 'type.bug': 'Bug',\n 'type.feature': 'Feature request',\n 'type.question': 'Question',\n 'type.praise': 'Praise',\n 'type.typo': 'Typo',\n 'severity.blocker': 'Blocker',\n 'severity.high': 'High',\n 'severity.medium': 'Medium',\n 'severity.low': 'Low',\n}\n\nexport type StringKey = keyof typeof DEFAULT_STRINGS\n\nconst FRENCH_STRINGS: Record<StringKey, string> = {\n 'fab.label': 'Envoyer un commentaire',\n 'form.title': 'Envoyer un commentaire',\n 'form.description.label': 'Qu’est-il arrivé ?',\n 'form.description.placeholder': 'Décrivez le problème ou l’idée en une ou deux phrases.',\n 'form.type.label': 'Type',\n 'form.severity.label': 'Sévérité',\n 'form.submit': 'Envoyer',\n 'form.cancel': 'Annuler',\n 'form.submitting': 'Envoi…',\n 'form.success': 'Merci — votre commentaire a été envoyé.',\n 'form.error': 'Échec d’envoi. Veuillez réessayer.',\n 'type.bug': 'Bogue',\n 'type.feature': 'Suggestion',\n 'type.question': 'Question',\n 'type.praise': 'Compliment',\n 'type.typo': 'Coquille',\n 'severity.blocker': 'Bloquant',\n 'severity.high': 'Élevée',\n 'severity.medium': 'Moyenne',\n 'severity.low': 'Faible',\n}\n\nconst LOCALE_PACKS: Record<string, Record<StringKey, string>> = {\n fr: FRENCH_STRINGS,\n}\n\ninterface ResolveOptions {\n locale?: string\n}\n\nfunction packFor(locale: string | undefined): Record<StringKey, string> | null {\n if (!locale) return null\n // Match the language subtag only (fr-CA, fr-FR → fr).\n const tag = locale.toLowerCase().split(/[-_]/)[0]!\n return LOCALE_PACKS[tag] ?? null\n}\n\nexport function resolveStrings(\n overrides: Record<string, string>,\n options: ResolveOptions = {},\n): Record<StringKey, string> {\n const localePack = packFor(options.locale) ?? {}\n return {\n ...DEFAULT_STRINGS,\n ...localePack,\n ...overrides,\n } as Record<StringKey, string>\n}\n","import { h, render } from 'preact'\nimport { useCallback, useState } from 'preact/hooks'\n\nimport { Fab } from './Fab'\nimport { Form, type FormValues } from './Form'\nimport { Modal } from './Modal'\nimport { WIDGET_STYLES } from './styles'\nimport type { StringKey } from './i18n'\n\nexport interface MountOptions {\n host: HTMLElement\n strings: Record<StringKey, string>\n showFAB: boolean\n onSubmit: (values: FormValues) => Promise<void>\n}\n\nexport interface MountHandle {\n open(): void\n close(): void\n dispose(): void\n}\n\ntype State = { open: boolean; status: 'idle' | 'submitting' | 'error' | 'success'; error?: string }\n\nexport function mountWidget(options: MountOptions): MountHandle {\n const shadow = options.host.attachShadow({ mode: 'open' })\n const style = document.createElement('style')\n style.textContent = WIDGET_STYLES\n shadow.appendChild(style)\n const mountPoint = document.createElement('div')\n shadow.appendChild(mountPoint)\n\n let currentState: State = { open: false, status: 'idle' }\n\n function rerender(state: State) {\n currentState = state\n render(h(Root, { state }), mountPoint)\n }\n\n function Root({ state }: { state: State }) {\n const handleSubmit = useCallback(async (values: FormValues) => {\n rerender({ open: true, status: 'submitting' })\n try {\n await options.onSubmit(values)\n rerender({ open: true, status: 'success' })\n setTimeout(() => rerender({ open: false, status: 'idle' }), 1200)\n } catch (err) {\n rerender({ open: true, status: 'error', error: err instanceof Error ? err.message : String(err) })\n }\n }, [])\n\n return (\n <>\n {options.showFAB && (\n <Fab\n label={options.strings['fab.label']}\n onClick={() => rerender({ ...currentState, open: true })}\n />\n )}\n {state.open && (\n <Modal onDismiss={() => rerender({ open: false, status: 'idle' })}>\n <Form\n strings={options.strings}\n onSubmit={handleSubmit}\n onCancel={() => rerender({ open: false, status: 'idle' })}\n status={state.status}\n {...(state.error !== undefined && { errorMessage: state.error })}\n />\n </Modal>\n )}\n </>\n )\n }\n\n rerender(currentState)\n\n return {\n open() { rerender({ ...currentState, open: true }) },\n close() { rerender({ ...currentState, open: false, status: 'idle' }) },\n dispose() {\n render(null, mountPoint)\n options.host.innerHTML = ''\n },\n }\n}\n","import { h } from 'preact'\n\ninterface FabProps {\n label: string\n onClick: () => void\n}\n\nexport function Fab({ label, onClick }: FabProps) {\n return (\n <button type=\"button\" class=\"fab\" aria-label={label} onClick={onClick}>\n 💬\n </button>\n )\n}\n","import { h } from 'preact'\nimport { useState } from 'preact/hooks'\n\nimport type { FeedbackSeverity, FeedbackType } from '../types'\nimport type { StringKey } from './i18n'\n\nexport type FormStatus = 'idle' | 'submitting' | 'error' | 'success'\n\nexport interface FormValues {\n description: string\n feedback_type: FeedbackType\n severity: FeedbackSeverity\n}\n\ninterface FormProps {\n strings: Record<StringKey, string>\n onSubmit: (values: FormValues) => void\n onCancel: () => void\n status: FormStatus\n errorMessage?: string\n}\n\nconst TYPES: FeedbackType[] = ['bug', 'feature', 'question', 'praise', 'typo']\nconst SEVERITIES: FeedbackSeverity[] = ['blocker', 'high', 'medium', 'low']\n\nexport function Form({ strings, onSubmit, onCancel, status, errorMessage }: FormProps) {\n const [description, setDescription] = useState('')\n const [feedbackType, setFeedbackType] = useState<FeedbackType>('bug')\n const [severity, setSeverity] = useState<FeedbackSeverity>('medium')\n const [localError, setLocalError] = useState('')\n\n const submitting = status === 'submitting'\n const submitLabel = submitting ? strings['form.submitting'] : strings['form.submit']\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n if (!description.trim()) {\n setLocalError(strings['form.description.placeholder'])\n return\n }\n setLocalError('')\n onSubmit({ description: description.trim(), feedback_type: feedbackType, severity })\n }\n\n return (\n <form onSubmit={handleSubmit}>\n <h2>{strings['form.title']}</h2>\n\n <div class=\"field\">\n <label for=\"mfb-desc\">{strings['form.description.label']}</label>\n <textarea\n id=\"mfb-desc\"\n value={description}\n placeholder={strings['form.description.placeholder']}\n onInput={(e) => setDescription((e.target as HTMLTextAreaElement).value)}\n />\n </div>\n\n <div class=\"row\">\n <div class=\"field\">\n <label for=\"mfb-type\">{strings['form.type.label']}</label>\n <select\n id=\"mfb-type\"\n value={feedbackType}\n onChange={(e) => setFeedbackType((e.target as HTMLSelectElement).value as FeedbackType)}\n >\n {TYPES.map((t) => <option value={t}>{strings[`type.${t}` as StringKey]}</option>)}\n </select>\n </div>\n <div class=\"field\">\n <label for=\"mfb-sev\">{strings['form.severity.label']}</label>\n <select\n id=\"mfb-sev\"\n value={severity}\n onChange={(e) => setSeverity((e.target as HTMLSelectElement).value as FeedbackSeverity)}\n >\n {SEVERITIES.map((s) => <option value={s}>{strings[`severity.${s}` as StringKey]}</option>)}\n </select>\n </div>\n </div>\n\n {localError && <div class=\"error\">{localError}</div>}\n {status === 'error' && errorMessage && <div class=\"error\">{errorMessage}</div>}\n {status === 'success' && <div class=\"success\">{strings['form.success']}</div>}\n\n <div class=\"actions\">\n <button type=\"button\" class=\"btn\" onClick={onCancel} disabled={submitting}>{strings['form.cancel']}</button>\n <button type=\"submit\" class=\"btn btn--primary\" disabled={submitting}>{submitLabel}</button>\n </div>\n </form>\n )\n}\n","import { h, type ComponentChildren } from 'preact'\n\ninterface ModalProps {\n onDismiss: () => void\n children: ComponentChildren\n}\n\nexport function Modal({ onDismiss, children }: ModalProps) {\n return (\n <div\n class=\"backdrop\"\n role=\"presentation\"\n onClick={(e) => { if (e.target === e.currentTarget) onDismiss() }}\n >\n <div class=\"modal\" role=\"dialog\" aria-modal=\"true\">{children}</div>\n </div>\n )\n}\n","export const WIDGET_STYLES = `\n:host {\n --mfb-accent: #3b82f6;\n --mfb-accent-contrast: #ffffff;\n --mfb-bg: #ffffff;\n --mfb-surface: #f9fafb;\n --mfb-text: #0a0a0a;\n --mfb-text-muted: #6b7280;\n --mfb-border: #e5e7eb;\n --mfb-radius: 8px;\n --mfb-font: system-ui, -apple-system, sans-serif;\n --mfb-z-index: 2147483640;\n\n all: initial;\n font-family: var(--mfb-font);\n color: var(--mfb-text);\n position: fixed;\n z-index: var(--mfb-z-index);\n}\n\n@media (prefers-color-scheme: dark) {\n :host {\n --mfb-bg: #111827;\n --mfb-surface: #1f2937;\n --mfb-text: #f9fafb;\n --mfb-text-muted: #9ca3af;\n --mfb-border: #374151;\n }\n}\n\n.fab {\n position: fixed;\n bottom: 24px;\n right: 24px;\n width: 52px;\n height: 52px;\n border-radius: 999px;\n background: var(--mfb-accent);\n color: var(--mfb-accent-contrast);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);\n font-size: 22px;\n display: grid;\n place-items: center;\n}\n\n.fab:focus-visible { outline: 2px solid var(--mfb-accent); outline-offset: 2px; }\n\n.backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n display: grid;\n place-items: center;\n}\n\n.modal {\n background: var(--mfb-bg);\n border-radius: calc(var(--mfb-radius) * 1.5);\n box-shadow: 0 20px 48px rgba(0, 0, 0, 0.25);\n width: min(420px, 92vw);\n padding: 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.modal h2 { margin: 0 0 4px; font-size: 18px; font-weight: 600; }\n\n.field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }\n\n.field label { color: var(--mfb-text-muted); }\n\n.field input, .field select, .field textarea {\n font-family: inherit;\n font-size: 14px;\n color: inherit;\n padding: 8px 10px;\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n background: var(--mfb-surface);\n}\n\n.field textarea { min-height: 88px; resize: vertical; }\n\n.row { display: flex; gap: 8px; }\n.row > * { flex: 1; }\n\n.actions { display: flex; gap: 8px; justify-content: flex-end; padding-top: 8px; }\n\n.btn {\n padding: 8px 14px;\n border-radius: var(--mfb-radius);\n border: 1px solid var(--mfb-border);\n background: var(--mfb-bg);\n color: var(--mfb-text);\n font: inherit;\n cursor: pointer;\n}\n\n.btn--primary {\n background: var(--mfb-accent);\n color: var(--mfb-accent-contrast);\n border-color: var(--mfb-accent);\n}\n\n.btn[disabled] { opacity: 0.6; cursor: not-allowed; }\n\n.error { color: #dc2626; font-size: 13px; }\n.success { color: #059669; font-size: 13px; }\n`\n","import { createApiClient } from './api/client'\nimport { installCapture } from './capture'\nimport { takeScreenshot } from './screenshot'\nimport { resolveStrings } from './widget/i18n'\nimport { mountWidget } from './widget/mount'\nimport type { FeedbackApi, FeedbackConfig, ReportPayload, ReportTransformer, UserIdentity } from './types'\n\nexport interface InternalConfig extends FeedbackConfig {\n fetchImpl?: typeof fetch\n}\n\ninterface WindowWithGlobal extends Window {\n mhosaicFeedback?: FeedbackApi\n}\n\nexport function createFeedback(config: InternalConfig): FeedbackApi & { _registerTransformer(fn: ReportTransformer): void } {\n const env = config.env ?? 'prod'\n const locale =\n config.locale ?? (typeof navigator !== 'undefined' ? navigator.language : undefined)\n const strings = resolveStrings(\n config.translations ?? {},\n locale !== undefined ? { locale } : {},\n )\n const capture = installCapture({\n ...(config.sanitizeUrl !== undefined && { sanitizeUrl: config.sanitizeUrl }),\n })\n const api = createApiClient({\n apiKey: config.apiKey,\n endpoint: config.endpoint,\n ...(config.fetchImpl !== undefined && { fetch: config.fetchImpl }),\n ...(config.beforeSend !== undefined && { beforeSend: config.beforeSend }),\n })\n\n let user: UserIdentity | undefined = config.user\n let metadata: Record<string, unknown> = config.metadata ?? {}\n const transformers: ReportTransformer[] = []\n\n const host = document.createElement('div')\n host.className = 'mhosaic-feedback'\n if (config.attachTo) {\n const attach = typeof config.attachTo === 'string' ? document.querySelector(config.attachTo) : config.attachTo\n attach?.appendChild(host)\n } else {\n document.body.appendChild(host)\n }\n\n async function buildAndSubmit(values: { description: string; feedback_type?: string; severity?: string }) {\n const screenshot = await takeScreenshot(document.body, { mask: ['.mhosaic-feedback', '[data-mfb-mask]'] })\n const payload: ReportPayload = {\n description: values.description,\n feedback_type: (values.feedback_type ?? 'bug') as ReportPayload['feedback_type'],\n severity: (values.severity ?? 'medium') as ReportPayload['severity'],\n env,\n page_url: window.location.href,\n user_agent: navigator.userAgent,\n capture_method: screenshot ? 'html2canvas' : 'none',\n technical_context: capture.snapshot(),\n }\n if (screenshot) payload.screenshot = screenshot\n let finalPayload: ReportPayload = payload\n for (const t of transformers) finalPayload = await t(finalPayload)\n try {\n const result = await api.submitReport(finalPayload)\n config.onSubmitSuccess?.(result)\n capture.clear()\n return result\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n config.onError?.(error)\n throw error\n }\n }\n\n const handle = mountWidget({\n host,\n strings,\n showFAB: config.showFAB ?? true,\n onSubmit: async (values) => { await buildAndSubmit(values) },\n })\n\n const instance: FeedbackApi & { _registerTransformer(fn: ReportTransformer): void } = {\n show() { handle.open() },\n hide() { handle.close() },\n open(opts) { handle.open(); void opts },\n async submit(partial) {\n return buildAndSubmit({\n description: partial.description,\n ...(partial.feedback_type !== undefined && { feedback_type: partial.feedback_type }),\n ...(partial.severity !== undefined && { severity: partial.severity }),\n })\n },\n identify(u) { user = u; void user },\n setMetadata(kv) { metadata = { ...metadata, ...kv }; void metadata },\n shutdown() {\n handle.dispose()\n capture.dispose()\n host.remove()\n // Only release the global if it still points at *us* — otherwise a\n // newer instance has taken ownership and we mustn't blow it away.\n const w = window as unknown as WindowWithGlobal\n if (w.mhosaicFeedback === instance) {\n delete w.mhosaicFeedback\n }\n },\n _registerTransformer(fn: ReportTransformer) { transformers.push(fn) },\n }\n\n // Expose the instance globally for ad-hoc callers (DevTools, docs pages,\n // help-widget integrations). The most-recently-created instance wins.\n ;(window as unknown as WindowWithGlobal).mhosaicFeedback = instance\n\n return instance\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsxs"]}