@mhosaic/feedback 0.17.0 → 0.18.1
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.
- package/dist/{chunk-TG4YNEXE.mjs → chunk-5FVEQYA5.mjs} +12 -6
- package/dist/chunk-5FVEQYA5.mjs.map +1 -0
- package/dist/{chunk-RP46APZ6.mjs → chunk-IP4Y5EZE.mjs} +9 -2
- package/dist/chunk-IP4Y5EZE.mjs.map +1 -0
- package/dist/{chunk-QVCHZCDS.mjs → chunk-QJ562NTG.mjs} +3 -1
- package/dist/chunk-QJ562NTG.mjs.map +1 -0
- package/dist/embed.min.js +2 -2
- package/dist/embed.min.js.map +1 -1
- package/dist/error-tracking.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/loader/react.d.ts +6 -5
- package/dist/loader/react.mjs +3 -9
- package/dist/loader/react.mjs.map +1 -1
- package/dist/loader.d.ts +13 -2
- package/dist/loader.min.js +1 -1
- package/dist/loader.min.js.map +1 -1
- package/dist/loader.mjs +1 -1
- package/dist/react.mjs +4 -4
- package/dist/widget.min.js +6 -4
- package/dist/widget.min.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-QVCHZCDS.mjs.map +0 -1
- package/dist/chunk-RP46APZ6.mjs.map +0 -1
- package/dist/chunk-TG4YNEXE.mjs.map +0 -1
|
@@ -174,7 +174,14 @@ async function loadAndAttach(config, deferred) {
|
|
|
174
174
|
...config,
|
|
175
175
|
// Forward the project's per-end-user gating flag from the manifest unless
|
|
176
176
|
// the host set it explicitly. The widget then runs the visibility check.
|
|
177
|
-
requiresVisibilityCheck: config.requiresVisibilityCheck ?? manifest.config?.requires_visibility_check ?? false
|
|
177
|
+
requiresVisibilityCheck: config.requiresVisibilityCheck ?? manifest.config?.requires_visibility_check ?? false,
|
|
178
|
+
// Error capture is armed INSIDE the bundle (the only auto-updating part
|
|
179
|
+
// of a loader install), so already-deployed hosts pick it up without a
|
|
180
|
+
// redeploy. Precedence: explicit host override > per-project manifest
|
|
181
|
+
// flag > on. The loader provider forwards its `errorTracking` prop here
|
|
182
|
+
// rather than wrapping host-side, so there's exactly one arm point (the
|
|
183
|
+
// real instance) — no deferred/real double-registration.
|
|
184
|
+
errorTracking: config.errorTracking ?? manifest.config?.error_tracking ?? true
|
|
178
185
|
});
|
|
179
186
|
deferred._attach(real);
|
|
180
187
|
}
|
|
@@ -182,4 +189,4 @@ async function loadAndAttach(config, deferred) {
|
|
|
182
189
|
export {
|
|
183
190
|
createFeedback
|
|
184
191
|
};
|
|
185
|
-
//# sourceMappingURL=chunk-
|
|
192
|
+
//# sourceMappingURL=chunk-IP4Y5EZE.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/loader/bundleLoader.ts","../src/loader/manifest.ts","../src/loader/deferredApi.ts","../src/loader/index.ts"],"sourcesContent":["/**\n * Inject the widget bundle as an SRI-protected <script> and wait for its\n * window global to appear.\n *\n * Why a <script> tag and not `import()`:\n * `import()` can fetch cross-origin ESM but doesn't honor Subresource\n * Integrity on the dynamic-import call itself. A <script> tag with\n * `integrity=…` is the only path where the browser actually refuses\n * to execute a bundle whose bytes don't match the manifest's hash.\n *\n * The bundle is built with `tsup --format iife --globalName MhosaicFeedback`,\n * so once it parses it sets `window.MhosaicFeedback = { createFeedback }`\n * (per `src/widget.ts`'s exports). We wait for that to appear.\n *\n * Idempotency: if multiple FeedbackProviders mount on the same page (e.g.\n * during a React fast-refresh cycle), we reuse an already-injected bundle\n * instead of fetching a second copy.\n */\n\nimport type { FeedbackApi, FeedbackConfig } from '../types'\nimport type { ErrorTrackingOptions } from '../modules/error-tracking'\n\n/** What the loader may pass to the bundle's `createFeedback`: the public\n * config plus the bundle-only `errorTracking` knob the loader forwards\n * from the manifest. */\nexport type BundleConfig = FeedbackConfig & {\n errorTracking?: boolean | ErrorTrackingOptions\n}\n\ndeclare global {\n interface Window {\n MhosaicFeedback?: {\n createFeedback(config: BundleConfig): FeedbackApi\n }\n }\n}\n\nconst SCRIPT_DATA_ATTR = 'data-mhosaic-feedback-bundle'\n\nexport interface BundleLoadOptions {\n bundleUrl: string\n sriHash: string\n /** Default 30 s. Long enough for slow networks; short enough to surface\n * CDN outages quickly. */\n timeoutMs?: number\n}\n\nexport interface BundleHandle {\n createFeedback(config: BundleConfig): FeedbackApi\n}\n\nexport async function injectBundle(\n opts: BundleLoadOptions,\n): Promise<BundleHandle> {\n // Reuse a bundle already loaded this page.\n if (window.MhosaicFeedback?.createFeedback) {\n return window.MhosaicFeedback\n }\n\n const existing = document.querySelector<HTMLScriptElement>(\n `script[${SCRIPT_DATA_ATTR}]`,\n )\n if (existing) {\n // Another loader instance started the fetch; wait for the global.\n return waitForGlobal(opts.timeoutMs ?? 30_000)\n }\n\n return new Promise<BundleHandle>((resolve, reject) => {\n const script = document.createElement('script')\n script.src = opts.bundleUrl\n script.integrity = opts.sriHash\n script.crossOrigin = 'anonymous'\n script.async = true\n script.setAttribute(SCRIPT_DATA_ATTR, '1')\n script.onload = () => {\n if (window.MhosaicFeedback?.createFeedback) {\n resolve(window.MhosaicFeedback)\n } else {\n reject(\n new Error(\n 'mhosaic-feedback: bundle loaded but window.MhosaicFeedback.createFeedback is missing — bundle/loader version mismatch?',\n ),\n )\n }\n }\n script.onerror = () => {\n reject(\n new Error(\n `mhosaic-feedback: failed to load bundle from ${opts.bundleUrl} ` +\n '(network, CSP, or SRI mismatch)',\n ),\n )\n }\n document.head.appendChild(script)\n\n const timeoutMs = opts.timeoutMs ?? 30_000\n setTimeout(() => {\n reject(\n new Error(`mhosaic-feedback: bundle load timeout after ${timeoutMs}ms`),\n )\n }, timeoutMs)\n })\n}\n\nfunction waitForGlobal(timeoutMs: number): Promise<BundleHandle> {\n return new Promise((resolve, reject) => {\n const start = Date.now()\n const tick = () => {\n if (window.MhosaicFeedback?.createFeedback) {\n resolve(window.MhosaicFeedback)\n return\n }\n if (Date.now() - start > timeoutMs) {\n reject(\n new Error(\n 'mhosaic-feedback: timed out waiting for bundle global (another loader instance started the fetch but never finished)',\n ),\n )\n return\n }\n setTimeout(tick, 50)\n }\n tick()\n })\n}\n","/**\n * Fetch the widget-manifest from the Mhosaic backend.\n *\n * The loader calls this on every page load. The backend reads `Project.\n * pinned_version` (or current stable) + `Project.widget_enabled` and\n * returns the bundle URL + SRI hash for the version this tenant should\n * receive — or `{enabled: false}` if the widget is killed for the tenant.\n *\n * Network failures are surfaced to the caller. The loader degrades to\n * \"widget not present\" rather than crashing the host page.\n */\n\nexport interface Manifest {\n /** False when the widget is disabled for this project (kill switch) or\n * no stable release exists. Loader bails silently. */\n enabled: boolean\n /** Semver of the bundle being served. Present when enabled=true. */\n version?: string\n /** Fully-qualified URL to the version-pinned bundle (jsDelivr). */\n bundle_url?: string\n /** Subresource integrity hash for the bundle. The loader injects the\n * script tag with `integrity=…` so the browser refuses to run a\n * bundle whose bytes don't match. */\n sri_hash?: string\n /** Static config the manifest endpoint passes through to the widget. */\n config?: {\n endpoint: string\n project_slug: string\n share_reports_with_widget: boolean\n /** Phase 4: project gates the widget per end-user (default false). */\n requires_visibility_check?: boolean\n /** Per-project switch for the bundle's default error capture. When the\n * backend omits it, the bundle falls back to its own default (on). */\n error_tracking?: boolean\n }\n /** Human-readable detail when `enabled` is false. */\n detail?: string\n}\n\nexport async function fetchManifest(\n endpoint: string,\n apiKey: string,\n signal?: AbortSignal,\n): Promise<Manifest> {\n const base = endpoint.replace(/\\/$/, '')\n const url = `${base}/api/feedback/v1/widget-manifest/?pk=${encodeURIComponent(apiKey)}`\n // credentials: 'omit' — we authenticate via the public pk_proj_ query\n // param; sending cookies would just trigger CORS preflights for no\n // reason and is unnecessary since the manifest endpoint doesn't read\n // any session.\n const init: RequestInit = { credentials: 'omit' }\n if (signal) init.signal = signal\n const res = await fetch(url, init)\n if (!res.ok) {\n throw new Error(\n `mhosaic-feedback: manifest fetch failed (HTTP ${res.status})`,\n )\n }\n const body = (await res.json()) as Manifest\n return body\n}\n","/**\n * A FeedbackApi-shaped object that queues method calls until the real\n * widget bundle finishes loading, then drains the queue against the real\n * implementation.\n *\n * Why we need this: hosts that already have code like\n * const fb = createFeedback({...})\n * fb.identify({id, email, name})\n * useEffect(() => fb.open(...), [])\n * shouldn't have to refactor for async. The loader's createFeedback\n * returns sync — a deferred handle that records intent, then replays it\n * once the real bundle arrives. Idiomatic queue-then-flush pattern.\n *\n * If the bundle never loads (network failure, SRI mismatch, kill switch),\n * `_fail()` is called instead. Void methods (identify/setMetadata/open/...)\n * silently drop in that case — the widget just doesn't appear. The\n * `submit` Promise rejects so callers can surface real errors.\n */\n\nimport type {\n FeedbackApi,\n ReportPayload,\n SubmittedReport,\n UserIdentity,\n} from '../types'\n\ntype VoidMethod = 'show' | 'hide' | 'shutdown'\ntype ArgMethod = 'open' | 'identify' | 'setMetadata'\n\ntype Queued =\n | { kind: 'void'; method: VoidMethod }\n | { kind: 'arg'; method: 'open'; arg: Parameters<FeedbackApi['open']>[0] }\n | { kind: 'arg'; method: 'identify'; arg: UserIdentity }\n | { kind: 'arg'; method: 'setMetadata'; arg: Record<string, unknown> }\n | {\n kind: 'submit'\n payload: Partial<ReportPayload> & { description: string }\n resolve: (r: SubmittedReport) => void\n reject: (e: unknown) => void\n }\n\nexport interface DeferredHandle extends FeedbackApi {\n /** Called by the loader once the bundle is loaded and a real API exists. */\n _attach(real: FeedbackApi): void\n /** Called by the loader if the bundle fails to load. */\n _fail(err: Error): void\n}\n\nexport function createDeferredApi(): DeferredHandle {\n let real: FeedbackApi | null = null\n let failure: Error | null = null\n const queue: Queued[] = []\n\n function flush(item: Queued): void {\n if (real) {\n if (item.kind === 'void') {\n ;(real[item.method] as () => void)()\n } else if (item.kind === 'arg') {\n ;(real[item.method] as (a: unknown) => void)(item.arg)\n } else {\n // submit\n Promise.resolve(real.submit(item.payload)).then(\n item.resolve,\n item.reject,\n )\n }\n return\n }\n if (failure) {\n if (item.kind === 'submit') item.reject(failure)\n // Void / arg methods silently dropped — the widget never appeared.\n return\n }\n queue.push(item)\n }\n\n return {\n show() {\n flush({ kind: 'void', method: 'show' })\n },\n hide() {\n flush({ kind: 'void', method: 'hide' })\n },\n shutdown() {\n flush({ kind: 'void', method: 'shutdown' })\n },\n open(arg) {\n flush({ kind: 'arg', method: 'open', arg })\n },\n identify(arg) {\n flush({ kind: 'arg', method: 'identify', arg })\n },\n setMetadata(arg) {\n flush({ kind: 'arg', method: 'setMetadata', arg })\n },\n submit(payload) {\n return new Promise<SubmittedReport>((resolve, reject) => {\n flush({ kind: 'submit', payload, resolve, reject })\n })\n },\n _attach(impl) {\n real = impl\n while (queue.length > 0) flush(queue.shift()!)\n },\n _fail(err) {\n failure = err\n // Drain any pending submits with the failure; drop void/arg.\n for (const item of queue) {\n if (item.kind === 'submit') item.reject(err)\n }\n queue.length = 0\n },\n }\n}\n","/**\n * `@mhosaic/feedback/loader` — public entry for the loader architecture.\n *\n * Same shape as the direct-import path (`@mhosaic/feedback`), but the\n * widget bundle is fetched at runtime from a CDN URL the Mhosaic backend\n * dictates via the manifest endpoint. Letting hosts switch from the\n * direct-import path to the loader path gives them auto-updates without\n * any further code changes — Mhosaic ships a new Release row, every host\n * picks up the new bundle on next page load.\n *\n * Public surface MUST mirror the direct-import path exactly:\n * - `createFeedback(config)` returns a `FeedbackApi`-shaped handle.\n * - Method calls before the bundle finishes loading queue up and replay.\n * - `submit()` returns a Promise that resolves after the bundle is up\n * and the real submit completes.\n *\n * If the manifest endpoint reports the widget is disabled for this\n * project (`enabled: false` — kill switch or no stable release configured),\n * the deferred handle silently no-ops void calls and rejects `submit()`\n * calls with a clear error. The host page never crashes.\n */\n\nimport type { FeedbackApi, FeedbackConfig } from '../types'\nimport type { ErrorTrackingOptions } from '../modules/error-tracking'\nimport { injectBundle } from './bundleLoader'\nimport { fetchManifest } from './manifest'\nimport { createDeferredApi, type DeferredHandle } from './deferredApi'\n\nexport type { FeedbackApi, FeedbackConfig } from '../types'\nexport type { Manifest } from './manifest'\n\n/** Loader config = the public widget config plus the loader-only knobs the\n * host can set to override what the manifest dictates. */\nexport type LoaderConfig = FeedbackConfig & {\n /** Override the bundle's default error capture. Omit (or pass `undefined`)\n * to let the project's manifest flag decide (which itself defaults on). */\n errorTracking?: boolean | ErrorTrackingOptions | undefined\n}\n\nexport function createFeedback(config: LoaderConfig): FeedbackApi {\n const deferred = createDeferredApi()\n loadAndAttach(config, deferred).catch((err: Error) => {\n // Surface to console — host devtools is the canonical channel for\n // widget bootstrap errors. Production telemetry is the bundle's job\n // (it can't run if it never loaded), so console.warn is the floor.\n // eslint-disable-next-line no-console\n console.warn('[mhosaic-feedback] widget did not load:', err.message)\n deferred._fail(err)\n })\n return deferred\n}\n\nasync function loadAndAttach(\n config: LoaderConfig,\n deferred: DeferredHandle,\n): Promise<void> {\n const manifest = await fetchManifest(config.endpoint, config.apiKey)\n if (!manifest.enabled || !manifest.bundle_url || !manifest.sri_hash) {\n // Disabled by Mhosaic (kill switch) or no stable release. Surface a\n // clear failure so submit() callers see an error, but no host crash.\n deferred._fail(\n new Error(\n `mhosaic-feedback: widget disabled for this project${\n manifest.detail ? ` — ${manifest.detail}` : ''\n }`,\n ),\n )\n return\n }\n const bundle = await injectBundle({\n bundleUrl: manifest.bundle_url,\n sriHash: manifest.sri_hash,\n })\n const real: FeedbackApi = bundle.createFeedback({\n ...config,\n // Forward the project's per-end-user gating flag from the manifest unless\n // the host set it explicitly. The widget then runs the visibility check.\n requiresVisibilityCheck:\n config.requiresVisibilityCheck ??\n manifest.config?.requires_visibility_check ??\n false,\n // Error capture is armed INSIDE the bundle (the only auto-updating part\n // of a loader install), so already-deployed hosts pick it up without a\n // redeploy. Precedence: explicit host override > per-project manifest\n // flag > on. The loader provider forwards its `errorTracking` prop here\n // rather than wrapping host-side, so there's exactly one arm point (the\n // real instance) — no deferred/real double-registration.\n errorTracking:\n config.errorTracking ?? manifest.config?.error_tracking ?? true,\n })\n deferred._attach(real)\n}\n"],"mappings":"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","names":[]}
|
|
@@ -46,6 +46,8 @@ function withErrorTracking(fb, options = {}) {
|
|
|
46
46
|
if (!opts.enabled) return fb;
|
|
47
47
|
if (typeof window === "undefined") return fb;
|
|
48
48
|
const internal = fb;
|
|
49
|
+
if (internal._errorTrackingArmed) return fb;
|
|
50
|
+
internal._errorTrackingArmed = true;
|
|
49
51
|
const inFlight = /* @__PURE__ */ new Set();
|
|
50
52
|
const lastSent = /* @__PURE__ */ new Map();
|
|
51
53
|
const recentSendTimes = [];
|
|
@@ -140,4 +142,4 @@ function withErrorTracking(fb, options = {}) {
|
|
|
140
142
|
export {
|
|
141
143
|
withErrorTracking
|
|
142
144
|
};
|
|
143
|
-
//# sourceMappingURL=chunk-
|
|
145
|
+
//# sourceMappingURL=chunk-QJ562NTG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/modules/error-tracking.ts"],"sourcesContent":["/**\n * Always-on debugger module. Hooks `window.error` and `unhandledrejection`,\n * then ships each fresh runtime error as a synthetic FeedbackReport via\n * the existing widget submit pipeline.\n *\n * Same opt-in pattern as `withReplay` / `withWebVitals` — host apps that\n * want curated-feedback-only simply don't import it.\n *\n * Design choices (see PR description):\n * - Per-fingerprint cooldown (default 5 min) absorbs render loops without\n * flooding the operator dashboard or burning the per-key write throttle.\n * - Server-side fingerprinting groups across sessions; the client-side\n * fingerprint exists only to dedup within a single page lifetime, so\n * it doesn't need to match the server's hash.\n * - Recursion guard: an error thrown *inside* the submit pipeline must\n * not re-enter the handler.\n * - Description is the error message truncated at 200 chars — the full\n * stack lives in technical_context.errors[].\n * - No screenshot is taken (buildAndSubmit honors `synthetic: true`):\n * html2canvas is slow + the DOM is unreliable mid-error.\n */\n\nimport type { FeedbackApi } from '../types'\n\nexport interface ErrorTrackingOptions {\n /** Opt-out kill switch without removing the import. Default `true`. */\n enabled?: boolean\n /**\n * Drop repeats of the same fingerprint within this window.\n * Default 300_000 ms (5 minutes). Set to 0 to disable dedup\n * (every fired error becomes a report — useful only for tests).\n */\n perFingerprintCooldownMs?: number\n /**\n * Probabilistic head sampling: 1.0 captures everything, 0.5 drops half.\n * Default 1.0. Sampled-out errors don't count toward the cooldown — if\n * you sample at 0.1, you'll still see ~10% of the volume per fingerprint.\n */\n sampleRate?: number\n /** Max characters in the auto-generated description. Default 200. */\n maxDescriptionLen?: number\n /**\n * Global ceiling on synthetic submissions per minute, regardless of\n * fingerprint. Defends against a hostile / buggy page that throws\n * errors with attacker-varying `message` strings (counter, nonce) —\n * each unique message creates a fresh fingerprint, bypassing the\n * per-fingerprint cooldown, and would otherwise burn the project's\n * backend write quota.\n * Default 30. Set to 0 to disable the global cap (not recommended).\n */\n globalRatePerMinute?: number\n /**\n * Max number of distinct fingerprints emitted per page lifetime. Once\n * exceeded, NEW fingerprints are dropped (the cooldown still applies\n * to already-seen ones, so legitimate repeating errors keep cycling).\n * Defense against a page that synthesizes an unbounded number of\n * unique error shapes.\n * Default 200. Set to 0 to disable.\n */\n maxDistinctFingerprints?: number\n}\n\ninterface InternalApi extends FeedbackApi {\n _registerTransformer?: (fn: unknown) => void\n /** Set once withErrorTracking has armed this instance (idempotency guard). */\n _errorTrackingArmed?: boolean\n}\n\ninterface NormalizedError {\n name: string\n message: string\n stack?: string\n}\n\nconst DEFAULTS = {\n enabled: true,\n perFingerprintCooldownMs: 5 * 60 * 1000,\n sampleRate: 1,\n maxDescriptionLen: 200,\n globalRatePerMinute: 30,\n maxDistinctFingerprints: 200,\n} as const satisfies Required<ErrorTrackingOptions>\n\n/**\n * Pull a normalized {name, message, stack} from whatever the runtime\n * handed us. Browsers throw genuine Error subclasses for uncaught\n * exceptions but `unhandledrejection.reason` is sometimes a string,\n * a plain object, or undefined.\n */\nfunction normalize(thrown: unknown): NormalizedError {\n if (thrown instanceof Error) {\n return {\n name: thrown.name || 'Error',\n message: String(thrown.message ?? ''),\n ...(thrown.stack && { stack: String(thrown.stack) }),\n }\n }\n if (typeof thrown === 'string') return { name: 'Error', message: thrown }\n if (thrown && typeof thrown === 'object') {\n const o = thrown as Record<string, unknown>\n return {\n name: (typeof o.name === 'string' && o.name) || 'Error',\n message:\n (typeof o.message === 'string' && o.message) ||\n (() => {\n try { return JSON.stringify(thrown) } catch { return String(thrown) }\n })(),\n ...(typeof o.stack === 'string' && { stack: o.stack }),\n }\n }\n return { name: 'Error', message: String(thrown) }\n}\n\n/**\n * Stable per-session signature. Server still computes its own fingerprint\n * across sessions — this only needs to dedup within one page lifetime.\n * Stack frames are the strongest discriminator; pathname keeps two distinct\n * routes from collapsing onto the same key.\n *\n * SECURITY: we include only a 30-char message prefix, not the full message.\n * A hostile or buggy page that throws errors with counter-suffixed messages\n * (e.g. `Error 1`, `Error 2`, …) would otherwise produce a fresh fingerprint\n * per throw and bypass the per-fingerprint cooldown. The stack frames are\n * the same across those counter variants, so collapsing the message into a\n * prefix preserves real-error distinction while killing the counter bypass.\n */\nfunction clientFingerprint(err: NormalizedError, pathname: string): string {\n const firstFrames = (err.stack ?? '').split('\\n').slice(0, 4).join('\\n')\n const messagePrefix = err.message.slice(0, 30)\n return `${err.name}:${messagePrefix}|${pathname}|${firstFrames}`\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s\n return s.slice(0, Math.max(0, max - 1)) + '…'\n}\n\nexport function withErrorTracking(\n fb: FeedbackApi,\n options: ErrorTrackingOptions = {},\n): FeedbackApi {\n const opts = { ...DEFAULTS, ...options }\n if (!opts.enabled) return fb\n if (typeof window === 'undefined') return fb\n\n const internal = fb as InternalApi\n\n // Idempotency guard. The same instance can now be armed from two places:\n // the host-side <FeedbackProvider> (opt-out default) AND the runtime\n // widget bundle (which self-arms on the loader path). A client who both\n // upgrades the provider and receives the self-arming bundle would\n // otherwise double-register the window listeners and file every error\n // twice. First arm wins; later calls are no-ops.\n if (internal._errorTrackingArmed) return fb\n internal._errorTrackingArmed = true\n\n // Recursion guard, scoped per-fingerprint: while we're posting a synthetic\n // report for fingerprint X, a re-entry for the SAME X (e.g. an error\n // raised by the submit pipeline itself) is dropped. Distinct errors that\n // fire concurrently still both go through.\n const inFlight = new Set<string>()\n\n // fingerprint -> last-sent epoch ms. Periodically pruned in shouldSend().\n const lastSent = new Map<string, number>()\n // Sliding-window of recent send timestamps for the global rate cap.\n // Trimmed in shouldSend(); never grows beyond globalRatePerMinute entries.\n const recentSendTimes: number[] = []\n\n function shouldSend(fp: string, now: number): boolean {\n // (1) Global rate ceiling — runs first because it doesn't depend on\n // fingerprint state. Defends against the \"counter-suffixed error\n // messages\" attack that would otherwise produce one unique\n // fingerprint per throw.\n if (opts.globalRatePerMinute > 0) {\n const windowStart = now - 60_000\n // Drop expired entries from the front of the sliding window.\n while (recentSendTimes.length > 0 && recentSendTimes[0]! < windowStart) {\n recentSendTimes.shift()\n }\n if (recentSendTimes.length >= opts.globalRatePerMinute) {\n return false\n }\n }\n // (2) Per-page cap on the number of distinct fingerprints. A hostile\n // page that synthesizes an unbounded number of unique error\n // shapes runs out of new slots after this many — already-seen\n // fingerprints keep cycling under the per-fp cooldown.\n if (\n opts.maxDistinctFingerprints > 0 &&\n !lastSent.has(fp) &&\n lastSent.size >= opts.maxDistinctFingerprints\n ) {\n return false\n }\n if (opts.perFingerprintCooldownMs <= 0) {\n recentSendTimes.push(now)\n return true\n }\n const prev = lastSent.get(fp)\n if (prev !== undefined && now - prev < opts.perFingerprintCooldownMs) {\n return false\n }\n // Cheap stale-entry sweep so the Map doesn't grow unboundedly on a\n // long-lived session with many distinct errors. First pass: drop\n // entries past `cooldown * 2`. If we're still above a hard cap of\n // 256 — i.e. an SPA that's been live for hours and keeps emitting\n // *fresh* fingerprints faster than they go stale — drop the oldest\n // entries until we're back to a comfortable ceiling. Map iteration\n // order is insertion order so the first N keys are the oldest.\n const HARD_CAP = 256\n const TARGET_AFTER_TRIM = 192\n if (lastSent.size > HARD_CAP) {\n const cutoff = now - opts.perFingerprintCooldownMs * 2\n for (const [k, v] of lastSent) {\n if (v < cutoff) lastSent.delete(k)\n }\n if (lastSent.size > HARD_CAP) {\n const toDrop = lastSent.size - TARGET_AFTER_TRIM\n let dropped = 0\n for (const k of lastSent.keys()) {\n if (dropped >= toDrop) break\n lastSent.delete(k)\n dropped++\n }\n }\n }\n recentSendTimes.push(now)\n return true\n }\n\n async function report(err: NormalizedError) {\n if (opts.sampleRate < 1 && Math.random() >= opts.sampleRate) return\n\n const fp = clientFingerprint(err, window.location.pathname)\n if (inFlight.has(fp)) return\n const now = Date.now()\n if (!shouldSend(fp, now)) return\n lastSent.set(fp, now)\n\n const description = truncate(\n err.message ? `${err.name}: ${err.message}` : err.name,\n opts.maxDescriptionLen,\n )\n\n inFlight.add(fp)\n try {\n await internal.submit({\n description,\n feedback_type: 'bug',\n severity: 'high',\n synthetic: true,\n } as Parameters<FeedbackApi['submit']>[0] & { synthetic: boolean })\n } catch {\n // Swallow submit errors — propagating them would just trigger another\n // unhandledrejection and feed the loop. The host's `onError` callback\n // (configured on createFeedback) still fires for visibility.\n } finally {\n inFlight.delete(fp)\n }\n }\n\n function onError(event: ErrorEvent) {\n const candidate: unknown = event.error ?? {\n name: 'Error',\n message: event.message,\n stack: `at ${event.filename}:${event.lineno}:${event.colno}`,\n }\n void report(normalize(candidate))\n }\n\n function onUnhandledRejection(event: PromiseRejectionEvent) {\n void report(normalize(event.reason))\n }\n\n window.addEventListener('error', onError)\n window.addEventListener('unhandledrejection', onUnhandledRejection)\n\n // Wrap shutdown so listeners come down with the widget. Without this, a\n // host that re-mounts the widget under React StrictMode would double the\n // listeners and emit each error twice.\n const originalShutdown = internal.shutdown.bind(internal)\n internal.shutdown = () => {\n window.removeEventListener('error', onError)\n window.removeEventListener('unhandledrejection', onUnhandledRejection)\n lastSent.clear()\n originalShutdown()\n }\n\n return fb\n}\n"],"mappings":"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","names":[]}
|
package/dist/embed.min.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var MhosaicFeedback=(()=>{var Ut=Object.defineProperty;var jt=(e,t,r)=>t in e?Ut(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var Ce=(e,t,r)=>jt(e,typeof t!="symbol"?t+"":t,r);var Ot=["description","feedback_type","severity","env","page_url","user_agent","capture_method"];function qt(e){let t;try{t=new URL(e)}catch(r){throw new Error(`[mhosaic-feedback] \`endpoint\` is not a valid URL: ${e}`)}if(t.protocol!=="https:"&&!(t.protocol==="http:"&&(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]")))throw new Error(`[mhosaic-feedback] \`endpoint\` must use https:// (got ${t.protocol}//${t.hostname}). http:// is only allowed for localhost in dev.`)}function Ne(e){var k,_;let t=((k=e.endpoint)!=null?k:"").replace(/\/+$/,"");if(!t)throw new Error('[mhosaic-feedback] `endpoint` is required (e.g. "https://feedback.example.com").');qt(t);let r=(_=e.fetch)!=null?_:globalThis.fetch;async function n(v){var L,T,F;let p=v;if(e.beforeSend&&(p=await e.beforeSend(v)),p===!1)throw new Error("Submission cancelled by beforeSend");let u=new FormData;for(let P of Ot)u.append(P,String(p[P]));u.append("technical_context",JSON.stringify(p.technical_context)),p.screenshot&&u.append("screenshot",p.screenshot,"screenshot.png"),p.synthetic&&u.append("synthetic","true"),(L=p.user)!=null&&L.id&&u.append("user",JSON.stringify(p.user)),p.widget_version&&u.append("widget_version",p.widget_version);let m={Authorization:`Bearer ${e.apiKey}`};p.synthetic&&(m["X-Mhosaic-Capture-Source"]="error-tracking");let x=(T=e.getSignedIdentity)==null?void 0:T.call(e);x&&x.userHash&&x.exp&&((F=p.user)!=null&&F.id)&&(m["X-Mhosaic-User"]=String(p.user.id),m["X-Mhosaic-User-Hmac"]=x.userHash,m["X-Mhosaic-User-Exp"]=String(x.exp),x.email&&(m["X-Mhosaic-User-Email"]=x.email));let R=await r(`${t}/api/feedback/v1/reports/`,{method:"POST",headers:m,body:u});if(!R.ok){let P=await R.text().catch(()=>"");throw new Error(`Feedback submit failed: ${R.status} ${P}`)}return R.json()}function a(v){var m;let p={Authorization:`Bearer ${e.apiKey}`,"X-Mhosaic-User":v},u=(m=e.getSignedIdentity)==null?void 0:m.call(e);return u&&u.userHash&&u.exp&&(p["X-Mhosaic-User-Hmac"]=u.userHash,p["X-Mhosaic-User-Exp"]=String(u.exp),u.email&&(p["X-Mhosaic-User-Email"]=u.email)),p}async function i(v){let p=await r(`${t}/api/feedback/v1/reports/widget/mine/`,{method:"GET",headers:a(v)});if(p.status===404)return[];if(!p.ok){let u=await p.text().catch(()=>"");throw new Error(`listMine failed: ${p.status} ${u}`)}return p.json()}async function s(v){let p=await r(`${t}/api/feedback/v1/reports/widget/changelog/`,{method:"GET",headers:a(v)});if(p.status===404)return[];if(!p.ok){let u=await p.text().catch(()=>"");throw new Error(`listChangelog failed: ${p.status} ${u}`)}return p.json()}async function l(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/${v}/`,{method:"GET",headers:a(p)});if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`getReport failed: ${u.status} ${m}`)}return u.json()}async function f(v,p,u,m){let x=await r(`${t}/api/feedback/v1/reports/widget/${v}/comments/`,{method:"POST",headers:{...a(p),"Content-Type":"application/json"},body:JSON.stringify({body:u,...m!==void 0&&{client_nonce:m}})});if(!x.ok){let R=await x.text().catch(()=>"");throw new Error(`addComment failed: ${x.status} ${R}`)}return x.json()}async function c(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/${v}/`,{method:"PATCH",headers:{...a(p),"Content-Type":"application/json"},body:JSON.stringify({status:"closed"})});if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`closeAsResolved failed: ${u.status} ${m}`)}return u.json()}function b(v){var m,x,R;if(!v)return"";let p=new URLSearchParams;(m=v.status)==null||m.forEach(L=>p.append("status",L)),(x=v.type)==null||x.forEach(L=>p.append("type",L)),(R=v.severity)==null||R.forEach(L=>p.append("severity",L)),v.q&&p.set("q",v.q),v.mine&&p.set("mine","1"),v.page&&v.page>1&&p.set("page",String(v.page));let u=p.toString();return u?`?${u}`:""}async function d(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/board/${b(p)}`,{method:"GET",headers:a(v)});if(u.status===404)return{count:0,next:null,previous:null,results:[]};if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`listBoard failed: ${u.status} ${m}`)}return u.json()}async function y(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/board/kpis/${b(p)}`,{method:"GET",headers:a(v)});if(u.status===404)return{total:0,by_status:{},resolution_rate:0,scope:"mine"};if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`fetchBoardKpis failed: ${u.status} ${m}`)}return u.json()}async function g(v){let
|
|
1
|
+
"use strict";var MhosaicFeedback=(()=>{var Ut=Object.defineProperty;var jt=(e,t,r)=>t in e?Ut(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var Ce=(e,t,r)=>jt(e,typeof t!="symbol"?t+"":t,r);var Ot=["description","feedback_type","severity","env","page_url","user_agent","capture_method"];function qt(e){let t;try{t=new URL(e)}catch(r){throw new Error(`[mhosaic-feedback] \`endpoint\` is not a valid URL: ${e}`)}if(t.protocol!=="https:"&&!(t.protocol==="http:"&&(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]")))throw new Error(`[mhosaic-feedback] \`endpoint\` must use https:// (got ${t.protocol}//${t.hostname}). http:// is only allowed for localhost in dev.`)}function Ne(e){var k,_;let t=((k=e.endpoint)!=null?k:"").replace(/\/+$/,"");if(!t)throw new Error('[mhosaic-feedback] `endpoint` is required (e.g. "https://feedback.example.com").');qt(t);let r=(_=e.fetch)!=null?_:globalThis.fetch;async function n(v){var L,T,F;let p=v;if(e.beforeSend&&(p=await e.beforeSend(v)),p===!1)throw new Error("Submission cancelled by beforeSend");let u=new FormData;for(let P of Ot)u.append(P,String(p[P]));u.append("technical_context",JSON.stringify(p.technical_context)),p.screenshot&&u.append("screenshot",p.screenshot,"screenshot.png"),p.synthetic&&u.append("synthetic","true"),(L=p.user)!=null&&L.id&&u.append("user",JSON.stringify(p.user)),p.widget_version&&u.append("widget_version",p.widget_version);let m={Authorization:`Bearer ${e.apiKey}`};p.synthetic&&(m["X-Mhosaic-Capture-Source"]="error-tracking");let x=(T=e.getSignedIdentity)==null?void 0:T.call(e);x&&x.userHash&&x.exp&&((F=p.user)!=null&&F.id)&&(m["X-Mhosaic-User"]=String(p.user.id),m["X-Mhosaic-User-Hmac"]=x.userHash,m["X-Mhosaic-User-Exp"]=String(x.exp),x.email&&(m["X-Mhosaic-User-Email"]=x.email));let R=await r(`${t}/api/feedback/v1/reports/`,{method:"POST",headers:m,body:u});if(!R.ok){let P=await R.text().catch(()=>"");throw new Error(`Feedback submit failed: ${R.status} ${P}`)}return R.json()}function a(v){var m;let p={Authorization:`Bearer ${e.apiKey}`,"X-Mhosaic-User":v},u=(m=e.getSignedIdentity)==null?void 0:m.call(e);return u&&u.userHash&&u.exp&&(p["X-Mhosaic-User-Hmac"]=u.userHash,p["X-Mhosaic-User-Exp"]=String(u.exp),u.email&&(p["X-Mhosaic-User-Email"]=u.email)),p}async function i(v){let p=await r(`${t}/api/feedback/v1/reports/widget/mine/`,{method:"GET",headers:a(v)});if(p.status===404)return[];if(!p.ok){let u=await p.text().catch(()=>"");throw new Error(`listMine failed: ${p.status} ${u}`)}return p.json()}async function s(v){let p=await r(`${t}/api/feedback/v1/reports/widget/changelog/`,{method:"GET",headers:a(v)});if(p.status===404)return[];if(!p.ok){let u=await p.text().catch(()=>"");throw new Error(`listChangelog failed: ${p.status} ${u}`)}return p.json()}async function l(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/${v}/`,{method:"GET",headers:a(p)});if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`getReport failed: ${u.status} ${m}`)}return u.json()}async function f(v,p,u,m){let x=await r(`${t}/api/feedback/v1/reports/widget/${v}/comments/`,{method:"POST",headers:{...a(p),"Content-Type":"application/json"},body:JSON.stringify({body:u,...m!==void 0&&{client_nonce:m}})});if(!x.ok){let R=await x.text().catch(()=>"");throw new Error(`addComment failed: ${x.status} ${R}`)}return x.json()}async function c(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/${v}/`,{method:"PATCH",headers:{...a(p),"Content-Type":"application/json"},body:JSON.stringify({status:"closed"})});if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`closeAsResolved failed: ${u.status} ${m}`)}return u.json()}function b(v){var m,x,R;if(!v)return"";let p=new URLSearchParams;(m=v.status)==null||m.forEach(L=>p.append("status",L)),(x=v.type)==null||x.forEach(L=>p.append("type",L)),(R=v.severity)==null||R.forEach(L=>p.append("severity",L)),v.q&&p.set("q",v.q),v.mine&&p.set("mine","1"),v.page&&v.page>1&&p.set("page",String(v.page));let u=p.toString();return u?`?${u}`:""}async function d(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/board/${b(p)}`,{method:"GET",headers:a(v)});if(u.status===404)return{count:0,next:null,previous:null,results:[]};if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`listBoard failed: ${u.status} ${m}`)}return u.json()}async function y(v,p){let u=await r(`${t}/api/feedback/v1/reports/widget/board/kpis/${b(p)}`,{method:"GET",headers:a(v)});if(u.status===404)return{total:0,by_status:{},resolution_rate:0,scope:"mine"};if(!u.ok){let m=await u.text().catch(()=>"");throw new Error(`fetchBoardKpis failed: ${u.status} ${m}`)}return u.json()}async function g(v,p){let u=await r(`${t}/api/feedback/v1/widget/visibility/`,{method:"POST",headers:{...a(v),"Content-Type":"application/json"},body:JSON.stringify({external_id:v,...p?{email:p}:{}})});if(!u.ok)throw new Error(`checkVisibility failed: ${u.status}`);return!!(await u.json()).show}return{submitReport:n,checkVisibility:g,listMine:i,listChangelog:s,getReport:l,addComment:f,closeAsResolved:c,listBoard:d,fetchBoardKpis:y}}var Vt=/token|key|password|secret|auth|session|sig|credential|bearer|cookie/i,Gt=[/^eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/,/^(?:sk|pk)_proj_[A-Za-z0-9_-]{16,}$/,/^gh[pousr]_[A-Za-z0-9]{30,}$/,/^(?:sk|pk|rk|whsec)_(?:live|test)_[A-Za-z0-9]{16,}$/,/^AKIA[0-9A-Z]{12,}$/,/^xox[abprso]-[A-Za-z0-9-]{12,}$/,/^[a-f0-9]{40,}$/i,/^[A-Za-z0-9_-]{40,}$/];function Xt(e){return Gt.some(t=>t.test(e))}function Y(e){try{let t=/^https?:\/\//i.test(e),r=e.startsWith("/");if(!t&&!r)return e;let n=typeof window!="undefined"?window.location.origin:"http://localhost",a=new URL(e,n),i=new URLSearchParams;return a.searchParams.forEach((s,l)=>{Vt.test(l)||Xt(s)?i.set(l,"[redacted]"):i.set(l,s)}),a.search=i.toString(),a.hash=a.hash?"#[redacted]":"",a.toString()}catch(t){return e}}var Zt=[/\b(?:sk|pk)_proj_[A-Za-z0-9_*-]+/g,/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g,/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/g,/\bAuthorization\s*[:=]\s*["']?[A-Za-z0-9._~+/=-]{16,}["']?/gi,/\bgh[pousr]_[A-Za-z0-9]{30,}\b/g,/\b(?:sk|pk|rk|whsec)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,/\bAKIA[0-9A-Z]{12,}\b/g,/\bxox[abprso]-[A-Za-z0-9-]{12,}\b/g,/\bAIza[0-9A-Za-z_-]{35}\b/g,/\bsk-(?:proj-|svcacct-)?[A-Za-z0-9_-]{20,}\b/g,/\bsk-ant-(?:api03-)?[A-Za-z0-9_-]{40,}\b/g,/\bAC[a-f0-9]{32}\b/g,/\bSK[a-f0-9]{32}\b/g];function j(e){let t=e;for(let r of Zt)t=t.replace(r,"[redacted-token]");return t}function Ue(){var l;let e=navigator,t=(l=e.connection)==null?void 0:l.effectiveType,r=e.deviceMemory,n=document.referrer||void 0,a=n!==void 0?Y(n):void 0,i=Y(window.location.pathname+window.location.search),s;try{let f=new URL(i,window.location.origin);s=f.pathname+f.search}catch(f){s=window.location.pathname}return{viewport:{w:window.innerWidth,h:window.innerHeight,dpr:window.devicePixelRatio||1},screen:{w:window.screen.width,h:window.screen.height},platform:e.platform,language:e.language,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffset:new Date().getTimezoneOffset(),...t!==void 0&&{connection:t},online:e.onLine,...r!==void 0&&{deviceMemory:r},hardwareConcurrency:e.hardwareConcurrency,...a!==void 0&&{referrer:a},title:j(document.title||"").slice(0,200),pathname:s}}function Yt(e){if(e==null)return String(e);if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return String(e);if(e instanceof Error)return`${e.name}: ${e.message}`;if(e instanceof Element)return`<${e.tagName.toLowerCase()}>`;try{return JSON.stringify(e,(t,r)=>typeof r=="bigint"?r.toString():r)}catch(t){try{return String(e)}catch(r){return"[unserializable]"}}}function je(e){let t=["log","info","warn","error","debug"],r={};for(let n of t){let a=console[n];typeof a=="function"&&(r[n]=a,console[n]=function(...s){try{let l=s.map(Yt).join(" "),f=j(l).slice(0,2e3),c={level:n,message:f,ts:Date.now()};if(n==="error"){let b=new Error().stack;b&&(c.stack=b.split(`
|
|
2
2
|
`).slice(2,8).join(`
|
|
3
3
|
`))}e.push(c)}catch(l){}a.apply(console,s)})}return()=>{for(let[n,a]of Object.entries(r))console[n]=a}}function Oe(e,t){if(typeof window=="undefined"||typeof window.fetch!="function")return()=>{};let r=window.fetch.bind(window);return window.fetch=async function(a,i){let s=performance.now(),l=typeof a=="string"?a:a instanceof URL?a.toString():a.url,f=((i==null?void 0:i.method)||(a instanceof Request?a.method:"GET")).toUpperCase();try{let c=await r(a,i);return e.push({url:t(l),method:f,status:c.status,durationMs:Math.round(performance.now()-s),ts:Date.now()}),c}catch(c){let b=c instanceof Error?c.message:String(c);throw e.push({url:t(l),method:f,status:0,durationMs:Math.round(performance.now()-s),ts:Date.now(),error:j(b)}),c}},()=>{window.fetch=r}}function qe(e,t){if(typeof window=="undefined"||typeof window.XMLHttpRequest!="function")return()=>{};let r=window.XMLHttpRequest,n=r.prototype.open,a=r.prototype.send;return r.prototype.open=function(s,l){return this.__mfb={method:s.toUpperCase(),url:typeof l=="string"?l:l.toString(),start:performance.now()},n.apply(this,arguments)},r.prototype.send=function(s){return this.addEventListener("loadend",()=>{try{let l=this.__mfb;if(!l)return;e.push({url:t(l.url),method:l.method,status:this.status,durationMs:Math.round(performance.now()-l.start),ts:Date.now()})}catch(l){}}),a.call(this,s!=null?s:null)},()=>{r.prototype.open=n,r.prototype.send=a}}function Ve(e){if(typeof window=="undefined")return()=>{};let t=n=>{let a=n.error instanceof Error?n.error.stack:void 0,i=a!==void 0?j(a):void 0;e.push({message:j(n.message||"Unknown error"),...i!==void 0&&{stack:i},ts:Date.now(),source:"window.error"})},r=n=>{let a=n.reason,i=a instanceof Error?a.message:typeof a=="string"?a:(()=>{try{return JSON.stringify(a)}catch(f){return String(a)}})(),s=a instanceof Error?a.stack:void 0,l=s!==void 0?j(s):void 0;e.push({message:j(i),...l!==void 0&&{stack:l},ts:Date.now(),source:"unhandledrejection"})};return window.addEventListener("error",t),window.addEventListener("unhandledrejection",r),()=>{window.removeEventListener("error",t),window.removeEventListener("unhandledrejection",r)}}function Ge(e=1e3){let t=[],r=[],n=null;if(typeof PerformanceObserver!="undefined")try{n=new PerformanceObserver(a=>{for(let i of a.getEntries())if(i.entryType==="longtask")for(t.push({duration:i.duration,startTime:i.startTime});t.length>20;)t.shift();else if(i.entryType==="resource"){let s=i;if(s.duration>e)for(r.push({name:Y(s.name),duration:s.duration,initiatorType:s.initiatorType});r.length>20;)r.shift()}}),n.observe({entryTypes:["longtask","resource"]})}catch(a){}return{snapshot(){let a=typeof performance!="undefined"?performance.getEntriesByType("navigation")[0]:void 0,i=a?{type:a.type,duration:a.duration}:void 0;return{...i!==void 0&&{navigation:i},longTasks:t.slice(),slowResources:r.slice()}},dispose(){n==null||n.disconnect()}}}var te=class{constructor(t){Ce(this,"max",t);Ce(this,"items",[])}push(t){for(this.items.push(t);this.items.length>this.max;)this.items.shift()}snapshot(){return this.items.slice()}clear(){this.items.length=0}};function Xe(e={}){var g;let{maxConsole:t=50,maxNetwork:r=50,maxErrors:n=20}=e,a=(g=e.sanitizeUrl)!=null?g:Y,i=new te(t),s=new te(r),l=new te(n),f=je(i),c=Oe(s,a),b=qe(s,a),d=Ve(l),y=Ge();return{snapshot(){return{consoleLogs:i.snapshot(),networkRequests:s.snapshot(),errors:l.snapshot(),device:Ue(),capturedAt:Date.now()}},clear(){i.clear(),s.clear(),l.clear()},dispose(){f(),c(),b(),d(),y.dispose()}}}var Jt={"fab.label":"Send feedback","form.title":"Send feedback","form.description.label":"What happened?","form.description.placeholder":"Describe the issue or idea in one or two sentences.","form.type.label":"Type","form.severity.label":"Severity","form.submit":"Send","form.cancel":"Cancel","form.close":"Close","form.submitting":"Sending\u2026","form.success":"Thanks \u2014 your feedback was sent.","form.error":"Could not send. Please try again.","form.description.required":"Please describe the issue before sending.","form.screenshot.label":"Screenshot","form.screenshot.cta_click":"Click","form.screenshot.cta_rest":"drop, or paste an image","form.screenshot.formats":"PNG, JPEG or WebP \u2014 up to 10 MB","form.screenshot.remove":"Remove screenshot","form.screenshot.annotate":"Annotate","form.screenshot.error_type":"Unsupported file type. Use PNG, JPEG or WebP.","form.screenshot.error_size":"File too large (max {max} MB).","form.context.label":"Page","type.bug":"Bug","type.feature":"Feature request","type.question":"Question","type.praise":"Praise","type.typo":"Typo","severity.blocker":"Blocker","severity.high":"High","severity.medium":"Medium","severity.low":"Low","annotator.title":"Annotate screenshot","annotator.tool.rectangle":"Rectangle","annotator.tool.arrow":"Arrow","annotator.tool.freehand":"Freehand","annotator.tool.text":"Text","annotator.tool.highlight":"Highlight","annotator.tool.blur":"Blur (hide sensitive data)","annotator.text_prompt":"Enter text:","annotator.color_picker":"Custom color","annotator.undo":"Undo","annotator.redo":"Redo","annotator.clear":"Clear all","annotator.count_suffix":"annotations","annotator.loading":"Loading\u2026","annotator.apply":"Apply","annotator.applying":"Applying\u2026","tab.send":"Send","tab.mine":"My reports","tab.changelog":"This week","tab.board":"Board","board.kpi.total":"Total","board.kpi.new":"New","board.kpi.in_progress":"In progress","board.kpi.awaiting_validation":"Awaiting validation","board.kpi.closed":"Closed","board.kpi.rejected":"Rejected","board.kpi.resolution_rate":"Resolution rate","board.filter.status":"Status","board.filter.type":"Type","board.filter.severity":"Severity","board.filter.search.placeholder":"Search\u2026","board.filter.mine":"Mine only","board.filter.clear":"Clear filters","board.list.empty.title":"Nothing here yet","board.list.empty.description":"When reports land, they\u2019ll show up here.","board.list.loading":"Loading\u2026","board.list.error":"Couldn\u2019t load reports. Try again.","board.list.you":"you","board.list.count":"{n} of {total}","board.detail.empty":"Pick a report on the left to see its full thread.","board.detail.by":"By","board.detail.confirm_resolution":"Confirm resolution","board.detail.status_history":"History","board.scope.project":"Project reports","board.scope.mine":"Your reports","board.back":"Back","changelog.empty.title":"Nothing resolved yet","changelog.empty.body":"Once a report you sent is fixed it will appear here, grouped by week.","changelog.week_of":"Week of {date}","changelog.resolved_one":"{count} resolved","changelog.resolved_many":"{count} resolved","mine.empty.title":"No reports yet","mine.empty.body":"Once you send feedback you can follow the thread here.","mine.refresh":"Refresh","mine.loading":"Loading\u2026","mine.error":"Could not load your reports.","mine.replies_one":"1 reply","mine.replies_many":"{count} replies","mine.filter.empty":"No reports match this filter.","kpi.new":"New","kpi.in_progress":"In progress","kpi.awaiting_validation":"Awaiting you","kpi.resolution_rate":"Resolution rate","detail.back":"Back","detail.thread":"Conversation","detail.no_replies":"No replies yet \u2014 we\u2019ll let you know when an operator responds.","detail.compose_placeholder":"Add a follow-up reply\u2026","detail.compose_send":"Reply","detail.compose_sending":"Sending\u2026","detail.close_cta":"Mark as resolved","detail.close_busy":"Marking\u2026","detail.teammate_notice":"Viewing a teammate\u2019s report \u2014 replies are private to the submitter.","detail.load_failed.title":"Report not available","detail.load_failed.body":"It may have been deleted, or you no longer have access to it.","detail.load_failed.cta":"Back","detail.send_failed":"Couldn\u2019t send your reply. Try again.","detail.close_failed":"Couldn\u2019t mark as resolved. Try again.","detail.history":"Status history","detail.context.submitted_at":"Submitted","detail.context.page":"Page","detail.context.capture.manual":"Manual capture","detail.context.capture.html2canvas":"Auto capture","detail.context.capture.display_media":"Screen share","detail.context.capture.none":"No screenshot","detail.author.staff":"Operator","detail.author.mcp":"Mhosaic Team","detail.author.system":"System","detail.tech.title":"What we received","detail.tech.errors_one":"error","detail.tech.errors_many":"errors","detail.tech.device":"Device","detail.tech.device.viewport":"Viewport","detail.tech.device.platform":"Platform","detail.tech.device.language":"Language","detail.tech.device.timezone":"Timezone","detail.tech.device.connection":"Connection","detail.tech.errors":"Runtime errors","detail.tech.console":"Console (last 20)","detail.tech.network":"Network (last 15)","status.new":"New","status.in_progress":"In progress","status.awaiting_validation":"Awaiting your validation","status.closed":"Closed","status.rejected":"Rejected","status.duplicate":"Duplicate","status.wontfix":"Won\u2019t fix"},Qt={"fab.label":"Envoyer un commentaire","form.title":"Envoyer un commentaire","form.description.label":"Qu\u2019est-il arriv\xE9 ?","form.description.placeholder":"D\xE9crivez le probl\xE8me ou l\u2019id\xE9e en une ou deux phrases.","form.type.label":"Type","form.severity.label":"S\xE9v\xE9rit\xE9","form.submit":"Envoyer","form.cancel":"Annuler","form.close":"Fermer","form.submitting":"Envoi\u2026","form.success":"Merci \u2014 votre commentaire a \xE9t\xE9 envoy\xE9.","form.error":"\xC9chec d\u2019envoi. Veuillez r\xE9essayer.","form.description.required":"D\xE9crivez le probl\xE8me avant d\u2019envoyer.","form.screenshot.label":"Capture d\u2019\xE9cran","form.screenshot.cta_click":"Cliquez","form.screenshot.cta_rest":"d\xE9posez ou collez une image","form.screenshot.formats":"PNG, JPEG ou WebP \u2014 jusqu\u2019\xE0 10 Mo","form.screenshot.remove":"Retirer la capture","form.screenshot.annotate":"Annoter","form.screenshot.error_type":"Format non support\xE9. Utilisez PNG, JPEG ou WebP.","form.screenshot.error_size":"Fichier trop volumineux (max {max} Mo).","form.context.label":"Page","type.bug":"Bogue","type.feature":"Suggestion","type.question":"Question","type.praise":"Compliment","type.typo":"Coquille","severity.blocker":"Bloquant","severity.high":"\xC9lev\xE9e","severity.medium":"Moyenne","severity.low":"Faible","annotator.title":"Annoter la capture","annotator.tool.rectangle":"Rectangle","annotator.tool.arrow":"Fl\xE8che","annotator.tool.freehand":"Dessin libre","annotator.tool.text":"Texte","annotator.tool.highlight":"Surligner","annotator.tool.blur":"Flouter (donn\xE9es sensibles)","annotator.text_prompt":"Entrez le texte :","annotator.color_picker":"Couleur personnalis\xE9e","annotator.undo":"Annuler","annotator.redo":"Refaire","annotator.clear":"Tout effacer","annotator.count_suffix":"annotations","annotator.loading":"Chargement\u2026","annotator.apply":"Appliquer","annotator.applying":"Application\u2026","tab.send":"Envoyer","tab.mine":"Mes rapports","tab.changelog":"Cette semaine","tab.board":"Tableau","board.kpi.total":"Total","board.kpi.new":"Nouveau","board.kpi.in_progress":"En cours","board.kpi.awaiting_validation":"\xC0 valider","board.kpi.closed":"Ferm\xE9","board.kpi.rejected":"Refus\xE9","board.kpi.resolution_rate":"Taux de r\xE9solution","board.filter.status":"Statut","board.filter.type":"Type","board.filter.severity":"S\xE9v\xE9rit\xE9","board.filter.search.placeholder":"Rechercher\u2026","board.filter.mine":"Les miens","board.filter.clear":"Effacer les filtres","board.list.empty.title":"Rien \xE0 voir ici","board.list.empty.description":"Les rapports appara\xEEtront ici d\xE8s qu\u2019ils arrivent.","board.list.loading":"Chargement\u2026","board.list.error":"Impossible de charger les rapports. R\xE9essayez.","board.list.you":"vous","board.list.count":"{n} sur {total}","board.detail.empty":"S\xE9lectionnez un rapport \xE0 gauche pour voir le fil complet.","board.detail.by":"Par","board.detail.confirm_resolution":"Confirmer la r\xE9solution","board.detail.status_history":"Historique","board.scope.project":"Rapports du projet","board.scope.mine":"Vos rapports","board.back":"Retour","changelog.empty.title":"Rien de r\xE9solu pour l\u2019instant","changelog.empty.body":"Quand un rapport que vous avez envoy\xE9 est corrig\xE9, il appara\xEEtra ici, regroup\xE9 par semaine.","changelog.week_of":"Semaine du {date}","changelog.resolved_one":"{count} r\xE9solu","changelog.resolved_many":"{count} r\xE9solus","mine.empty.title":"Aucun rapport","mine.empty.body":"Apr\xE8s votre premier envoi vous pourrez suivre la conversation ici.","mine.refresh":"Actualiser","mine.loading":"Chargement\u2026","mine.error":"Impossible de charger vos rapports.","mine.replies_one":"1 r\xE9ponse","mine.replies_many":"{count} r\xE9ponses","mine.filter.empty":"Aucun rapport ne correspond \xE0 ce filtre.","kpi.new":"Nouveau","kpi.in_progress":"En cours","kpi.awaiting_validation":"\xC0 valider","kpi.resolution_rate":"Taux de r\xE9solution","detail.back":"Retour","detail.thread":"Conversation","detail.no_replies":"Pas encore de r\xE9ponse \u2014 vous serez notifi\xE9 d\xE8s qu\u2019un op\xE9rateur r\xE9pondra.","detail.compose_placeholder":"Ajouter une r\xE9ponse\u2026","detail.compose_send":"R\xE9pondre","detail.compose_sending":"Envoi\u2026","detail.close_cta":"Marquer comme r\xE9solu","detail.close_busy":"Validation\u2026","detail.teammate_notice":"Vous consultez le rapport d\u2019un co\xE9quipier \u2014 les r\xE9ponses sont priv\xE9es au soumetteur.","detail.load_failed.title":"Rapport indisponible","detail.load_failed.body":"Il a peut-\xEAtre \xE9t\xE9 supprim\xE9, ou vous n\u2019y avez plus acc\xE8s.","detail.load_failed.cta":"Retour","detail.send_failed":"Impossible d\u2019envoyer votre r\xE9ponse. R\xE9essayez.","detail.close_failed":"Impossible de marquer comme r\xE9solu. R\xE9essayez.","detail.history":"Historique du statut","detail.context.submitted_at":"Envoy\xE9","detail.context.page":"Page","detail.context.capture.manual":"Capture manuelle","detail.context.capture.html2canvas":"Capture automatique","detail.context.capture.display_media":"Partage d\u2019\xE9cran","detail.context.capture.none":"Sans capture","detail.author.staff":"Op\xE9rateur","detail.author.mcp":"\xC9quipe Mhosaic","detail.author.system":"Syst\xE8me","detail.tech.title":"Ce que nous avons re\xE7u","detail.tech.errors_one":"erreur","detail.tech.errors_many":"erreurs","detail.tech.device":"Appareil","detail.tech.device.viewport":"Fen\xEAtre","detail.tech.device.platform":"Plateforme","detail.tech.device.language":"Langue","detail.tech.device.timezone":"Fuseau horaire","detail.tech.device.connection":"Connexion","detail.tech.errors":"Erreurs d\u2019ex\xE9cution","detail.tech.console":"Console (20 derniers)","detail.tech.network":"R\xE9seau (15 derniers)","status.new":"Nouveau","status.in_progress":"En cours","status.awaiting_validation":"En attente de validation","status.closed":"Ferm\xE9","status.rejected":"Rejet\xE9","status.duplicate":"Doublon","status.wontfix":"Non corrig\xE9"},er={fr:Qt};function tr(e){var r;if(!e)return null;let t=e.toLowerCase().split(/[-_]/)[0];return(r=er[t])!=null?r:null}function Ze(e,t={}){var n;let r=(n=tr(t.locale))!=null?n:{};return{...Jt,...r,...e}}var be,z,tt,rr,X,Ye,rt,ot,Re,ce,ie,nt,Pe,Ee,Me,or,ue={},fe=[],nr=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,he=Array.isArray;function G(e,t){for(var r in t)e[r]=t[r];return e}function ze(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Be(e,t,r){var n,a,i,s={};for(i in t)i=="key"?n=t[i]:i=="ref"?a=t[i]:s[i]=t[i];if(arguments.length>2&&(s.children=arguments.length>3?be.call(arguments,2):r),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)s[i]===void 0&&(s[i]=e.defaultProps[i]);return de(e,s,n,a,null)}function de(e,t,r,n,a){var i={type:e,props:t,key:r,ref:n,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:a==null?++tt:a,__i:-1,__u:0};return a==null&&z.vnode!=null&&z.vnode(i),i}function U(e){return e.children}function pe(e,t){this.props=e,this.context=t}function re(e,t){if(t==null)return e.__?re(e.__,e.__i+1):null;for(var r;t<e.__k.length;t++)if((r=e.__k[t])!=null&&r.__e!=null)return r.__e;return typeof e.type=="function"?re(e):null}function ar(e){if(e.__P&&e.__d){var t=e.__v,r=t.__e,n=[],a=[],i=G({},t);i.__v=t.__v+1,z.vnode&&z.vnode(i),Le(e.__P,i,t,e.__n,e.__P.namespaceURI,32&t.__u?[r]:null,n,r==null?re(t):r,!!(32&t.__u),a),i.__v=t.__v,i.__.__k[i.__i]=i,lt(n,i,a),t.__e=t.__=null,i.__e!=r&&at(i)}}function at(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(t){if(t!=null&&t.__e!=null)return e.__e=e.__c.base=t.__e}),at(e)}function Je(e){(!e.__d&&(e.__d=!0)&&X.push(e)&&!me.__r++||Ye!=z.debounceRendering)&&((Ye=z.debounceRendering)||rt)(me)}function me(){try{for(var e,t=1;X.length;)X.length>t&&X.sort(ot),e=X.shift(),t=X.length,ar(e)}finally{X.length=me.__r=0}}function it(e,t,r,n,a,i,s,l,f,c,b){var d,y,g,k,_,v,p,u=n&&n.__k||fe,m=t.length;for(f=ir(r,t,u,f,m),d=0;d<m;d++)(g=r.__k[d])!=null&&(y=g.__i!=-1&&u[g.__i]||ue,g.__i=d,v=Le(e,g,y,a,i,s,l,f,c,b),k=g.__e,g.ref&&y.ref!=g.ref&&(y.ref&&Fe(y.ref,null,g),b.push(g.ref,g.__c||k,g)),_==null&&k!=null&&(_=k),(p=!!(4&g.__u))||y.__k===g.__k?(f=st(g,f,e,p),p&&y.__e&&(y.__e=null)):typeof g.type=="function"&&v!==void 0?f=v:k&&(f=k.nextSibling),g.__u&=-7);return r.__e=_,f}function ir(e,t,r,n,a){var i,s,l,f,c,b=r.length,d=b,y=0;for(e.__k=new Array(a),i=0;i<a;i++)(s=t[i])!=null&&typeof s!="boolean"&&typeof s!="function"?(typeof s=="string"||typeof s=="number"||typeof s=="bigint"||s.constructor==String?s=e.__k[i]=de(null,s,null,null,null):he(s)?s=e.__k[i]=de(U,{children:s},null,null,null):s.constructor===void 0&&s.__b>0?s=e.__k[i]=de(s.type,s.props,s.key,s.ref?s.ref:null,s.__v):e.__k[i]=s,f=i+y,s.__=e,s.__b=e.__b+1,l=null,(c=s.__i=sr(s,r,f,d))!=-1&&(d--,(l=r[c])&&(l.__u|=2)),l==null||l.__v==null?(c==-1&&(a>b?y--:a<b&&y++),typeof s.type!="function"&&(s.__u|=4)):c!=f&&(c==f-1?y--:c==f+1?y++:(c>f?y--:y++,s.__u|=4))):e.__k[i]=null;if(d)for(i=0;i<b;i++)(l=r[i])!=null&&(2&l.__u)==0&&(l.__e==n&&(n=re(l)),dt(l,l));return n}function st(e,t,r,n){var a,i;if(typeof e.type=="function"){for(a=e.__k,i=0;a&&i<a.length;i++)a[i]&&(a[i].__=e,t=st(a[i],t,r,n));return t}e.__e!=t&&(n&&(t&&e.type&&!t.parentNode&&(t=re(e)),r.insertBefore(e.__e,t||null)),t=e.__e);do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function sr(e,t,r,n){var a,i,s,l=e.key,f=e.type,c=t[r],b=c!=null&&(2&c.__u)==0;if(c===null&&l==null||b&&l==c.key&&f==c.type)return r;if(n>(b?1:0)){for(a=r-1,i=r+1;a>=0||i<t.length;)if((c=t[s=a>=0?a--:i++])!=null&&(2&c.__u)==0&&l==c.key&&f==c.type)return s}return-1}function Qe(e,t,r){t[0]=="-"?e.setProperty(t,r==null?"":r):e[t]=r==null?"":typeof r!="number"||nr.test(t)?r:r+"px"}function le(e,t,r,n,a){var i,s;e:if(t=="style")if(typeof r=="string")e.style.cssText=r;else{if(typeof n=="string"&&(e.style.cssText=n=""),n)for(t in n)r&&t in r||Qe(e.style,t,"");if(r)for(t in r)n&&r[t]==n[t]||Qe(e.style,t,r[t])}else if(t[0]=="o"&&t[1]=="n")i=t!=(t=t.replace(nt,"$1")),s=t.toLowerCase(),t=s in e||t=="onFocusOut"||t=="onFocusIn"?s.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=r,r?n?r[ie]=n[ie]:(r[ie]=Pe,e.addEventListener(t,i?Me:Ee,i)):e.removeEventListener(t,i?Me:Ee,i);else{if(a=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=r==null?"":r;break e}catch(l){}typeof r=="function"||(r==null||r===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&r==1?"":r))}}function et(e){return function(t){if(this.l){var r=this.l[t.type+e];if(t[ce]==null)t[ce]=Pe++;else if(t[ce]<r[ie])return;return r(z.event?z.event(t):t)}}}function Le(e,t,r,n,a,i,s,l,f,c){var b,d,y,g,k,_,v,p,u,m,x,R,L,T,F,P=t.type;if(t.constructor!==void 0)return null;128&r.__u&&(f=!!(32&r.__u),i=[l=t.__e=r.__e]),(b=z.__b)&&b(t);e:if(typeof P=="function")try{if(p=t.props,u=P.prototype&&P.prototype.render,m=(b=P.contextType)&&n[b.__c],x=b?m?m.props.value:b.__:n,r.__c?v=(d=t.__c=r.__c).__=d.__E:(u?t.__c=d=new P(p,x):(t.__c=d=new pe(p,x),d.constructor=P,d.render=cr),m&&m.sub(d),d.state||(d.state={}),d.__n=n,y=d.__d=!0,d.__h=[],d._sb=[]),u&&d.__s==null&&(d.__s=d.state),u&&P.getDerivedStateFromProps!=null&&(d.__s==d.state&&(d.__s=G({},d.__s)),G(d.__s,P.getDerivedStateFromProps(p,d.__s))),g=d.props,k=d.state,d.__v=t,y)u&&P.getDerivedStateFromProps==null&&d.componentWillMount!=null&&d.componentWillMount(),u&&d.componentDidMount!=null&&d.__h.push(d.componentDidMount);else{if(u&&P.getDerivedStateFromProps==null&&p!==g&&d.componentWillReceiveProps!=null&&d.componentWillReceiveProps(p,x),t.__v==r.__v||!d.__e&&d.shouldComponentUpdate!=null&&d.shouldComponentUpdate(p,d.__s,x)===!1){t.__v!=r.__v&&(d.props=p,d.state=d.__s,d.__d=!1),t.__e=r.__e,t.__k=r.__k,t.__k.some(function(K){K&&(K.__=t)}),fe.push.apply(d.__h,d._sb),d._sb=[],d.__h.length&&s.push(d);break e}d.componentWillUpdate!=null&&d.componentWillUpdate(p,d.__s,x),u&&d.componentDidUpdate!=null&&d.__h.push(function(){d.componentDidUpdate(g,k,_)})}if(d.context=x,d.props=p,d.__P=e,d.__e=!1,R=z.__r,L=0,u)d.state=d.__s,d.__d=!1,R&&R(t),b=d.render(d.props,d.state,d.context),fe.push.apply(d.__h,d._sb),d._sb=[];else do d.__d=!1,R&&R(t),b=d.render(d.props,d.state,d.context),d.state=d.__s;while(d.__d&&++L<25);d.state=d.__s,d.getChildContext!=null&&(n=G(G({},n),d.getChildContext())),u&&!y&&d.getSnapshotBeforeUpdate!=null&&(_=d.getSnapshotBeforeUpdate(g,k)),T=b!=null&&b.type===U&&b.key==null?ct(b.props.children):b,l=it(e,he(T)?T:[T],t,r,n,a,i,s,l,f,c),d.base=t.__e,t.__u&=-161,d.__h.length&&s.push(d),v&&(d.__E=d.__=null)}catch(K){if(t.__v=null,f||i!=null)if(K.then){for(t.__u|=f?160:128;l&&l.nodeType==8&&l.nextSibling;)l=l.nextSibling;i[i.indexOf(l)]=null,t.__e=l}else{for(F=i.length;F--;)ze(i[F]);Te(t)}else t.__e=r.__e,t.__k=r.__k,K.then||Te(t);z.__e(K,t,r)}else i==null&&t.__v==r.__v?(t.__k=r.__k,t.__e=r.__e):l=t.__e=lr(r.__e,t,r,n,a,i,s,f,c);return(b=z.diffed)&&b(t),128&t.__u?void 0:l}function Te(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(Te))}function lt(e,t,r){for(var n=0;n<r.length;n++)Fe(r[n],r[++n],r[++n]);z.__c&&z.__c(t,e),e.some(function(a){try{e=a.__h,a.__h=[],e.some(function(i){i.call(a)})}catch(i){z.__e(i,a.__v)}})}function ct(e){return typeof e!="object"||e==null||e.__b>0?e:he(e)?e.map(ct):G({},e)}function lr(e,t,r,n,a,i,s,l,f){var c,b,d,y,g,k,_,v=r.props||ue,p=t.props,u=t.type;if(u=="svg"?a="http://www.w3.org/2000/svg":u=="math"?a="http://www.w3.org/1998/Math/MathML":a||(a="http://www.w3.org/1999/xhtml"),i!=null){for(c=0;c<i.length;c++)if((g=i[c])&&"setAttribute"in g==!!u&&(u?g.localName==u:g.nodeType==3)){e=g,i[c]=null;break}}if(e==null){if(u==null)return document.createTextNode(p);e=document.createElementNS(a,u,p.is&&p),l&&(z.__m&&z.__m(t,i),l=!1),i=null}if(u==null)v===p||l&&e.data==p||(e.data=p);else{if(i=i&&be.call(e.childNodes),!l&&i!=null)for(v={},c=0;c<e.attributes.length;c++)v[(g=e.attributes[c]).name]=g.value;for(c in v)g=v[c],c=="dangerouslySetInnerHTML"?d=g:c=="children"||c in p||c=="value"&&"defaultValue"in p||c=="checked"&&"defaultChecked"in p||le(e,c,null,g,a);for(c in p)g=p[c],c=="children"?y=g:c=="dangerouslySetInnerHTML"?b=g:c=="value"?k=g:c=="checked"?_=g:l&&typeof g!="function"||v[c]===g||le(e,c,g,v[c],a);if(b)l||d&&(b.__html==d.__html||b.__html==e.innerHTML)||(e.innerHTML=b.__html),t.__k=[];else if(d&&(e.innerHTML=""),it(t.type=="template"?e.content:e,he(y)?y:[y],t,r,n,u=="foreignObject"?"http://www.w3.org/1999/xhtml":a,i,s,i?i[0]:r.__k&&re(r,0),l,f),i!=null)for(c=i.length;c--;)ze(i[c]);l||(c="value",u=="progress"&&k==null?e.removeAttribute("value"):k!=null&&(k!==e[c]||u=="progress"&&!k||u=="option"&&k!=v[c])&&le(e,c,k,v[c],a),c="checked",_!=null&&_!=e[c]&&le(e,c,_,v[c],a))}return e}function Fe(e,t,r){try{if(typeof e=="function"){var n=typeof e.__u=="function";n&&e.__u(),n&&t==null||(e.__u=e(t))}else e.current=t}catch(a){z.__e(a,r)}}function dt(e,t,r){var n,a;if(z.unmount&&z.unmount(e),(n=e.ref)&&(n.current&&n.current!=e.__e||Fe(n,null,t)),(n=e.__c)!=null){if(n.componentWillUnmount)try{n.componentWillUnmount()}catch(i){z.__e(i,t)}n.base=n.__P=null}if(n=e.__k)for(a=0;a<n.length;a++)n[a]&&dt(n[a],t,r||typeof e.type!="function");r||ze(e.__e),e.__c=e.__=e.__e=void 0}function cr(e,t,r){return this.constructor(e,r)}function Ae(e,t,r){var n,a,i,s;t==document&&(t=document.documentElement),z.__&&z.__(e,t),a=(n=typeof r=="function")?null:r&&r.__k||t.__k,i=[],s=[],Le(t,e=(!n&&r||t).__k=Be(U,null,[e]),a||ue,ue,t.namespaceURI,!n&&r?[r]:a?null:t.firstChild?be.call(t.childNodes):null,i,!n&&r?r:a?a.__e:t.firstChild,n,s),lt(i,e,s)}be=fe.slice,z={__e:function(e,t,r,n){for(var a,i,s;t=t.__;)if((a=t.__c)&&!a.__)try{if((i=a.constructor)&&i.getDerivedStateFromError!=null&&(a.setState(i.getDerivedStateFromError(e)),s=a.__d),a.componentDidCatch!=null&&(a.componentDidCatch(e,n||{}),s=a.__d),s)return a.__E=a}catch(l){e=l}throw e}},tt=0,rr=function(e){return e!=null&&e.constructor===void 0},pe.prototype.setState=function(e,t){var r;r=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=G({},this.state),typeof e=="function"&&(e=e(G({},r),this.props)),e&&G(r,e),e!=null&&this.__v&&(t&&this._sb.push(t),Je(this))},pe.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Je(this))},pe.prototype.render=U,X=[],rt=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,ot=function(e,t){return e.__v.__b-t.__v.__b},me.__r=0,Re=Math.random().toString(8),ce="__d"+Re,ie="__a"+Re,nt=/(PointerCapture)$|Capture$/i,Pe=0,Ee=et(!1),Me=et(!0),or=0;var oe,A,Ie,pt,se=0,yt=[],$=z,ut=$.__b,ft=$.__r,mt=$.diffed,bt=$.__c,ht=$.unmount,gt=$.__;function ve(e,t){$.__h&&$.__h(A,e,se||t),se=0;var r=A.__H||(A.__H={__:[],__h:[]});return e>=r.__.length&&r.__.push({}),r.__[e]}function C(e){return se=1,dr(xt,e)}function dr(e,t,r){var n=ve(oe++,2);if(n.t=e,!n.__c&&(n.__=[r?r(t):xt(void 0,t),function(l){var f=n.__N?n.__N[0]:n.__[0],c=n.t(f,l);f!==c&&(n.__N=[c,n.__[1]],n.__c.setState({}))}],n.__c=A,!A.__f)){var a=function(l,f,c){if(!n.__c.__H)return!0;var b=n.__c.__H.__.filter(function(y){return y.__c});if(b.every(function(y){return!y.__N}))return!i||i.call(this,l,f,c);var d=n.__c.props!==l;return b.some(function(y){if(y.__N){var g=y.__[0];y.__=y.__N,y.__N=void 0,g!==y.__[0]&&(d=!0)}}),i&&i.call(this,l,f,c)||d};A.__f=!0;var i=A.shouldComponentUpdate,s=A.componentWillUpdate;A.componentWillUpdate=function(l,f,c){if(this.__e){var b=i;i=void 0,a(l,f,c),i=b}s&&s.call(this,l,f,c)},A.shouldComponentUpdate=a}return n.__N||n.__}function D(e,t){var r=ve(oe++,3);!$.__s&&Ke(r.__H,t)&&(r.__=e,r.u=t,A.__H.__h.push(r))}function De(e,t){var r=ve(oe++,4);!$.__s&&Ke(r.__H,t)&&(r.__=e,r.u=t,A.__h.push(r))}function W(e){return se=5,J(function(){return{current:e}},[])}function J(e,t){var r=ve(oe++,7);return Ke(r.__H,t)&&(r.__=e(),r.__H=t,r.__h=e),r.__}function _t(e,t){return se=8,J(function(){return e},t)}function pr(){for(var e;e=yt.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(ge),t.__h.some($e),t.__h=[]}catch(r){t.__h=[],$.__e(r,e.__v)}}}$.__b=function(e){A=null,ut&&ut(e)},$.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),gt&>(e,t)},$.__r=function(e){ft&&ft(e),oe=0;var t=(A=e.__c).__H;t&&(Ie===A?(t.__h=[],A.__h=[],t.__.some(function(r){r.__N&&(r.__=r.__N),r.u=r.__N=void 0})):(t.__h.some(ge),t.__h.some($e),t.__h=[],oe=0)),Ie=A},$.diffed=function(e){mt&&mt(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(yt.push(t)!==1&&pt===$.requestAnimationFrame||((pt=$.requestAnimationFrame)||ur)(pr)),t.__H.__.some(function(r){r.u&&(r.__H=r.u),r.u=void 0})),Ie=A=null},$.__c=function(e,t){t.some(function(r){try{r.__h.some(ge),r.__h=r.__h.filter(function(n){return!n.__||$e(n)})}catch(n){t.some(function(a){a.__h&&(a.__h=[])}),t=[],$.__e(n,r.__v)}}),bt&&bt(e,t)},$.unmount=function(e){ht&&ht(e);var t,r=e.__c;r&&r.__H&&(r.__H.__.some(function(n){try{ge(n)}catch(a){t=a}}),r.__H=void 0,t&&$.__e(t,r.__v))};var vt=typeof requestAnimationFrame=="function";function ur(e){var t,r=function(){clearTimeout(n),vt&&cancelAnimationFrame(t),setTimeout(e)},n=setTimeout(r,35);vt&&(t=requestAnimationFrame(r))}function ge(e){var t=A,r=e.__c;typeof r=="function"&&(e.__c=void 0,r()),A=t}function $e(e){var t=A;e.__c=e.__(),A=t}function Ke(e,t){return!e||e.length!==t.length||t.some(function(r,n){return r!==e[n]})}function xt(e,t){return typeof t=="function"?t(e):t}var fr=0;function o(e,t,r,n,a,i){t||(t={});var s,l,f=t;if("ref"in f)for(l in f={},t)l=="ref"?s=t[l]:f[l]=t[l];var c={type:e,props:f,key:r,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--fr,__i:-1,__u:0,__source:a,__self:i};if(typeof e=="function"&&(s=e.defaultProps))for(l in s)f[l]===void 0&&(f[l]=s[l]);return z.vnode&&z.vnode(c),c}function wt({comment:e,strings:t}){let r=e.is_mine,n=!r&&e.author_source==="mcp",a=!r&&e.author_source==="system",i=n?"mcp":a?"system":"staff",s=i==="mcp"?"detail.author.mcp":i==="system"?"detail.author.system":"detail.author.staff",l=e.author_label||t[s];return o("div",{class:`comment-bubble ${r?"is-mine":"is-other"}`,children:[!r&&l&&o("div",{class:`comment-author comment-author--${i}`,children:l}),o("div",{class:"comment-body",children:e.body}),o("div",{class:"comment-time",children:mr(e.created_at)})]})}function mr(e){try{return new Date(e).toLocaleString(void 0,{dateStyle:"short",timeStyle:"short"})}catch(t){return e}}var br=["image/png","image/jpeg","image/webp"];function kt(e){return br.includes(e.type)?e.size>10485760?{kind:"size",maxMb:10485760/(1024*1024)}:null:{kind:"type"}}function ne(e,t=80){if(e.length<=t)return e;let r=Math.floor((t-1)/2),n=t-1-r;return`${e.slice(0,r)}\u2026${e.slice(e.length-n)}`}function We(e){if(!e)return;let t;try{t=new URL(e)}catch(r){return}if(t.protocol==="https:"||t.protocol==="http:"&&(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="[::1]"))return t.toString()}var hr=3e4;function ye({api:e,externalId:t,reportId:r,strings:n,onBack:a,canModerate:i=!0,variant:s="modal"}){var F,P,K;let[l,f]=C(null),[c,b]=C(null),[d,y]=C(""),[g,k]=C(!1),[_,v]=C(!1),p=W(!0),u=async()=>{try{let B=await e.getReport(r,t);if(!p.current)return;f(B),b(null)}catch(B){if(typeof console!="undefined"&&console.warn("[mhosaic] getReport:",B),!p.current)return;b("load_failed")}};D(()=>{p.current=!0,u();let B=setInterval(()=>{u()},hr);return()=>{p.current=!1,clearInterval(B)}},[r,t]);let m=async()=>{if(!(!d.trim()||g)){k(!0);try{let B=`${r}:${Date.now()}`,O=await e.addComment(r,t,d.trim(),B);if(!p.current)return;y(""),f(N=>N&&{...N,comments:gr(N.comments,O)}),u()}catch(B){if(typeof console!="undefined"&&console.warn("[mhosaic] addComment:",B),!p.current)return;b(n["detail.send_failed"])}finally{p.current&&k(!1)}}},x=async()=>{if(!_){v(!0);try{let B=await e.closeAsResolved(r,t);if(!p.current)return;f(B)}catch(B){if(typeof console!="undefined"&&console.warn("[mhosaic] closeAsResolved:",B),!p.current)return;b(n["detail.close_failed"])}finally{p.current&&v(!1)}}};if(!l&&!c)return o("div",{class:"mine-loading",children:n["mine.loading"]});if(!l)return o("div",{class:"report-detail-empty-state",role:"alert",children:[o("p",{class:"report-detail-empty-state-title",children:n["detail.load_failed.title"]}),o("p",{class:"report-detail-empty-state-body",children:n["detail.load_failed.body"]}),o("button",{type:"button",class:"btn",onClick:a,children:["\u2190 ",n["detail.load_failed.cta"]]})]});let R=(F=l.is_mine)!=null?F:i,L=R&&l.status==="awaiting_validation",T=R;return o("div",{class:`report-detail variant-${s}`,children:[s==="modal"&&o("div",{class:"report-detail-header",children:[o("button",{type:"button",class:"btn",onClick:a,children:["\u2190 ",n["detail.back"]]}),o("span",{class:`pill pill-status pill-status--${l.status}`,children:(P=n[`status.${l.status}`])!=null?P:l.status})]}),s==="board"&&o("div",{class:"report-detail-header report-detail-header--board",children:[o("button",{type:"button",class:"btn btn--ghost report-detail-back",onClick:a,"aria-label":n["board.back"],children:["\u2190 ",n["board.back"]]}),o("span",{class:`pill pill-status pill-status--${l.status}`,children:(K=n[`status.${l.status}`])!=null?K:l.status})]}),o("div",{class:"report-detail-body",children:[o(vr,{detail:l,strings:n}),o("p",{class:"report-detail-description",children:l.description}),l.screenshot_url&&(()=>{let B=We(l.screenshot_url);return B?o("a",{class:"report-detail-screenshot",href:B,target:"_blank",rel:"noopener noreferrer",children:o("img",{src:l.screenshot_url,alt:"",loading:"lazy"})}):o("div",{class:"report-detail-screenshot",children:o("img",{src:l.screenshot_url,alt:"",loading:"lazy"})})})(),o("h3",{class:"report-detail-section",children:n["detail.thread"]}),l.comments.length===0?o("p",{class:"report-detail-empty",children:n["detail.no_replies"]}):o("ul",{class:"report-comments",children:l.comments.map(B=>o("li",{children:o(wt,{comment:B,strings:n})}))}),l.status_history&&l.status_history.length>0&&o(Er,{rows:l.status_history,strings:n}),l.technical_context&&o(xr,{ctx:l.technical_context,strings:n}),T?o("div",{class:"report-compose",children:[o("textarea",{value:d,placeholder:n["detail.compose_placeholder"],onInput:B=>y(B.target.value),disabled:g}),o("div",{class:"report-compose-actions",children:[L&&o("button",{type:"button",class:"btn",onClick:x,disabled:_,children:_?n["detail.close_busy"]:n["detail.close_cta"]}),o("button",{type:"button",class:"btn btn--primary",onClick:m,disabled:!d.trim()||g,children:g?n["detail.compose_sending"]:n["detail.compose_send"]})]})]}):o("p",{class:"report-detail-teammate-notice",role:"note",children:n["detail.teammate_notice"]}),c&&o("div",{class:"error",children:c})]})]})}function gr(e,t){return e.some(r=>r.id===t.id)?e:[...e,t]}function vr({detail:e,strings:t}){var a;let r=`detail.context.capture.${e.capture_method}`,n=(a=t[r])!=null?a:e.capture_method;return o("div",{class:"report-detail-context",children:[o("div",{class:"report-detail-context-pills",children:[o("span",{class:"pill pill-type",children:t[`type.${e.feedback_type}`]}),o("span",{class:`pill pill-severity pill-severity--${e.severity}`,children:t[`severity.${e.severity}`]}),o("span",{class:"pill pill-capture",children:n})]}),o("div",{class:"report-detail-context-line",children:[o("span",{class:"report-detail-context-label",children:t["detail.context.submitted_at"]}),o("span",{children:St(e.created_at)})]}),e.page_url&&(()=>{let i=We(e.page_url);return o("div",{class:"report-detail-context-line",title:e.page_url,children:[o("span",{class:"report-detail-context-label",children:t["detail.context.page"]}),i?o("a",{class:"report-detail-context-url",href:i,target:"_blank",rel:"noopener noreferrer",children:ne(e.page_url,64)}):o("span",{class:"report-detail-context-url",children:ne(e.page_url,64)})]})})()]})}function St(e){try{return new Date(e).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"})}catch(t){return e}}var yr=20,_r=15;function xr({ctx:e,strings:t}){var c,b,d;let r=(c=e.errors)!=null?c:[],n=((b=e.consoleLogs)!=null?b:[]).slice(-yr),a=((d=e.networkRequests)!=null?d:[]).slice(-_r),i=e.device;if(!(!!i||r.length>0||n.length>0||a.length>0))return null;let l=r.length,f=l>0?`${t["detail.tech.title"]} \xB7 ${l} ${l===1?t["detail.tech.errors_one"]:t["detail.tech.errors_many"]}`:t["detail.tech.title"];return o("details",{class:"report-detail-tech",children:[o("summary",{children:f}),o("div",{class:"tech-body",children:[i&&o(wr,{device:i,strings:t}),r.length>0&&o(kr,{errors:r,strings:t}),n.length>0&&o(Sr,{logs:n,strings:t}),a.length>0&&o(Cr,{rows:a,strings:t})]})]})}function wr({device:e,strings:t}){let r=[];if(e!=null&&e.viewport){let n=e.viewport.dpr?` @${e.viewport.dpr}x`:"";r.push({label:t["detail.tech.device.viewport"],value:`${e.viewport.w}\xD7${e.viewport.h}${n}`})}return e!=null&&e.platform&&r.push({label:t["detail.tech.device.platform"],value:e.platform}),e!=null&&e.language&&r.push({label:t["detail.tech.device.language"],value:e.language}),e!=null&&e.timezone&&r.push({label:t["detail.tech.device.timezone"],value:e.timezone}),e!=null&&e.connection&&r.push({label:t["detail.tech.device.connection"],value:e.connection}),r.length===0?null:o("div",{class:"tech-section",children:[o("h4",{children:t["detail.tech.device"]}),o("dl",{class:"tech-device",children:r.map(n=>o(U,{children:[o("dt",{children:n.label}),o("dd",{children:n.value})]}))})]})}function kr({errors:e,strings:t}){return o("div",{class:"tech-section",children:[o("h4",{children:t["detail.tech.errors"]}),o("ul",{class:"tech-errors",children:e.map(r=>o("li",{children:[o("div",{class:"tech-errors-msg",children:r.message}),r.stack&&o("pre",{class:"tech-errors-stack",children:Rr(r.stack)})]}))})]})}function Sr({logs:e,strings:t}){return o("div",{class:"tech-section",children:[o("h4",{children:t["detail.tech.console"]}),o("ul",{class:"tech-console",children:e.map(r=>o("li",{class:`tech-console-row tech-console-row--${r.level}`,children:[o("span",{class:"tech-console-level",children:r.level}),o("span",{class:"tech-console-msg",children:r.message})]}))})]})}function Cr({rows:e,strings:t}){return o("div",{class:"tech-section",children:[o("h4",{children:t["detail.tech.network"]}),o("ul",{class:"tech-network",children:e.map(r=>{let n=r.status>=400||r.status===0;return o("li",{class:`tech-network-row${n?" tech-network-row--fail":""}`,children:[o("span",{class:"tech-network-status",children:r.status||"\u2014"}),o("span",{class:"tech-network-method",children:r.method}),o("span",{class:"tech-network-url",title:r.url,children:ne(r.url,56)}),o("span",{class:"tech-network-time",children:[Math.round(r.durationMs),"ms"]})]})})})]})}function Rr(e){let t=e.split(`
|
|
4
4
|
`);return t.length<=12?e:t.slice(0,12).join(`
|
|
@@ -1690,5 +1690,5 @@
|
|
|
1690
1690
|
@media (prefers-reduced-motion: reduce) {
|
|
1691
1691
|
.skeleton-line { animation: none; }
|
|
1692
1692
|
}
|
|
1693
|
-
`;function po(e,t,r){return!(!e.showFAB||e.getExternalId!==void 0&&!t||e.requiresVisibilityCheck&&!r)}function $t(e){let t=e.host.attachShadow({mode:"open"}),r=document.createElement("style");r.textContent=It,t.appendChild(r);let n=document.createElement("div");t.appendChild(n);let a={open:!1,status:"idle",tab:"send"},i=null;function s(c){a=c,Ae(Be(f,{state:c}),n)}function l(c){let{selectedReportId:b,...d}=c;return d}function f({state:c}){var v;let b=_t(async p=>{s({...a,status:"submitting"});try{await e.onSubmit(p),s({...a,status:"success"}),i!==null&&clearTimeout(i),i=setTimeout(()=>{i=null,s({...a,open:!1,status:"idle",tab:e.api?"mine":"send"})},1200)}catch(u){typeof console!="undefined"&&console.warn("[mhosaic] submit:",u),s({...a,status:"error",error:e.strings["form.error"]})}},[]),d=(v=e.getExternalId)==null?void 0:v.call(e),[y,g]=C(!e.requiresVisibilityCheck);D(()=>{if(!e.requiresVisibilityCheck){g(!0);return}if(!d||!e.checkVisibility){g(!1);return}let p=!1;return e.checkVisibility(d).then(u=>{p||g(u)}).catch(()=>{p||g(!1)}),()=>{p=!0}},[d]);let k=po(e,d,y),_=!!(e.api&&d);return o(U,{children:[k&&o(Et,{label:e.strings["fab.label"],onClick:()=>s({...a,open:!0})}),c.open&&o(At,{onDismiss:()=>s(l({...a,open:!1,status:"idle"})),closeLabel:e.strings["form.close"],expanded:c.tab==="board",children:[_&&o("div",{class:"tab-strip",role:"tablist",children:[o("button",{type:"button",role:"tab","aria-selected":c.tab==="send",class:`tab-button ${c.tab==="send"?"is-active":""}`,onClick:()=>s(l({...a,tab:"send"})),children:e.strings["tab.send"]}),o("button",{type:"button",role:"tab","aria-selected":c.tab==="mine",class:`tab-button ${c.tab==="mine"?"is-active":""}`,onClick:()=>s(l({...a,tab:"mine"})),children:e.strings["tab.mine"]}),o("button",{type:"button",role:"tab","aria-selected":c.tab==="changelog",class:`tab-button ${c.tab==="changelog"?"is-active":""}`,onClick:()=>s(l({...a,tab:"changelog"})),children:e.strings["tab.changelog"]}),o("button",{type:"button",role:"tab","aria-selected":c.tab==="board",class:`tab-button tab-button--board ${c.tab==="board"?"is-active":""}`,onClick:()=>s(l({...a,tab:"board"})),children:e.strings["tab.board"]})]}),c.tab==="send"&&o(zt,{strings:e.strings,onSubmit:b,onCancel:()=>s({...a,open:!1,status:"idle"}),status:c.status,...c.error!==void 0&&{errorMessage:c.error}}),c.tab==="mine"&&e.api&&d&&!c.selectedReportId&&o(Ft,{api:e.api,externalId:d,strings:e.strings,onSelect:p=>s({...a,selectedReportId:p.id})}),(c.tab==="mine"||c.tab==="changelog")&&e.api&&d&&c.selectedReportId&&o(ye,{api:e.api,externalId:d,reportId:c.selectedReportId,strings:e.strings,onBack:()=>s(l({...a}))}),c.tab==="changelog"&&e.api&&d&&!c.selectedReportId&&o(Rt,{api:e.api,externalId:d,strings:e.strings,onSelect:p=>s({...a,selectedReportId:p.id})}),c.tab==="board"&&e.api&&d&&o(Ct,{api:e.api,externalId:d,strings:e.strings})]})]})}return s(a),{open(){s({...a,open:!0})},close(){s({...a,open:!1,status:"idle"})},dispose(){i!==null&&(clearTimeout(i),i=null),Ae(null,n),e.host.innerHTML=""},notifyIdentityChanged(){s({...a})}}}function He(e){var g,k,_,v,p,u;let t=(g=e.env)!=null?g:"prod",r=(k=e.locale)!=null?k:typeof navigator!="undefined"?navigator.language:void 0,n=Ze((_=e.translations)!=null?_:{},r!==void 0?{locale:r}:{}),a=Xe({...e.sanitizeUrl!==void 0&&{sanitizeUrl:e.sanitizeUrl}}),i=e.user,s=(v=e.metadata)!=null?v:{},l=Ne({apiKey:e.apiKey,endpoint:e.endpoint,...e.fetchImpl!==void 0&&{fetch:e.fetchImpl},...e.beforeSend!==void 0&&{beforeSend:e.beforeSend},getSignedIdentity:()=>!i||!i.userHash||!i.exp||!i.email?null:{userHash:i.userHash,exp:i.exp,email:i.email}}),f=[],c=document.createElement("div");if(c.className="mhosaic-feedback",e.attachTo){let m=typeof e.attachTo=="string"?document.querySelector(e.attachTo):e.attachTo;m==null||m.appendChild(c)}else document.body.appendChild(c);async function b(m){var P,K,B,O,N;let x=m.synthetic?void 0:m.screenshot,R=a.snapshot();if(i){let{userHash:H,exp:Z,...ae}=i;R.user=ae}s&&Object.keys(s).length>0&&(R.metadata={...s});let L=x?(P=m.capture_method)!=null?P:"manual":"none",T={description:m.description,feedback_type:(K=m.feedback_type)!=null?K:"bug",severity:(B=m.severity)!=null?B:"medium",env:t,page_url:window.location.href,user_agent:navigator.userAgent,capture_method:L,technical_context:R};T.widget_version="0.
|
|
1693
|
+
`;function po(e,t,r){return!(!e.showFAB||e.getExternalId!==void 0&&!t||e.requiresVisibilityCheck&&!r)}function $t(e){let t=e.host.attachShadow({mode:"open"}),r=document.createElement("style");r.textContent=It,t.appendChild(r);let n=document.createElement("div");t.appendChild(n);let a={open:!1,status:"idle",tab:"send"},i=null;function s(c){a=c,Ae(Be(f,{state:c}),n)}function l(c){let{selectedReportId:b,...d}=c;return d}function f({state:c}){var v;let b=_t(async p=>{s({...a,status:"submitting"});try{await e.onSubmit(p),s({...a,status:"success"}),i!==null&&clearTimeout(i),i=setTimeout(()=>{i=null,s({...a,open:!1,status:"idle",tab:e.api?"mine":"send"})},1200)}catch(u){typeof console!="undefined"&&console.warn("[mhosaic] submit:",u),s({...a,status:"error",error:e.strings["form.error"]})}},[]),d=(v=e.getExternalId)==null?void 0:v.call(e),[y,g]=C(!e.requiresVisibilityCheck);D(()=>{if(!e.requiresVisibilityCheck){g(!0);return}if(!d||!e.checkVisibility){g(!1);return}let p=!1;return e.checkVisibility(d).then(u=>{p||g(u)}).catch(()=>{p||g(!1)}),()=>{p=!0}},[d]);let k=po(e,d,y),_=!!(e.api&&d);return o(U,{children:[k&&o(Et,{label:e.strings["fab.label"],onClick:()=>s({...a,open:!0})}),c.open&&o(At,{onDismiss:()=>s(l({...a,open:!1,status:"idle"})),closeLabel:e.strings["form.close"],expanded:c.tab==="board",children:[_&&o("div",{class:"tab-strip",role:"tablist",children:[o("button",{type:"button",role:"tab","aria-selected":c.tab==="send",class:`tab-button ${c.tab==="send"?"is-active":""}`,onClick:()=>s(l({...a,tab:"send"})),children:e.strings["tab.send"]}),o("button",{type:"button",role:"tab","aria-selected":c.tab==="mine",class:`tab-button ${c.tab==="mine"?"is-active":""}`,onClick:()=>s(l({...a,tab:"mine"})),children:e.strings["tab.mine"]}),o("button",{type:"button",role:"tab","aria-selected":c.tab==="changelog",class:`tab-button ${c.tab==="changelog"?"is-active":""}`,onClick:()=>s(l({...a,tab:"changelog"})),children:e.strings["tab.changelog"]}),o("button",{type:"button",role:"tab","aria-selected":c.tab==="board",class:`tab-button tab-button--board ${c.tab==="board"?"is-active":""}`,onClick:()=>s(l({...a,tab:"board"})),children:e.strings["tab.board"]})]}),c.tab==="send"&&o(zt,{strings:e.strings,onSubmit:b,onCancel:()=>s({...a,open:!1,status:"idle"}),status:c.status,...c.error!==void 0&&{errorMessage:c.error}}),c.tab==="mine"&&e.api&&d&&!c.selectedReportId&&o(Ft,{api:e.api,externalId:d,strings:e.strings,onSelect:p=>s({...a,selectedReportId:p.id})}),(c.tab==="mine"||c.tab==="changelog")&&e.api&&d&&c.selectedReportId&&o(ye,{api:e.api,externalId:d,reportId:c.selectedReportId,strings:e.strings,onBack:()=>s(l({...a}))}),c.tab==="changelog"&&e.api&&d&&!c.selectedReportId&&o(Rt,{api:e.api,externalId:d,strings:e.strings,onSelect:p=>s({...a,selectedReportId:p.id})}),c.tab==="board"&&e.api&&d&&o(Ct,{api:e.api,externalId:d,strings:e.strings})]})]})}return s(a),{open(){s({...a,open:!0})},close(){s({...a,open:!1,status:"idle"})},dispose(){i!==null&&(clearTimeout(i),i=null),Ae(null,n),e.host.innerHTML=""},notifyIdentityChanged(){s({...a})}}}function He(e){var g,k,_,v,p,u;let t=(g=e.env)!=null?g:"prod",r=(k=e.locale)!=null?k:typeof navigator!="undefined"?navigator.language:void 0,n=Ze((_=e.translations)!=null?_:{},r!==void 0?{locale:r}:{}),a=Xe({...e.sanitizeUrl!==void 0&&{sanitizeUrl:e.sanitizeUrl}}),i=e.user,s=(v=e.metadata)!=null?v:{},l=Ne({apiKey:e.apiKey,endpoint:e.endpoint,...e.fetchImpl!==void 0&&{fetch:e.fetchImpl},...e.beforeSend!==void 0&&{beforeSend:e.beforeSend},getSignedIdentity:()=>!i||!i.userHash||!i.exp||!i.email?null:{userHash:i.userHash,exp:i.exp,email:i.email}}),f=[],c=document.createElement("div");if(c.className="mhosaic-feedback",e.attachTo){let m=typeof e.attachTo=="string"?document.querySelector(e.attachTo):e.attachTo;m==null||m.appendChild(c)}else document.body.appendChild(c);async function b(m){var P,K,B,O,N;let x=m.synthetic?void 0:m.screenshot,R=a.snapshot();if(i){let{userHash:H,exp:Z,...ae}=i;R.user=ae}s&&Object.keys(s).length>0&&(R.metadata={...s});let L=x?(P=m.capture_method)!=null?P:"manual":"none",T={description:m.description,feedback_type:(K=m.feedback_type)!=null?K:"bug",severity:(B=m.severity)!=null?B:"medium",env:t,page_url:window.location.href,user_agent:navigator.userAgent,capture_method:L,technical_context:R};T.widget_version="0.18.1",x&&(T.screenshot=x),m.synthetic&&(T.synthetic=!0),(i==null?void 0:i.id)!==void 0&&i.id!==null&&i.id!==""&&(T.user={id:String(i.id),...i.email!==void 0&&{email:i.email},...i.name!==void 0&&{name:i.name}});let F=T;for(let H of f)F=await H(F);try{let H=await l.submitReport(F);return(O=e.onSubmitSuccess)==null||O.call(e,H),a.clear(),H}catch(H){let Z=H instanceof Error?H:new Error(String(H));throw(N=e.onError)==null||N.call(e,Z),Z}}let d=$t({host:c,strings:n,showFAB:(p=e.showFAB)!=null?p:!0,onSubmit:async m=>{await b(m)},api:l,getExternalId:()=>(i==null?void 0:i.id)!==void 0&&i.id!==null&&i.id!==""?String(i.id):void 0,requiresVisibilityCheck:(u=e.requiresVisibilityCheck)!=null?u:!1,checkVisibility:m=>l.checkVisibility(m,i==null?void 0:i.email)}),y={show(){d.open()},hide(){d.close()},open(m){d.open()},async submit(m){return b({description:m.description,...m.feedback_type!==void 0&&{feedback_type:m.feedback_type},...m.severity!==void 0&&{severity:m.severity},...m.synthetic!==void 0&&{synthetic:m.synthetic},...m.screenshot!==void 0&&{screenshot:m.screenshot}})},identify(m){i=m,d.notifyIdentityChanged()},setMetadata(m){s={...s,...m}},shutdown(){d.dispose(),a.dispose(),c.remove();let m=window;m.mhosaicFeedback===y&&delete m.mhosaicFeedback},_registerTransformer(m){f.push(m)}};return window.mhosaicFeedback=y,y}var Ht=window;function uo(){let e=document.currentScript;if(!e)return null;let t=e.dataset.key,r=e.dataset.endpoint;if(!t||!r)return null;let n=e.dataset.env;return{apiKey:t,endpoint:r,...n!==void 0&&{env:n}}}var Q=null,Kt,Wt,we=(Wt=(Kt=Ht.Feedback)==null?void 0:Kt.q)!=null?Wt:[];function Nt(e){let[t,r]=e;if(t==="init"){if(Q)return;Q=He(r);return}if(!Q){we.push(e);return}t==="identify"?Q.identify(r):t==="setMetadata"?Q.setMetadata(r):t==="open"&&Q.open(r)}var Dt=uo();Dt&&(Q=He(Dt));for(;we.length>0;)Nt(we.shift());var fo=Object.assign(function(t,r){Nt([t,r])},{q:we});Ht.Feedback=fo;})();
|
|
1694
1694
|
//# sourceMappingURL=embed.min.js.map
|