@usero/sdk 1.1.1 → 1.1.3
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/plugins/session-replay.cjs +2 -1
- package/dist/plugins/session-replay.cjs.map +1 -1
- package/dist/plugins/session-replay.d.cts +5 -0
- package/dist/plugins/session-replay.d.ts +5 -0
- package/dist/plugins/session-replay.js +2 -1
- package/dist/plugins/session-replay.js.map +1 -1
- package/dist/plugins/user-test.cjs +18 -3
- package/dist/plugins/user-test.cjs.map +1 -1
- package/dist/plugins/user-test.d.cts +5 -0
- package/dist/plugins/user-test.d.ts +5 -0
- package/dist/plugins/user-test.js +18 -3
- package/dist/plugins/user-test.js.map +1 -1
- package/dist/react.cjs +122 -34
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +5 -0
- package/dist/react.d.ts +5 -0
- package/dist/react.js +122 -34
- package/dist/react.js.map +1 -1
- package/dist/usero.iife.js +35 -35
- package/dist/usero.iife.js.map +1 -1
- package/dist/vanilla.cjs +122 -34
- package/dist/vanilla.cjs.map +1 -1
- package/dist/vanilla.d.cts +5 -0
- package/dist/vanilla.d.ts +5 -0
- package/dist/vanilla.js +122 -34
- package/dist/vanilla.js.map +1 -1
- package/package.json +1 -1
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/api.ts","../src/colorUtils.ts","../src/identity.ts","../src/plugin.ts","../src/validation.ts","../src/widgetCss.ts","../src/vanilla.ts","../src/react.tsx"],"names":[],"mappings":"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;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAA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","file":"react.js","sourcesContent":["// Shared types used by both the vanilla and React entry points.\n// Keep this file framework-free so the vanilla bundle never pulls react.\n\nexport type FeedbackRating = 1 | 2 | 3 | 4\n\nexport interface FeedbackMetadata {\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\ttimestamp: number\n}\n\nexport interface ScreenshotData {\n\tfileName: string\n\turl: string\n\tfileSize: number\n\twidth?: number\n\theight?: number\n\tmimeType: string\n}\n\nexport interface FeedbackSubmission {\n\tclientId: string\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\tenvironment?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata?: Record<string, unknown>\n\t// Legacy gzipped + base64-encoded rrweb event stream. The pre-chunked\n\t// session-replay plugin attached this on submit. The chunked-upload\n\t// plugin (>= 0.4.0) does NOT set this — it ships events out-of-band\n\t// via the chunk endpoints and points at the resulting session replay\n\t// via `sessionReplayId` + `replayOffsetMs`. Kept on the wire one\n\t// release for backward compat with old SaaS deployments that only\n\t// know how to ingest the legacy field.\n\treplayEvents?: string\n\t// Pointer to a SessionReplay row created by the session-replay\n\t// plugin's chunked-upload pipeline, plus the offset within that\n\t// recording at submit time so the dashboard can deep-link.\n\tsessionReplayId?: string\n\treplayOffsetMs?: number\n}\n\nexport interface FeedbackData {\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata: FeedbackMetadata\n}\n\n// Customer-supplied identity for the session-replay / identify pipeline.\n// Use the declarative form: pass `user` on the React widget (the SDK\n// diffs and auto-fires identify), or supply `getUser` on the vanilla\n// init (the SDK polls it at session start). An imperative `identify()`\n// call exists as an escape hatch only and is intentionally not\n// documented as the headline API.\nexport type UseroUserTraitValue = string | number | boolean | null\nexport type UseroUserTraits = Record<string, UseroUserTraitValue>\nexport interface UseroUser {\n\tid: string\n\temail?: string\n\tdisplayName?: string\n\ttraits?: UseroUserTraits\n}\n\nexport type WidgetPosition = 'right' | 'left'\n\nexport interface WidgetTheme {\n\tprimary: string\n\tbackground: string\n\ttext: string\n\tborder: string\n\tshadow: string\n}\n\n// Forward-declared to avoid a circular import. The plugin module imports\n// FeedbackSubmission from this file, so we can't import UseroPlugin back\n// up here without a cycle. Keeping the prop typed as an opaque object with\n// the minimal shape the widget actually inspects works fine for consumers.\nexport interface FeedbackWidgetProps {\n\tclientId: string\n\tposition?: WidgetPosition\n\ttheme?: Partial<WidgetTheme>\n\ttitle?: string\n\tplaceholder?: string\n\tshowEmailOption?: boolean\n\tshowScreenshotOption?: boolean\n\tenvironment?: string\n\tbaseUrl?: string\n\tmetadata?: Record<string, unknown>\n\tplugins?: ReadonlyArray<import('./plugin').UseroPlugin>\n\t// Declarative identity. React: pass the current user (or null on\n\t// logout) and the SDK auto-fires identify when the resolved id\n\t// transitions. Vanilla: pass a getter so the SDK can resolve user at\n\t// session start / chunk boundaries. Pass at most one. The SDK never\n\t// invokes both.\n\tuser?: UseroUser | null\n\tgetUser?: () => UseroUser | null | undefined\n\tonSubmit?: (feedback: FeedbackData) => void\n\tonError?: (error: Error) => void\n\tonOpen?: () => void\n\tonClose?: () => void\n}\n\nexport interface SubmissionResponse {\n\tsuccess: boolean\n\terror?: string\n\tid?: string\n\tmessage?: string\n\tdata?: unknown\n}\n\nexport const EMOJI_MAP: Record<FeedbackRating, string> = {\n\t1: '😞',\n\t2: '😐',\n\t3: '😊',\n\t4: '🤩',\n}\n\nexport const RATING_LABELS: Record<FeedbackRating, string> = {\n\t1: 'Needs work',\n\t2: \"It's okay\",\n\t3: 'Pretty good',\n\t4: 'Amazing!',\n}\n\nexport const EMOJI_BACKGROUNDS: Record<FeedbackRating, string> = {\n\t1: 'linear-gradient(135deg,#ff6b6b14,#ff6b6b1f)',\n\t2: 'linear-gradient(135deg,#9ca3af0f,#9ca3af1a)',\n\t3: 'linear-gradient(135deg,#3b82f614,#3b82f61f)',\n\t4: 'linear-gradient(135deg,#f59e0b14,#f59e0b1f)',\n}\n\nexport const DEFAULT_API_URL = 'https://usero.io'\n\nexport const DEFAULT_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#ffffff',\n\ttext: '#374151',\n\tborder: '#e5e7eb',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',\n}\n\nexport const DARK_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#1f2937',\n\ttext: '#f9fafb',\n\tborder: '#374151',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2)',\n}\n\nexport function mergeTheme(customTheme: Partial<WidgetTheme> = {}): WidgetTheme {\n\treturn { ...DEFAULT_THEME, ...customTheme }\n}\n","import {\n\tDEFAULT_API_URL,\n\ttype FeedbackSubmission,\n\ttype ScreenshotData,\n\ttype SubmissionResponse,\n} from './types'\n\ninterface JsonErrorBody {\n\terror?: string\n}\n\nfunction isJsonErrorBody(value: unknown): value is JsonErrorBody {\n\treturn typeof value === 'object' && value !== null && 'error' in value\n}\n\ninterface ScreenshotUploadResponseBody {\n\tsuccess: boolean\n\terror?: string\n\tscreenshot?: ScreenshotData\n}\n\nfunction parseScreenshotUploadBody(\n\tvalue: unknown,\n): ScreenshotUploadResponseBody {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn { success: false, error: 'Invalid response' }\n\t}\n\tconst obj = value as Record<string, unknown>\n\tconst success = obj.success === true\n\tconst error = typeof obj.error === 'string' ? obj.error : undefined\n\tconst rawShot = obj.screenshot\n\tlet screenshot: ScreenshotData | undefined\n\tif (typeof rawShot === 'object' && rawShot !== null) {\n\t\tconst s = rawShot as Record<string, unknown>\n\t\tif (\n\t\t\ttypeof s.fileName === 'string' &&\n\t\t\ttypeof s.url === 'string' &&\n\t\t\ttypeof s.fileSize === 'number' &&\n\t\t\ttypeof s.mimeType === 'string'\n\t\t) {\n\t\t\tscreenshot = {\n\t\t\t\tfileName: s.fileName,\n\t\t\t\turl: s.url,\n\t\t\t\tfileSize: s.fileSize,\n\t\t\t\tmimeType: s.mimeType,\n\t\t\t\twidth: typeof s.width === 'number' ? s.width : undefined,\n\t\t\t\theight: typeof s.height === 'number' ? s.height : undefined,\n\t\t\t}\n\t\t}\n\t}\n\treturn { success, error, screenshot }\n}\n\nexport class FeedbackApiClient {\n\tprivate baseUrl: string\n\n\tconstructor(baseUrl: string = DEFAULT_API_URL) {\n\t\tthis.baseUrl = baseUrl.replace(/\\/$/, '')\n\t}\n\n\tasync submitFeedback(data: FeedbackSubmission): Promise<SubmissionResponse> {\n\t\ttry {\n\t\t\tconst response = await fetch(`${this.baseUrl}/api/feedback`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(data),\n\t\t\t\tsignal: AbortSignal.timeout(10000),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `HTTP ${response.status}: ${response.statusText}`\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData: unknown = await response.json()\n\t\t\t\t\tif (isJsonErrorBody(errorData) && typeof errorData.error === 'string') {\n\t\t\t\t\t\terrorMessage = errorData.error\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore JSON parse errors\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage)\n\t\t\t}\n\n\t\t\tconst result: unknown = await response.json()\n\t\t\tconst message =\n\t\t\t\ttypeof result === 'object' &&\n\t\t\t\tresult !== null &&\n\t\t\t\t'message' in result &&\n\t\t\t\ttypeof (result as { message: unknown }).message === 'string'\n\t\t\t\t\t? (result as { message: string }).message\n\t\t\t\t\t: 'Feedback submitted successfully'\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: result,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\terror instanceof Error ? error.message : 'An unexpected error occurred',\n\t\t\t}\n\t\t}\n\t}\n\n\tasync uploadScreenshot(\n\t\tfile: File,\n\t\tclientId: string,\n\t): Promise<ScreenshotData> {\n\t\tconst formData = new FormData()\n\t\tformData.append('screenshot', file)\n\t\tformData.append('clientId', clientId)\n\n\t\tconst response = await fetch(`${this.baseUrl}/api/screenshots`, {\n\t\t\tmethod: 'POST',\n\t\t\tbody: formData,\n\t\t\tsignal: AbortSignal.timeout(30000),\n\t\t})\n\n\t\tlet body: ScreenshotUploadResponseBody = { success: false }\n\t\ttry {\n\t\t\tconst raw: unknown = await response.json()\n\t\t\tbody = parseScreenshotUploadBody(raw)\n\t\t} catch {\n\t\t\t// fall through to error handling below\n\t\t}\n\n\t\tif (!response.ok || !body.success || !body.screenshot) {\n\t\t\tconst message =\n\t\t\t\tbody.error ?? `HTTP ${response.status}: ${response.statusText}`\n\t\t\tthrow new Error(message)\n\t\t}\n\n\t\treturn body.screenshot\n\t}\n\n\tping(): void {\n\t\tfetch(`${this.baseUrl}/api/ping`, {\n\t\t\tsignal: AbortSignal.timeout(5000),\n\t\t}).catch(() => {})\n\t}\n}\n","export function colorNameToHex(color: string): string {\n\tif (color.startsWith('#')) return color\n\tif (typeof document === 'undefined') return color\n\n\tconst canvas = document.createElement('canvas')\n\tconst ctx = canvas.getContext('2d')\n\tif (!ctx) return color\n\n\tctx.fillStyle = color\n\treturn ctx.fillStyle\n}\n\nexport function getGradientEnd(color: string): string {\n\tconst hex = colorNameToHex(color)\n\tif (!hex.startsWith('#') || hex.length < 7) return hex\n\tconst r = parseInt(hex.slice(1, 3), 16)\n\tconst g = parseInt(hex.slice(3, 5), 16)\n\tconst b = parseInt(hex.slice(5, 7), 16)\n\tconst shiftedR = Math.max(0, r - 60)\n\tconst shiftedG = Math.min(255, g + 40)\n\tconst shiftedB = Math.min(255, b + 20)\n\treturn `#${[shiftedR, shiftedG, shiftedB]\n\t\t.map(x => x.toString(16).padStart(2, '0'))\n\t\t.join('')}`\n}\n","// Identity layer for the Usero SDK.\n//\n// Two responsibilities:\n// 1. Mint and persist a stable per-browser `anonymousId` in localStorage\n// so cross-tab + cross-day replays from the same browser stitch\n// together server-side. Falls back to an in-memory id if storage is\n// blocked (sandboxed iframes, Safari Lockdown, full quota). Replay\n// still works in that case, you just lose stitching.\n// 2. Auto-fire POST /api/identify when the resolved user transitions\n// (null -> id, id -> id'). Deduped by an in-memory fingerprint so\n// re-renders with the same user are no-ops on the network.\n//\n// All storage access is wrapped in try/catch and gated behind a one-shot\n// init read. The hot path (replay chunk flush) never touches localStorage.\n\nconst ANON_STORAGE_KEY = 'usero:anonymous-id'\n\nlet cachedAnonymousId: string | null = null\n// Fingerprint of the last identify we POSTed. Same SDK instance + same\n// resolved user + same traits = no-op. Cleared on logout (anonymousId\n// rotation).\nlet lastIdentifyFingerprint: string | null = null\n\nexport type UserTraitValue = string | number | boolean | null\nexport type UserTraits = Record<string, UserTraitValue>\n\nexport interface UseroUser {\n\tid: string\n\temail?: string\n\tdisplayName?: string\n\ttraits?: UserTraits\n}\n\nfunction generateRandomId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn crypto.randomUUID()\n\t}\n\tconst bytes = new Uint8Array(16)\n\tif (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n\t\tcrypto.getRandomValues(bytes)\n\t} else {\n\t\tfor (let i = 0; i < bytes.length; i += 1) bytes[i] = Math.floor(Math.random() * 256)\n\t}\n\tlet out = ''\n\tfor (const b of bytes) out += b.toString(16).padStart(2, '0')\n\treturn out\n}\n\nfunction safeReadLocalStorage(key: string): string | null {\n\tif (typeof window === 'undefined') return null\n\ttry {\n\t\treturn window.localStorage?.getItem(key) ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction safeWriteLocalStorage(key: string, value: string): void {\n\tif (typeof window === 'undefined') return\n\ttry {\n\t\twindow.localStorage?.setItem(key, value)\n\t} catch {\n\t\t// Sandboxed iframe / Safari Lockdown / quota. Fall back to memory.\n\t}\n}\n\n/**\n * Returns the stable per-browser anonymousId. Reads localStorage at most\n * once per SDK instance. Subsequent calls hit the in-memory cache, so\n * even hot paths (per-event in replay) are safe to call this.\n */\nexport function getOrMintAnonymousId(): string {\n\tif (cachedAnonymousId) return cachedAnonymousId\n\tconst existing = safeReadLocalStorage(ANON_STORAGE_KEY)\n\t// Sanity filter, not strict validation. We accept anything that looks\n\t// plausibly like an id (>=8 alphanumeric-or-hyphen) so older SDK\n\t// versions that wrote a slightly different shape still stitch. Fresh\n\t// mint is cheap, so we only reject obvious garbage; tightening this\n\t// would force rotation in customer browsers and split otherwise-good\n\t// sibling-session attribution.\n\tif (existing && /^[a-z0-9-]{8,}$/i.test(existing)) {\n\t\tcachedAnonymousId = existing\n\t\treturn existing\n\t}\n\tconst id = generateRandomId()\n\tsafeWriteLocalStorage(ANON_STORAGE_KEY, id)\n\tcachedAnonymousId = id\n\treturn id\n}\n\n/**\n * Rotate the anonymousId. Called on logout (user transitions from a\n * known id to null) so the next anonymous trail does not get auto-merged\n * into the previous person on the next identify().\n */\nexport function rotateAnonymousId(): string {\n\tconst id = generateRandomId()\n\tcachedAnonymousId = id\n\tsafeWriteLocalStorage(ANON_STORAGE_KEY, id)\n\tlastIdentifyFingerprint = null\n\treturn id\n}\n\nfunction fingerprintUser(anonymousId: string, user: UseroUser): string {\n\t// Stable across re-renders: keys sorted, traits canonicalised. Cheap\n\t// enough on the hot path (only runs when the SDK thinks the user might\n\t// have changed, never per-event).\n\tconst traits = user.traits ?? {}\n\tconst keys = Object.keys(traits).sort()\n\tconst canonical: Array<[string, UserTraitValue]> = keys.map(k => [k, traits[k] ?? null])\n\treturn JSON.stringify([anonymousId, user.id, user.email ?? null, user.displayName ?? null, canonical])\n}\n\nexport interface IdentifyTransport {\n\tapiUrl: string\n\tclientId: string\n}\n\n/**\n * POST to /api/identify if the (anonymousId, user) fingerprint differs\n * from the last call. Returns true if a network request actually fired.\n * Never throws; failures are best-effort and the caller (the widget /\n * provider) should not treat them as errors.\n *\n * Tab-unload safety: if the page is hidden when this fires (visibility\n * 'hidden' or a pagehide handler), we route the payload through\n * `navigator.sendBeacon` so the request survives unload. Otherwise we\n * use a normal fetch and only cache the fingerprint when the server\n * confirms `accepted: true`. A 200 `{ accepted: false }` (e.g.\n * `unknown_client` for a clientId that becomes valid mid-session) is\n * treated as retryable so the next call re-fires.\n */\nexport async function identifyIfChanged(transport: IdentifyTransport, user: UseroUser): Promise<boolean> {\n\tconst anonymousId = getOrMintAnonymousId()\n\tconst fp = fingerprintUser(anonymousId, user)\n\tif (fp === lastIdentifyFingerprint) return false\n\n\tconst url = `${transport.apiUrl.replace(/\\/$/, '')}/api/identify`\n\t// Body must stay under the browser's keepalive / sendBeacon cap\n\t// (~64KB across most engines) when this fires on pagehide. That\n\t// transitively caps trait payload size; in practice traits should be\n\t// small typed scalars, not blobs.\n\tconst body = JSON.stringify({\n\t\tclientId: transport.clientId,\n\t\tanonymousId,\n\t\texternalUserId: user.id,\n\t\temail: user.email,\n\t\tdisplayName: user.displayName,\n\t\ttraits: user.traits,\n\t})\n\n\t// If the document is hidden (pagehide / tab close in flight), best-effort\n\t// hand off to sendBeacon. We don't get a response back, so we optimistically\n\t// cache the fingerprint to avoid re-firing on the next page; the server is\n\t// idempotent if the page reload re-runs identify with the same payload.\n\tif (\n\t\ttypeof document !== 'undefined' &&\n\t\tdocument.visibilityState === 'hidden' &&\n\t\ttypeof navigator !== 'undefined' &&\n\t\ttypeof navigator.sendBeacon === 'function'\n\t) {\n\t\ttry {\n\t\t\tconst blob = new Blob([body], { type: 'application/json' })\n\t\t\t// sendBeacon returns false when the user agent refuses to queue\n\t\t\t// the request (size cap, or historically Safari rejecting\n\t\t\t// non-CORS-simple content types). Modern Safari accepts\n\t\t\t// application/json, but we keep a keepalive-fetch fallback so an\n\t\t\t// older WebKit that rejects the beacon still ships the identify.\n\t\t\tif (navigator.sendBeacon(url, blob)) {\n\t\t\t\tlastIdentifyFingerprint = fp\n\t\t\t\treturn true\n\t\t\t}\n\t\t} catch {\n\t\t\t// fall through to keepalive fetch below\n\t\t}\n\t}\n\n\ttry {\n\t\tconst res = await fetch(url, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody,\n\t\t\t// keepalive lets the request survive a tab-close mid-flight on\n\t\t\t// browsers that support it; sendBeacon above is the primary path.\n\t\t\tkeepalive: true,\n\t\t})\n\t\tif (!res.ok) return true\n\t\t// Parse the response: a 200 with `accepted: false` (e.g. unknown\n\t\t// client) is retryable. Only cache the fingerprint when the server\n\t\t// confirmed it actually stored the identity.\n\t\ttry {\n\t\t\tconst json = (await res.json()) as { accepted?: unknown }\n\t\t\tif (json && json.accepted === true) lastIdentifyFingerprint = fp\n\t\t} catch {\n\t\t\t// Server returned 2xx but unparseable body: don't cache, let the\n\t\t\t// next call retry.\n\t\t}\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Clear identify state and rotate anonymousId. Called when the resolved\n * user transitions from a known id to null (logout). The next anonymous\n * trail will get a fresh anonymousId so it does not merge into the\n * previous person.\n */\nexport function handleLogout(): void {\n\trotateAnonymousId()\n}\n\n// Test hooks (not exported from the package public surface).\nexport const __test__ = {\n\tANON_STORAGE_KEY,\n\tresetIdentityState: (): void => {\n\t\tcachedAnonymousId = null\n\t\tlastIdentifyFingerprint = null\n\t},\n}\n","// Plugin contract for the Usero widget.\n//\n// Plugins are opt-in modules that hook into the widget lifecycle to enrich\n// feedback submissions or react to widget events. They live in subpath\n// exports (e.g. `@usero/sdk/plugins/session-replay`) so consumers who don't\n// import them pay zero bundle cost.\n//\n// Design rules:\n// 1. The plugin contract MUST stay framework-free (no React types).\n// 2. `onInit` runs fire-and-forget so a slow plugin never blocks the\n// widget from rendering. Plugins that need to be ready before the\n// first interaction are responsible for their own gating internally.\n// 3. `onFeedbackSubmit` is awaited and its return value is merged into\n// the outgoing payload. Top-level keys are shallow-merged (later\n// plugins win wholesale); `metadata` is deep-merged one level so two\n// plugins can both contribute keys without clobbering each other.\n// Plugins MUST return quickly (a few hundred ms at most) or risk users\n// abandoning the submit.\n// 4. Plugin errors are caught and logged; they never block a submission.\n\nimport type { FeedbackSubmission } from './types'\n\nexport interface PluginLogger {\n\tdebug: (...args: unknown[]) => void\n\tinfo: (...args: unknown[]) => void\n\twarn: (...args: unknown[]) => void\n\terror: (...args: unknown[]) => void\n}\n\nexport interface PluginContext {\n\tclientId: string\n\tbaseUrl: string\n\t// Per-plugin scratch store. Plugins can stash state across hook calls\n\t// without leaking into globals. The key is the plugin's `name`.\n\tgetStore: <T>() => T | undefined\n\tsetStore: <T>(value: T) => void\n\tlogger: PluginLogger\n\t// Re-resolve the current user via the host's `user` prop or `getUser`\n\t// callback and run it through the identify dedupe pipeline. Plugins\n\t// that run independently of widget interaction (e.g. session-replay\n\t// for replay-only customers who never open the widget) should call\n\t// this at their own boundaries (session start, chunk flush, etc.)\n\t// so mid-session login is visible server-side. The fingerprint\n\t// dedupe in identity.ts makes repeated calls effectively free when\n\t// nothing changed.\n\tresolveUser?: () => void\n}\n\nexport interface UseroPlugin {\n\t// Stable, unique identifier. Used as the store key and in log prefixes.\n\t// Convention: lowercase kebab-case (e.g. `session-replay`).\n\tname: string\n\tonInit?: (ctx: PluginContext) => void | Promise<void>\n\t// Returns a partial submission patch that gets merged into the outgoing\n\t// payload. Top-level keys are shallow-merged (later plugins win on\n\t// conflict); `metadata` is deep-merged one level so multiple plugins\n\t// can each attach their own metadata keys without clobbering. Return\n\t// `undefined` to contribute nothing.\n\tonFeedbackSubmit?: (\n\t\tctx: PluginContext,\n\t\tsubmission: FeedbackSubmission,\n\t) => Promise<Partial<FeedbackSubmission> | undefined> | Partial<FeedbackSubmission> | undefined\n\tonDestroy?: (ctx: PluginContext) => void\n}\n\nexport function createPluginLogger(name: string): PluginLogger {\n\tconst prefix = `[usero:${name}]`\n\treturn {\n\t\tdebug: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.debug(prefix, ...args)\n\t\t},\n\t\tinfo: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.info(prefix, ...args)\n\t\t},\n\t\twarn: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.warn(prefix, ...args)\n\t\t},\n\t\terror: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.error(prefix, ...args)\n\t\t},\n\t}\n}\n","import type { FeedbackSubmission } from './types'\n\nexport interface ValidationResult {\n\tisValid: boolean\n\terrors: string[]\n}\n\nexport function validateFeedbackSubmission(\n\tdata: Partial<FeedbackSubmission>,\n): ValidationResult {\n\tconst errors: string[] = []\n\tconst hasRating = data.rating != null\n\tconst hasComment = !!data.comment?.trim()\n\n\tif (!hasRating && !hasComment) {\n\t\terrors.push('Add rating or comment')\n\t}\n\tif (hasRating && data.rating !== undefined && ![1, 2, 3, 4].includes(data.rating)) {\n\t\terrors.push('Invalid rating')\n\t}\n\tif (hasComment && data.comment !== undefined) {\n\t\tif (data.comment.length > 1000) {\n\t\t\terrors.push('Comment too long')\n\t\t}\n\t\tif (/<script[^>]*>.*?<\\/script>/gi.test(data.comment)) {\n\t\t\terrors.push('Invalid comment')\n\t\t}\n\t}\n\n\treturn {\n\t\tisValid: errors.length === 0,\n\t\terrors,\n\t}\n}\n","// CSS used by both entry points.\n//\n// React entry injects it once into <head> via injectFeedbackCSS().\n// Vanilla entry injects it inside a shadow root, so host page styles\n// can't bleed in and our class names can't collide with the host.\n\nexport const FEEDBACK_CSS = `\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.fb-es {\n display: flex;\n justify-content: center;\n gap: 12px;\n padding-bottom: 8px;\n}\n\n.fb-ec {\n border-radius: 16px;\n padding: 0 5px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n border: 3px solid transparent;\n cursor: pointer;\n text-align: center;\n}\n\n.fb-ec--sel {\n border-color: #2563eb;\n transform: scale(1.05);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.2);\n}\n\n.fb-ec--hov:not(.fb-ec--sel) {\n transform: scale(1.05);\n}\n\n.fb-eb {\n background: transparent;\n border: none;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n width: 100%;\n padding: 0;\n transition: all 200ms ease;\n}\n\n.fb-ei {\n font-size: 36px;\n transition: transform 200ms ease;\n}\n\n.fb-ei--hov {\n transform: scale(1.1);\n}\n\n.fb-el {\n font-size: 13px;\n font-weight: 600;\n color: currentColor;\n line-height: 1.2;\n}\n\n.fb-hdr {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 4px;\n margin-bottom: 10px;\n}\n\n.fb-msg {\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n margin-bottom: 8px;\n border-radius: 6px;\n}\n\n.fb-msg--header {\n font-size: 12px;\n padding: 4px 8px;\n margin-bottom: 0;\n margin-left: auto;\n margin-right: 8px;\n}\n\n.fb-msg--ok {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n color: #16a34a;\n}\n\n.fb-msg--err {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n color: #dc2626;\n}\n\n.fb-sub {\n width: 100%;\n padding: 12px 24px;\n border: none;\n border-radius: 12px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n transition: all 200ms ease;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.fb-sub--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-spin {\n width: 16px;\n height: 16px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n.fb-cnt {\n padding: 20px 24px 16px;\n overflow: auto;\n max-height: calc(90vh - 48px);\n}\n\n.fb-ttl {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n}\n\n.fb-ta {\n width: 100%;\n min-height: 80px;\n padding: 10px;\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n resize: vertical;\n transition: border-color 150ms ease;\n margin-bottom: 2px;\n box-sizing: border-box;\n}\n\n.fb-toolrow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n.fb-charcount {\n font-size: 12px;\n margin-left: auto;\n text-align: right;\n}\n\n.fb-charcount--low {\n color: #dc2626;\n}\n\n.fb-email {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 10px;\n}\n\n.fb-email-lbl {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n}\n\n.fb-email-cb {\n margin: 0;\n cursor: pointer;\n}\n\n.fb-email-inp {\n width: 100%;\n padding: 8px 12px;\n border-radius: 4px;\n font-size: 14px;\n outline: none;\n transition: border-color 150ms ease;\n box-sizing: border-box;\n}\n\n.fb-btn {\n position: fixed;\n width: 50px;\n height: 50px;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n z-index: 9998;\n color: #ffffff;\n top: 50%;\n transform: translateY(-50%);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-btn--right {\n right: -25px;\n border-radius: 40px 0 0 40px;\n padding-right: 8px;\n box-shadow: -4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--left {\n left: -25px;\n border-radius: 0 40px 40px 0;\n padding-left: 8px;\n box-shadow: 4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--right.fb-btn--open {\n right: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-btn--left.fb-btn--open {\n left: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.3);\n transition: opacity 300ms ease;\n z-index: 9999;\n backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl-base {\n position: fixed;\n top: 10vh;\n width: 400px;\n max-width: 90vw;\n max-height: 60vh;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n transition: transform 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: 16px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl--right { right: 0; }\n.fb-pnl--right.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--right.fb-pnl--closed { transform: translateX(100%); }\n\n.fb-pnl--left { left: 0; }\n.fb-pnl--left.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--left.fb-pnl--closed { transform: translateX(-100%); }\n\n.fb-close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n opacity: 0.7;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: background-color 150ms ease;\n}\n\n.fb-up {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 8px;\n}\n\n.fb-upb {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n align-self: flex-start;\n padding: 8px 12px;\n border-radius: 8px;\n background: transparent;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 150ms ease, opacity 150ms ease;\n font-family: inherit;\n}\n\n.fb-upb:hover:not(.fb-upb--dis) {\n background-color: rgba(37, 99, 235, 0.06);\n}\n\n.fb-upb--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-ups {\n width: 12px;\n height: 12px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n display: inline-block;\n}\n\n.fb-up-extras {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.fb-upe {\n font-size: 12px;\n color: #dc2626;\n}\n\n.fb-ss {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.fb-sp {\n position: relative;\n width: 64px;\n height: 64px;\n border-radius: 6px;\n overflow: hidden;\n border: 1px solid rgba(0, 0, 0, 0.08);\n}\n\n.fb-si {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.fb-sr {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: rgba(0, 0, 0, 0.65);\n color: #fff;\n font-size: 11px;\n line-height: 1;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n}\n\n.fb-sr:hover {\n background: rgba(0, 0, 0, 0.85);\n}\n\n.fb-sl {\n font-size: 11px;\n opacity: 0.6;\n}\n\n@media (max-width: 768px) {\n .fb-pnl-base {\n width: 100% !important;\n max-width: none !important;\n top: 4vh !important;\n max-height: 92vh !important;\n }\n .fb-cnt { padding: 16px 18px 14px !important; max-height: calc(100vh - 40px) !important; }\n .fb-ta { font-size: 16px !important; min-height: 64px !important; }\n .fb-ttl { font-size: 18px !important; }\n .fb-ei { font-size: 24px !important; }\n .fb-el { font-size: 11px !important; }\n .fb-sub { padding: 12px 20px !important; font-size: 16px !important; }\n}\n`\n\nexport function injectFeedbackCSS(): void {\n\tif (typeof document === 'undefined') return\n\tconst styleId = 'usero-feedback-widget-css'\n\tif (document.getElementById(styleId)) return\n\tconst style = document.createElement('style')\n\tstyle.id = styleId\n\tstyle.textContent = FEEDBACK_CSS\n\tdocument.head.appendChild(style)\n}\n","// Framework-free Usero widget. Renders into a shadow root attached to a\n// container <div> on document.body so host page styles cannot bleed in\n// and our class names cannot collide with the host's.\n//\n// API:\n// const widget = initUseroFeedbackWidget({ clientId: '...' })\n// widget.destroy()\n//\n// The endpoint and request shape match the React widget exactly so a\n// feedback row created here is indistinguishable from one created via React.\n\nimport { FeedbackApiClient } from './api'\nimport { getGradientEnd } from './colorUtils'\nimport { handleLogout as identityHandleLogout, identifyIfChanged } from './identity'\nimport {\n\tcreatePluginLogger,\n\ttype PluginContext,\n\ttype UseroPlugin,\n} from './plugin'\nimport { DEFAULT_API_URL, type UseroUser } from './types'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tEMOJI_BACKGROUNDS,\n\tEMOJI_MAP,\n\ttype FeedbackData,\n\ttype FeedbackRating,\n\ttype FeedbackSubmission,\n\ttype FeedbackWidgetProps,\n\tmergeTheme,\n\tRATING_LABELS,\n\ttype ScreenshotData,\n\ttype WidgetPosition,\n\ttype WidgetTheme,\n} from './types'\nimport { validateFeedbackSubmission } from './validation'\nimport { FEEDBACK_CSS } from './widgetCss'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\n\n// Pick the base theme to merge user overrides onto, based on the OS color\n// scheme. Defaults to dark when matchMedia is unavailable (SSR, old browsers)\n// or when neither dark nor light is explicitly preferred.\nfunction resolveBaseTheme(): WidgetTheme {\n\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n\t\treturn DARK_THEME\n\t}\n\tif (window.matchMedia('(prefers-color-scheme: dark)').matches) return DARK_THEME\n\tif (window.matchMedia('(prefers-color-scheme: light)').matches) return DEFAULT_THEME\n\treturn DARK_THEME\n}\n\n// Resolve the effective theme. If the caller passed a partial theme, it wins\n// per-key over the OS-resolved base. If they passed nothing, we just use the\n// OS-resolved base directly.\nexport function resolveTheme(userTheme: Partial<WidgetTheme> | undefined): WidgetTheme {\n\tconst base = resolveBaseTheme()\n\tif (!userTheme) return base\n\treturn { ...base, ...userTheme }\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type {\n\tPluginContext,\n\tPluginLogger,\n\tUseroPlugin,\n} from './plugin'\n\nexport interface UseroWidgetHandle {\n\tdestroy: () => void\n\topen: () => void\n\tclose: () => void\n\t// Hot-swap any subset of props EXCEPT `clientId` and `baseUrl`. Changing\n\t// those requires destroy + re-init (the API client is bound to baseUrl,\n\t// and clientId is the identity of the widget). Callers (e.g. the React\n\t// wrapper) typically route callbacks through this so identity changes on\n\t// re-render don't force a tear-down.\n\tupdate: (next: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>>) => void\n\t// Imperative identify(). Documented as a fallback for setups that\n\t// cannot expose user state via the declarative `user` prop or\n\t// `getUser` getter. Internally just routes through the same dedupe\n\t// pipeline as the declarative path.\n\tidentify: (user: UseroUser | null) => void\n\t// Resolves once every plugin's `onInit` promise has settled (fulfilled\n\t// OR rejected). Intended for end-to-end tests and dogfooding scripts\n\t// that want to trigger a synthetic submit only after plugins are live.\n\t// Plugins with synchronous `onInit` make this resolve on the next\n\t// microtask. If no plugins are registered, it resolves immediately.\n\twhenReady: () => Promise<void>\n}\n\nconst EMAIL_STORAGE_KEY = 'feedback_user_email'\n\nfunction escapeHtml(value: string): string {\n\treturn value.replace(/[&<>\"']/g, ch => {\n\t\tswitch (ch) {\n\t\t\tcase '&':\n\t\t\t\treturn '&'\n\t\t\tcase '<':\n\t\t\t\treturn '<'\n\t\t\tcase '>':\n\t\t\t\treturn '>'\n\t\t\tcase '\"':\n\t\t\t\treturn '"'\n\t\t\tcase \"'\":\n\t\t\t\treturn '''\n\t\t\tdefault:\n\t\t\t\treturn ch\n\t\t}\n\t})\n}\n\n// Merge plugin onFeedbackSubmit patches into a base submission.\n//\n// Top-level keys: shallow-merge, later patches win wholesale.\n// `metadata`: deep-merge one level. Earlier keys are preserved when later\n// patches don't set them; later keys win on conflict. This means two\n// plugins can both contribute `metadata: { ... }` without either erasing\n// the other's keys.\nexport function mergePluginPatches(\n\tbase: FeedbackSubmission,\n\tpatches: ReadonlyArray<Partial<FeedbackSubmission> | undefined>,\n): FeedbackSubmission {\n\tlet result: FeedbackSubmission = base\n\tfor (const patch of patches) {\n\t\tif (!patch || typeof patch !== 'object') continue\n\t\tconst { metadata: patchMetadata, ...rest } = patch\n\t\tresult = { ...result, ...rest }\n\t\tif (patchMetadata && typeof patchMetadata === 'object') {\n\t\t\tresult.metadata = {\n\t\t\t\t...(result.metadata ?? {}),\n\t\t\t\t...patchMetadata,\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\nfunction readStoredEmail(): string {\n\tif (typeof window === 'undefined') return ''\n\ttry {\n\t\treturn window.localStorage.getItem(EMAIL_STORAGE_KEY) ?? ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\nfunction writeStoredEmail(email: string): void {\n\ttry {\n\t\twindow.localStorage.setItem(EMAIL_STORAGE_KEY, email)\n\t} catch {\n\t\t// ignore\n\t}\n}\n\nexport function initUseroFeedbackWidget(\n\tprops: FeedbackWidgetProps,\n): UseroWidgetHandle {\n\tif (typeof document === 'undefined') {\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t\tidentify: () => {},\n\t\t}\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\tif (!clientId || clientId.length < 3) {\n\t\tconst err = new Error('Invalid config. Contact admin.')\n\t\tprops.onError?.(err)\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t\tidentify: () => {},\n\t\t}\n\t}\n\n\t// Mutable view of every prop that can be hot-swapped via update(). Read\n\t// these at render time, never destructure into local const above the\n\t// render closures or you'll capture stale values.\n\tlet position: WidgetPosition = props.position ?? 'right'\n\tlet userThemeOverride: Partial<WidgetTheme> | undefined = props.theme\n\tlet theme: WidgetTheme = resolveTheme(userThemeOverride)\n\tlet title: string = props.title ?? 'Share Feedback'\n\tlet placeholder: string = props.placeholder ?? 'Tell us what you think... (optional)'\n\tlet showEmailOption: boolean = props.showEmailOption ?? true\n\tlet showScreenshotOption: boolean = props.showScreenshotOption ?? true\n\tlet environment: string | undefined = props.environment\n\tlet metadata: Record<string, unknown> | undefined = props.metadata\n\tlet onSubmit: FeedbackWidgetProps['onSubmit'] = props.onSubmit\n\tlet onError: FeedbackWidgetProps['onError'] = props.onError\n\tlet onOpen: FeedbackWidgetProps['onOpen'] = props.onOpen\n\tlet onClose: FeedbackWidgetProps['onClose'] = props.onClose\n\tlet getUserFn: FeedbackWidgetProps['getUser'] = props.getUser\n\t// Last `user` prop seen via init or update(). When set (including\n\t// explicit null for logout), it wins over getUserFn on re-resolve.\n\t// `undefined` means \"no `user` prop ever supplied; defer to getUser\".\n\tlet currentUserProp: UseroUser | null | undefined = props.user\n\n\tconst apiClient = new FeedbackApiClient(baseUrl)\n\tconst identifyTransport = { apiUrl: baseUrl ?? DEFAULT_API_URL, clientId }\n\n\t// Track the last id the SDK has seen so we can detect logout\n\t// (id -> null) and rotate the anonymousId. Identify dedupe inside\n\t// identifyIfChanged via a fingerprint guarantees re-runs with the same\n\t// user never POST. We also short-circuit BEFORE calling it when the\n\t// trait object is reference-identical, which only catches hosts that\n\t// memoise their traits object; the common React case of a fresh\n\t// `{ ... }` literal per render falls through to the fingerprint\n\t// dedupe, which is cheap (one stringify, no network) so this is fine.\n\tlet lastUserId: string | null = null\n\tlet lastTraitsRef: UseroUser['traits'] | undefined\n\tlet lastEmail: string | undefined\n\tlet lastDisplayName: string | undefined\n\n\tfunction applyResolvedUser(user: UseroUser | null | undefined): void {\n\t\tconst next = user ?? null\n\t\tif (next) {\n\t\t\tconst unchanged =\n\t\t\t\tnext.id === lastUserId &&\n\t\t\t\tnext.traits === lastTraitsRef &&\n\t\t\t\tnext.email === lastEmail &&\n\t\t\t\tnext.displayName === lastDisplayName\n\t\t\tif (unchanged) return\n\t\t\tvoid identifyIfChanged(identifyTransport, next)\n\t\t\tlastUserId = next.id\n\t\t\tlastTraitsRef = next.traits\n\t\t\tlastEmail = next.email\n\t\t\tlastDisplayName = next.displayName\n\t\t} else if (lastUserId !== null) {\n\t\t\t// Logout transition. Rotate anonymousId so the next anonymous\n\t\t\t// trail doesn't get auto-merged into the previous person on\n\t\t\t// the next identify().\n\t\t\tidentityHandleLogout()\n\t\t\tlastUserId = null\n\t\t\tlastTraitsRef = undefined\n\t\t\tlastEmail = undefined\n\t\t\tlastDisplayName = undefined\n\t\t}\n\t}\n\n\tfunction resolveAndApplyGetUser(): void {\n\t\tif (!getUserFn) return\n\t\ttry {\n\t\t\tapplyResolvedUser(getUserFn() ?? null)\n\t\t} catch {\n\t\t\t// getUser threw; leave the resolved user as it was. Do not\n\t\t\t// rotate, do not fire identify. A throwing getter likely means\n\t\t\t// the host app's auth context is mid-render.\n\t\t}\n\t}\n\n\t// Initial resolve: prefer the imperative `user` prop, fall back to\n\t// the `getUser` callback. Both are safe to call here; we just don't\n\t// fire identify when both are absent.\n\tif (props.user !== undefined) {\n\t\tapplyResolvedUser(props.user)\n\t} else if (getUserFn) {\n\t\tresolveAndApplyGetUser()\n\t}\n\n\t// Plugin registry. Each plugin gets its own context with a private store.\n\t// `onInit` is fired non-blocking so a slow plugin can't delay the first\n\t// paint. Errors are caught so a misbehaving plugin can't tear the widget\n\t// down or block submissions.\n\tconst pluginList: ReadonlyArray<UseroPlugin> = props.plugins ?? []\n\tconst pluginStores = new Map<string, unknown>()\n\tconst pluginContexts = new Map<string, PluginContext>()\n\t// Tracks every onInit's settlement so `whenReady()` can resolve only\n\t// after all plugins have finished initializing. Synchronous onInits\n\t// resolve on the next microtask via Promise.resolve().\n\tconst initPromises: Promise<void>[] = []\n\tfor (const plugin of pluginList) {\n\t\tconst ctx: PluginContext = {\n\t\t\tclientId,\n\t\t\tbaseUrl: baseUrl ?? DEFAULT_API_URL,\n\t\t\tlogger: createPluginLogger(plugin.name),\n\t\t\tgetStore: <T,>() => pluginStores.get(plugin.name) as T | undefined,\n\t\t\tsetStore: <T,>(value: T) => {\n\t\t\t\tpluginStores.set(plugin.name, value)\n\t\t\t},\n\t\t\t// Expose the same user-resolution path the widget uses, so plugins\n\t\t\t// (e.g. session-replay for replay-only installs that never open the\n\t\t\t// widget) can re-poll user state at their own boundaries. Prefers\n\t\t\t// the imperative `user` prop when set, falls back to `getUser`.\n\t\t\tresolveUser: () => {\n\t\t\t\tif (destroyed) return\n\t\t\t\tif (currentUserProp !== undefined) {\n\t\t\t\t\tapplyResolvedUser(currentUserProp)\n\t\t\t\t} else {\n\t\t\t\t\tresolveAndApplyGetUser()\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t\tpluginContexts.set(plugin.name, ctx)\n\t\tif (plugin.onInit) {\n\t\t\tconst settled = (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait plugin.onInit?.(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onInit threw', err)\n\t\t\t\t}\n\t\t\t})()\n\t\t\tinitPromises.push(settled)\n\t\t}\n\t}\n\tconst readyPromise: Promise<void> =\n\t\tinitPromises.length === 0 ? Promise.resolve() : Promise.all(initPromises).then(() => {})\n\n\t// State\n\tlet isOpen = false\n\tlet focusCommentNext = false\n\tlet selectedRating: FeedbackRating | undefined = undefined\n\tlet comment = ''\n\tlet shareEmail = false\n\tlet userEmail = readStoredEmail()\n\tlet isSubmitting = false\n\tlet submitMessage: { type: 'success' | 'error'; text: string } | null = null\n\tlet screenshots: ScreenshotData[] = []\n\tlet isUploadingScreenshot = false\n\tlet screenshotError: string | null = null\n\n\tconst MAX_SCREENSHOTS = 3\n\tconst MAX_SCREENSHOT_BYTES = 10 * 1024 * 1024 // 10MB, matches old React widget\n\n\t// Host element on the page. ShadowRoot keeps host CSS isolated.\n\tconst host = document.createElement('div')\n\thost.setAttribute('data-usero-widget', '')\n\t// position: static so the host element doesn't take any space; the\n\t// fixed-position children inside the shadow root anchor to the viewport.\n\thost.style.cssText = 'all: initial;'\n\tdocument.body.appendChild(host)\n\tconst root = host.attachShadow({ mode: 'open' })\n\n\t// Notify recording plugins (e.g. session-replay) that a shadow root they\n\t// need to observe has just been mounted into the page. rrweb's automatic\n\t// shadow-root traversal only catches roots that exist at record-start\n\t// time (via the initial full snapshot) OR that get attached as part of\n\t// a new node addition observed by its MutationObserver. Our widget host\n\t// is appended to <body> first and `attachShadow` is called immediately\n\t// after, so the observed mutation does not yet have a shadowRoot. The\n\t// session-replay plugin handles this signal by re-taking a full\n\t// snapshot, which causes rrweb to walk into and start observing this\n\t// shadow tree. Dispatched as a CustomEvent on window so the plugin\n\t// stays decoupled from the widget.\n\t// Re-poll getUser at widget interaction boundaries (panel open, mount).\n\t// This catches \"user logged in while widget was idle\" without setting\n\t// up a polling timer that would tick on background tabs. Identify dedupe\n\t// via fingerprint inside identifyIfChanged means same-user re-polls are\n\t// no-ops on the network.\n\tfunction pollGetUser(): void {\n\t\tresolveAndApplyGetUser()\n\t}\n\n\tfunction notifyShadowUpdate(reason: 'mount' | 'panel-open'): void {\n\t\ttry {\n\t\t\twindow.dispatchEvent(\n\t\t\t\tnew CustomEvent('usero:shadow-update', {\n\t\t\t\t\tdetail: { host, root, reason },\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// Older browsers without CustomEvent / dispatchEvent: best-effort.\n\t\t}\n\t}\n\tnotifyShadowUpdate('mount')\n\n\t// Inject styles once into the shadow root.\n\tconst style = document.createElement('style')\n\tstyle.textContent = FEEDBACK_CSS\n\troot.appendChild(style)\n\n\t// Containers\n\tconst buttonEl = document.createElement('button')\n\tconst backdropEl = document.createElement('div')\n\tconst panelEl = document.createElement('div')\n\troot.appendChild(buttonEl)\n\troot.appendChild(backdropEl)\n\troot.appendChild(panelEl)\n\n\tfunction setSubmitMessage(\n\t\tnext: { type: 'success' | 'error'; text: string } | null,\n\t): void {\n\t\tsubmitMessage = next\n\t\trender()\n\t}\n\n\tfunction open(): void {\n\t\tif (isOpen) return\n\t\tisOpen = true\n\t\tfocusCommentNext = true\n\t\t// Reset transient state\n\t\tselectedRating = undefined\n\t\tcomment = ''\n\t\tshareEmail = false\n\t\tsubmitMessage = null\n\t\tscreenshots = []\n\t\tscreenshotError = null\n\t\tisUploadingScreenshot = false\n\t\tapiClient.ping()\n\t\tpollGetUser()\n\t\tonOpen?.()\n\t\trender()\n\t\t// The panel's interactive content is `innerHTML`-ed inside the shadow\n\t\t// root on first render, which IS observable by rrweb's MutationObserver\n\t\t// as long as the shadow root is registered. Re-fire the signal so a\n\t\t// recorder that started before the widget mounted (or before the panel\n\t\t// rendered its first interactive markup) re-snapshots and observes the\n\t\t// shadow root from this point on.\n\t\tnotifyShadowUpdate('panel-open')\n\t}\n\n\tasync function handleScreenshotFile(file: File): Promise<void> {\n\t\tscreenshotError = null\n\t\tif (!file.type.startsWith('image/')) {\n\t\t\tscreenshotError = 'Image files only'\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\t\tif (file.size > MAX_SCREENSHOT_BYTES) {\n\t\t\tscreenshotError = 'Max 10MB'\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\t\tif (screenshots.length >= MAX_SCREENSHOTS) {\n\t\t\tscreenshotError = `Max ${MAX_SCREENSHOTS} screenshots`\n\t\t\trender()\n\t\t\treturn\n\t\t}\n\n\t\tisUploadingScreenshot = true\n\t\trender()\n\t\ttry {\n\t\t\tconst uploaded = await apiClient.uploadScreenshot(file, clientId)\n\t\t\tscreenshots = [...screenshots, uploaded]\n\t\t} catch (err) {\n\t\t\tscreenshotError = err instanceof Error ? err.message : 'Upload failed'\n\t\t} finally {\n\t\t\tisUploadingScreenshot = false\n\t\t\trender()\n\t\t}\n\t}\n\n\tfunction removeScreenshot(index: number): void {\n\t\tscreenshots = screenshots.filter((_, i) => i !== index)\n\t\trender()\n\t}\n\n\tfunction close(): void {\n\t\tif (!isOpen) return\n\t\tisOpen = false\n\t\tonClose?.()\n\t\trender()\n\t}\n\n\tasync function submitForm(): Promise<void> {\n\t\tif (isSubmitting) return\n\t\tisSubmitting = true\n\t\tsubmitMessage = null\n\t\trender()\n\n\t\tconst feedbackData: FeedbackData = {\n\t\t\trating: selectedRating,\n\t\t\tcomment: comment.trim() || undefined,\n\t\t\tuserEmail: shareEmail ? userEmail : undefined,\n\t\t\tscreenshots: screenshots.length > 0 ? screenshots : undefined,\n\t\t\tmetadata: {\n\t\t\t\tpageUrl: window.location.href,\n\t\t\t\tpageTitle: document.title || 'Untitled Page',\n\t\t\t\treferrer: document.referrer || undefined,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t},\n\t\t}\n\n\t\tconst submission: FeedbackSubmission = {\n\t\t\tclientId,\n\t\t\trating: feedbackData.rating,\n\t\t\tcomment: feedbackData.comment,\n\t\t\tuserEmail: feedbackData.userEmail,\n\t\t\tpageUrl: feedbackData.metadata.pageUrl,\n\t\t\tpageTitle: feedbackData.metadata.pageTitle,\n\t\t\treferrer: feedbackData.metadata.referrer,\n\t\t\tenvironment,\n\t\t}\n\t\tif (screenshots.length > 0) submission.screenshots = screenshots\n\t\tif (metadata !== undefined) submission.metadata = metadata\n\n\t\tconst validation = validateFeedbackSubmission(submission)\n\t\tif (!validation.isValid) {\n\t\t\tisSubmitting = false\n\t\t\tsetSubmitMessage({ type: 'error', text: validation.errors.join(', ') })\n\t\t\treturn\n\t\t}\n\n\t\t// Run plugin onFeedbackSubmit hooks in parallel and merge the\n\t\t// returned partial payloads into the outgoing submission. A plugin\n\t\t// that throws or rejects is logged and skipped — never blocks submit.\n\t\t//\n\t\t// Merge policy:\n\t\t// - `metadata` is DEEP-merged (one level): later plugins' keys\n\t\t// win on conflict, but non-conflicting keys from earlier\n\t\t// plugins are preserved. metadata is the natural collision\n\t\t// point (every plugin wants to attach context) so deep merge\n\t\t// is what users expect.\n\t\t// - Every other top-level key is shallow-merged: later plugins\n\t\t// win wholesale. This is fine in practice because dedicated\n\t\t// keys like `replayEvents` have a single writer.\n\t\tlet enrichedSubmission: FeedbackSubmission = submission\n\t\tif (pluginList.length > 0) {\n\t\t\tconst patchPromises = pluginList.map(async plugin => {\n\t\t\t\tif (!plugin.onFeedbackSubmit) return undefined\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) return undefined\n\t\t\t\ttry {\n\t\t\t\t\treturn await plugin.onFeedbackSubmit(ctx, submission)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onFeedbackSubmit threw', err)\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t})\n\t\t\tconst patches = await Promise.all(patchPromises)\n\t\t\tenrichedSubmission = mergePluginPatches(submission, patches)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await apiClient.submitFeedback(enrichedSubmission)\n\t\t\tif (response.success) {\n\t\t\t\tif (shareEmail && userEmail) writeStoredEmail(userEmail)\n\t\t\t\tonSubmit?.(feedbackData)\n\t\t\t\tselectedRating = undefined\n\t\t\t\tcomment = ''\n\t\t\t\tshareEmail = false\n\t\t\t\tscreenshots = []\n\t\t\t\tscreenshotError = null\n\t\t\t\tsubmitMessage = { type: 'success', text: 'Thank you!' }\n\t\t\t} else {\n\t\t\t\tconst msg = response.error ?? 'Error occurred. Try again.'\n\t\t\t\tonError?.(new Error(msg))\n\t\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : 'Error occurred. Try again.'\n\t\t\tonError?.(new Error(msg))\n\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t} finally {\n\t\t\tisSubmitting = false\n\t\t\trender()\n\t\t}\n\t}\n\n\t// Static button content + styles (only style.background changes once)\n\tfunction renderButton(): void {\n\t\tbuttonEl.className = `fb-btn fb-btn--${position} ${isOpen ? 'fb-btn--open' : ''}`\n\t\tbuttonEl.setAttribute('aria-label', 'Open feedback')\n\t\tbuttonEl.type = 'button'\n\t\tbuttonEl.style.background = `linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)})`\n\t\tbuttonEl.innerHTML = isOpen\n\t\t\t? `<span style=\"font-size:20px;\">✕</span>`\n\t\t\t: ''\n\t}\n\n\tfunction renderBackdrop(): void {\n\t\tbackdropEl.className = 'fb-backdrop'\n\t\tbackdropEl.style.display = isOpen ? 'block' : 'none'\n\t\tbackdropEl.setAttribute('aria-label', 'Close modal')\n\t}\n\n\tfunction renderPanel(): void {\n\t\tpanelEl.className = `fb-pnl-base fb-pnl--${position} ${\n\t\t\tisOpen ? 'fb-pnl--open' : 'fb-pnl--closed'\n\t\t}`\n\t\tpanelEl.style.backgroundColor = theme.background\n\t\tif (position === 'right') {\n\t\t\tpanelEl.style.borderLeft = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderRight = ''\n\t\t} else {\n\t\t\tpanelEl.style.borderRight = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderLeft = ''\n\t\t}\n\t\tpanelEl.setAttribute('role', 'dialog')\n\t\tpanelEl.setAttribute('aria-modal', 'true')\n\t\tpanelEl.setAttribute('aria-labelledby', 'usero-feedback-title')\n\n\t\tconst remaining = 1000 - comment.length\n\t\tconst lowChars = remaining < 50\n\n\t\tconst ratingsHtml = ([1, 2, 3, 4] as FeedbackRating[])\n\t\t\t.map(r => {\n\t\t\t\tconst sel = selectedRating === r\n\t\t\t\tconst bg = EMOJI_BACKGROUNDS[r]\n\t\t\t\tconst cls = ['fb-ec', sel && 'fb-ec--sel'].filter(Boolean).join(' ')\n\t\t\t\t// Set color on the button so .fb-el (color: currentColor) inherits\n\t\t\t\t// the themed foreground. Without this it falls back to the UA\n\t\t\t\t// default for <button>, which is black on dark backgrounds.\n\t\t\t\treturn `\n\t\t\t\t\t<div class=\"${cls}\" style=\"background:${bg}\">\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-eb\" data-rating=\"${r}\" role=\"radio\" aria-checked=\"${sel}\" aria-label=\"${r}: ${RATING_LABELS[r]}\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t\t<div class=\"fb-ei\"><span role=\"img\" aria-label=\"${RATING_LABELS[r]}\">${EMOJI_MAP[r]}</span></div>\n\t\t\t\t\t\t\t<div class=\"fb-el\" style=\"color:${theme.text}\">${RATING_LABELS[r]}</div>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t`\n\t\t\t})\n\t\t\t.join('')\n\n\t\tconst messageHtml = submitMessage\n\t\t\t? `<div class=\"fb-msg fb-msg--header ${submitMessage.type === 'success' ? 'fb-msg--ok' : 'fb-msg--err'}\">${submitMessage.type === 'success' ? '✓' : '⚠'} ${escapeHtml(submitMessage.text)}</div>`\n\t\t\t: ''\n\n\t\t// The upload button + char counter share a single horizontal row to\n\t\t// keep the panel compact (matches the legacy react-feedback-collector\n\t\t// layout). Upload extras (error message, previews, max limit) live on\n\t\t// their own row beneath, so they can wrap freely.\n\t\tconst uploadBtnHtml = showScreenshotOption\n\t\t\t? (() => {\n\t\t\t\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\t\t\t\tconst btnDisabled = isUploadingScreenshot || atMax\n\t\t\t\t\treturn `\n\t\t\t\t\t\t<input type=\"file\" accept=\"image/*\" data-role=\"screenshot-input\" style=\"display:none;\" aria-label=\"Choose screenshot\" />\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-upb ${btnDisabled ? 'fb-upb--dis' : ''}\" data-role=\"screenshot-pick\" ${btnDisabled ? 'disabled' : ''} style=\"border:1px solid ${theme.border};color:${theme.text};\">\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\tisUploadingScreenshot\n\t\t\t\t\t\t\t\t\t? '<span class=\"fb-ups\"></span> Uploading...'\n\t\t\t\t\t\t\t\t\t: '📷 Add screenshot'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t`\n\t\t\t\t})()\n\t\t\t: ''\n\t\tconst uploadExtrasHtml = showScreenshotOption\n\t\t\t? (() => {\n\t\t\t\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\t\t\t\tconst previewsHtml = screenshots\n\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t(shot, i) => `\n\t\t\t\t\t\t\t\t<div class=\"fb-sp\">\n\t\t\t\t\t\t\t\t\t<img src=\"${escapeHtml(shot.url)}\" alt=\"Screenshot ${i + 1}\" class=\"fb-si\" />\n\t\t\t\t\t\t\t\t\t<button type=\"button\" class=\"fb-sr\" data-role=\"screenshot-remove\" data-index=\"${i}\" aria-label=\"Remove screenshot\">✕</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('')\n\t\t\t\t\tconst errorHtml = screenshotError\n\t\t\t\t\t\t? `<div class=\"fb-upe\">⚠ ${escapeHtml(screenshotError)}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t\tconst limitHtml = atMax\n\t\t\t\t\t\t? `<div class=\"fb-sl\">Max ${MAX_SCREENSHOTS}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t\treturn screenshotError || screenshots.length > 0 || atMax\n\t\t\t\t\t\t? `<div class=\"fb-up-extras\">${errorHtml}${\n\t\t\t\t\t\t\t\tscreenshots.length > 0\n\t\t\t\t\t\t\t\t\t? `<div class=\"fb-ss\">${previewsHtml}</div>`\n\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t}${limitHtml}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t})()\n\t\t\t: ''\n\n\t\tconst emailBlockHtml = showEmailOption\n\t\t\t? `\n\t\t\t\t<div class=\"fb-email\">\n\t\t\t\t\t<label class=\"fb-email-lbl\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t<input type=\"checkbox\" class=\"fb-email-cb\" data-role=\"share-email\" ${shareEmail ? 'checked' : ''} aria-label=\"Share email\" />\n\t\t\t\t\t\t<span>Share my email</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t${\n\t\t\t\t\t\tshareEmail\n\t\t\t\t\t\t\t? `<input type=\"email\" class=\"fb-email-inp\" data-role=\"email-input\" value=\"${escapeHtml(userEmail)}\" placeholder=\"your.email@example.com\" aria-label=\"Email\" maxlength=\"254\" autocomplete=\"email\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\" />`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t`\n\t\t\t: ''\n\n\t\tconst submitDisabled = isSubmitting\n\t\tconst submitStyle = `background:linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)});color:#ffffff;${submitDisabled ? 'opacity:0.6;cursor:not-allowed;' : ''}`\n\n\t\tpanelEl.innerHTML = `\n\t\t\t<div class=\"fb-cnt\">\n\t\t\t\t<div class=\"fb-hdr\" style=\"border-bottom:1px solid ${theme.border}\">\n\t\t\t\t\t<h2 id=\"usero-feedback-title\" class=\"fb-ttl\" style=\"color:${theme.text}\">${escapeHtml(title)}</h2>\n\t\t\t\t\t${messageHtml}\n\t\t\t\t\t<button class=\"fb-close-btn\" data-role=\"close\" style=\"color:${theme.text}\" aria-label=\"Close\" type=\"button\">✕</button>\n\t\t\t\t</div>\n\t\t\t\t<form data-role=\"form\">\n\t\t\t\t\t<div class=\"fb-es\" role=\"radiogroup\" aria-label=\"Rate experience\">${ratingsHtml}</div>\n\t\t\t\t\t<textarea class=\"fb-ta\" data-role=\"comment\" placeholder=\"${escapeHtml(placeholder)}\" aria-label=\"Comments\" maxlength=\"1000\" rows=\"2\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\">${escapeHtml(comment)}</textarea>\n\t\t\t\t\t<div class=\"fb-toolrow\">\n\t\t\t\t\t\t${uploadBtnHtml}\n\t\t\t\t\t\t<div class=\"fb-charcount${lowChars ? ' fb-charcount--low' : ''}\" data-role=\"charcount\" style=\"color:${lowChars ? '#dc2626' : theme.text};opacity:${lowChars ? 1 : 0.6};\">${remaining} chars remaining</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t${uploadExtrasHtml ? `<div class=\"fb-up\">${uploadExtrasHtml}</div>` : ''}\n\t\t\t\t\t${emailBlockHtml}\n\t\t\t\t\t<button class=\"fb-sub ${submitDisabled ? 'fb-sub--dis' : ''}\" type=\"submit\" aria-label=\"Submit\" ${submitDisabled ? 'disabled' : ''} style=\"${submitStyle}\">\n\t\t\t\t\t\t${isSubmitting ? '<span class=\"fb-spin\"></span>' : ''}\n\t\t\t\t\t\t${isSubmitting ? 'Submitting...' : 'Send Feedback 🚀'}\n\t\t\t\t\t</button>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t`\n\n\t\t// Wire up panel-internal events\n\t\tconst form = panelEl.querySelector<HTMLFormElement>('form[data-role=\"form\"]')\n\t\tform?.addEventListener('submit', e => {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t})\n\n\t\tpanelEl\n\t\t\t.querySelector<HTMLButtonElement>('button[data-role=\"close\"]')\n\t\t\t?.addEventListener('click', close)\n\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>('button[data-rating]')\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst value = btn.dataset.rating\n\t\t\t\t\tif (value === '1' || value === '2' || value === '3' || value === '4') {\n\t\t\t\t\t\tselectedRating = Number(value) as FeedbackRating\n\t\t\t\t\t\tfocusCommentNext = true\n\t\t\t\t\t\trender()\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\n\t\tconst textarea = panelEl.querySelector<HTMLTextAreaElement>(\n\t\t\t'textarea[data-role=\"comment\"]',\n\t\t)\n\t\tif (textarea) {\n\t\t\tif (focusCommentNext) {\n\t\t\t\tfocusCommentNext = false\n\t\t\t\t// Defer to next frame so the browser doesn't scroll the panel\n\t\t\t\t// while it's still animating in.\n\t\t\t\trequestAnimationFrame(() => textarea.focus({ preventScroll: true }))\n\t\t\t}\n\t\t\ttextarea.addEventListener('input', () => {\n\t\t\t\tif (textarea.value.length <= 1000) {\n\t\t\t\t\tcomment = textarea.value\n\t\t\t\t\t// Update char count without full rerender to avoid losing focus.\n\t\t\t\t\t// IMPORTANT: target by stable class. A previous selector\n\t\t\t\t\t// `.fb-cnt form > div > div` matched the first rating tile,\n\t\t\t\t\t// hijacking it with the char-count text on every keystroke.\n\t\t\t\t\tconst counter = panelEl.querySelector<HTMLDivElement>(\n\t\t\t\t\t\t'[data-role=\"charcount\"]',\n\t\t\t\t\t)\n\t\t\t\t\tif (counter) {\n\t\t\t\t\t\tconst left = 1000 - comment.length\n\t\t\t\t\t\tcounter.textContent = `${left} chars remaining`\n\t\t\t\t\t\tcounter.style.color = left < 50 ? '#dc2626' : theme.text\n\t\t\t\t\t\tcounter.style.opacity = left < 50 ? '1' : '0.6'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tconst shareCb = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"share-email\"]',\n\t\t)\n\t\tshareCb?.addEventListener('change', () => {\n\t\t\tshareEmail = shareCb.checked\n\t\t\trender()\n\t\t})\n\n\t\tconst emailInp = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"email-input\"]',\n\t\t)\n\t\temailInp?.addEventListener('input', () => {\n\t\t\tif (emailInp.value.length <= 254) {\n\t\t\t\tuserEmail = emailInp.value\n\t\t\t}\n\t\t})\n\n\t\tconst fileInput = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"screenshot-input\"]',\n\t\t)\n\t\tconst pickBtn = panelEl.querySelector<HTMLButtonElement>(\n\t\t\t'button[data-role=\"screenshot-pick\"]',\n\t\t)\n\t\tpickBtn?.addEventListener('click', () => {\n\t\t\tfileInput?.click()\n\t\t})\n\t\tfileInput?.addEventListener('change', () => {\n\t\t\tconst file = fileInput.files?.[0]\n\t\t\tif (!file) return\n\t\t\tvoid handleScreenshotFile(file).finally(() => {\n\t\t\t\tif (fileInput) fileInput.value = ''\n\t\t\t})\n\t\t})\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>(\n\t\t\t\t'button[data-role=\"screenshot-remove\"]',\n\t\t\t)\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst idx = Number(btn.dataset.index)\n\t\t\t\t\tif (Number.isInteger(idx)) removeScreenshot(idx)\n\t\t\t\t})\n\t\t\t})\n\t}\n\n\tfunction render(): void {\n\t\trenderButton()\n\t\trenderBackdrop()\n\t\trenderPanel()\n\t}\n\n\t// Top-level event listeners\n\tbuttonEl.addEventListener('click', () => {\n\t\tif (isOpen) close()\n\t\telse open()\n\t})\n\tbackdropEl.addEventListener('click', close)\n\n\tconst onKeyDown = (e: KeyboardEvent): void => {\n\t\tif (!isOpen) return\n\t\tif (e.key === 'Escape') close()\n\t\tif (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t}\n\t}\n\tdocument.addEventListener('keydown', onKeyDown)\n\n\t// Live OS color-scheme tracking. Only active while the caller has not\n\t// provided an explicit `theme` prop. If they later pass one via update(),\n\t// we detach. If they later clear it (set to undefined), we re-attach.\n\tlet darkMql: MediaQueryList | null = null\n\tlet mqlListener: ((ev: MediaQueryListEvent) => void) | null = null\n\n\tfunction detachMqlListener(): void {\n\t\tif (darkMql && mqlListener) {\n\t\t\tdarkMql.removeEventListener('change', mqlListener)\n\t\t}\n\t\tdarkMql = null\n\t\tmqlListener = null\n\t}\n\n\tfunction attachMqlListener(): void {\n\t\tif (darkMql) return\n\t\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n\t\tdarkMql = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tmqlListener = () => {\n\t\t\t// Only react if user still hasn't overridden the theme.\n\t\t\tif (userThemeOverride !== undefined) return\n\t\t\ttheme = resolveTheme(undefined)\n\t\t\trender()\n\t\t}\n\t\tdarkMql.addEventListener('change', mqlListener)\n\t}\n\n\tif (userThemeOverride === undefined) attachMqlListener()\n\n\t// Initial paint\n\trender()\n\n\tlet destroyed = false\n\treturn {\n\t\tdestroy: () => {\n\t\t\tif (destroyed) return\n\t\t\tdestroyed = true\n\t\t\tdocument.removeEventListener('keydown', onKeyDown)\n\t\t\tdetachMqlListener()\n\t\t\tfor (const plugin of pluginList) {\n\t\t\t\tif (!plugin.onDestroy) continue\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) continue\n\t\t\t\ttry {\n\t\t\t\t\tplugin.onDestroy(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onDestroy threw', err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tpluginStores.clear()\n\t\t\tpluginContexts.clear()\n\t\t\thost.remove()\n\t\t},\n\t\topen,\n\t\tclose,\n\t\twhenReady: () => readyPromise,\n\t\tidentify: (user: UseroUser | null) => {\n\t\t\tif (destroyed) return\n\t\t\tcurrentUserProp = user\n\t\t\tapplyResolvedUser(user)\n\t\t},\n\t\tupdate: next => {\n\t\t\tif (destroyed) return\n\t\t\tlet needsRender = false\n\t\t\tif (next.position !== undefined && next.position !== position) {\n\t\t\t\tposition = next.position\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif ('theme' in next) {\n\t\t\t\t// Caller opted in/out of explicit theme control. Track the\n\t\t\t\t// override so the matchMedia listener and any further\n\t\t\t\t// resolutions know whether the user is in charge.\n\t\t\t\tuserThemeOverride = next.theme\n\t\t\t\ttheme = resolveTheme(userThemeOverride)\n\t\t\t\tif (userThemeOverride === undefined) attachMqlListener()\n\t\t\t\telse detachMqlListener()\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.title !== undefined && next.title !== title) {\n\t\t\t\ttitle = next.title\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.placeholder !== undefined && next.placeholder !== placeholder) {\n\t\t\t\tplaceholder = next.placeholder\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showEmailOption !== undefined &&\n\t\t\t\tnext.showEmailOption !== showEmailOption\n\t\t\t) {\n\t\t\t\tshowEmailOption = next.showEmailOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showScreenshotOption !== undefined &&\n\t\t\t\tnext.showScreenshotOption !== showScreenshotOption\n\t\t\t) {\n\t\t\t\tshowScreenshotOption = next.showScreenshotOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\t// Non-render-affecting props: just swap refs.\n\t\t\tif ('environment' in next) environment = next.environment\n\t\t\tif ('metadata' in next) metadata = next.metadata\n\t\t\tif ('onSubmit' in next) onSubmit = next.onSubmit\n\t\t\tif ('onError' in next) onError = next.onError\n\t\t\tif ('onOpen' in next) onOpen = next.onOpen\n\t\t\tif ('onClose' in next) onClose = next.onClose\n\t\t\tif ('getUser' in next) getUserFn = next.getUser\n\t\t\t// Identity: React wrapper hot-swaps `user` here on every render.\n\t\t\t// applyResolvedUser dedupes via fingerprint, so passing the same\n\t\t\t// user object is a no-op transport-wise. Track the latest prop\n\t\t\t// so plugin-driven re-resolves (PluginContext.resolveUser) know\n\t\t\t// to prefer the imperative path over getUserFn.\n\t\t\tif ('user' in next) {\n\t\t\t\tcurrentUserProp = next.user\n\t\t\t\tapplyResolvedUser(next.user)\n\t\t\t}\n\t\t\tif (needsRender) render()\n\t\t},\n\t}\n}\n","// Thin React wrapper around the framework-free vanilla widget. Renders\n// nothing into the React tree; the widget mounts a host <div> on\n// document.body and renders into a shadow root. This keeps the React\n// bundle tiny (just the wrapper) and means there is one source of truth\n// for widget UX, the vanilla implementation.\n\nimport { useEffect, useRef } from 'react'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tinitUseroFeedbackWidget,\n\tmergeTheme,\n\ttype UseroWidgetHandle,\n} from './vanilla'\nimport type { FeedbackData, FeedbackWidgetProps } from './types'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tUseroUser,\n\tUseroUserTraitValue,\n\tUseroUserTraits,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type { UseroWidgetHandle } from './vanilla'\n\nexport function UseroFeedbackWidget(props: FeedbackWidgetProps): null {\n\tconst handleRef = useRef<UseroWidgetHandle | null>(null)\n\n\t// Latest callbacks live in a ref so identity changes (a new arrow each\n\t// render) never re-init the widget.\n\tconst callbacksRef = useRef({\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t})\n\tcallbacksRef.current = {\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\t// Init / tear-down. We only re-init when clientId or baseUrl change,\n\t// because the API client + widget identity are bound to those.\n\tuseEffect(() => {\n\t\tconst handle = initUseroFeedbackWidget({\n\t\t\t...props,\n\t\t\tonSubmit: (data: FeedbackData) => callbacksRef.current.onSubmit?.(data),\n\t\t\tonError: (err: Error) => callbacksRef.current.onError?.(err),\n\t\t\tonOpen: () => callbacksRef.current.onOpen?.(),\n\t\t\tonClose: () => callbacksRef.current.onClose?.(),\n\t\t})\n\t\thandleRef.current = handle\n\t\treturn () => {\n\t\t\thandle.destroy()\n\t\t\thandleRef.current = null\n\t\t}\n\t\t// Intentionally narrow deps. All other prop changes flow through the\n\t\t// update() effect below.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [clientId, baseUrl])\n\n\t// Hot-swap render-affecting props without re-init.\n\tconst themeJson = JSON.stringify(props.theme ?? null)\n\tconst metadataJson = JSON.stringify(props.metadata ?? null)\n\tuseEffect(() => {\n\t\tconst handle = handleRef.current\n\t\tif (!handle) return\n\t\tconst updates: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>> = {}\n\t\tif (props.position !== undefined) updates.position = props.position\n\t\tif (props.theme !== undefined) updates.theme = props.theme\n\t\tif (props.title !== undefined) updates.title = props.title\n\t\tif (props.placeholder !== undefined) updates.placeholder = props.placeholder\n\t\tif (props.showEmailOption !== undefined) {\n\t\t\tupdates.showEmailOption = props.showEmailOption\n\t\t}\n\t\tif (props.showScreenshotOption !== undefined) {\n\t\t\tupdates.showScreenshotOption = props.showScreenshotOption\n\t\t}\n\t\tif (props.environment !== undefined) updates.environment = props.environment\n\t\tif (props.metadata !== undefined) updates.metadata = props.metadata\n\t\thandle.update(updates)\n\t\t// theme/metadata compared by serialized identity since they're\n\t\t// objects; primitives use direct dep tracking.\n\t}, [\n\t\tprops.position,\n\t\tthemeJson,\n\t\tprops.title,\n\t\tprops.placeholder,\n\t\tprops.showEmailOption,\n\t\tprops.showScreenshotOption,\n\t\tprops.environment,\n\t\tmetadataJson,\n\t])\n\n\t// Identity: diff the resolved user by id + email + serialised traits.\n\t// Re-renders that pass the same logical user are no-ops at the\n\t// transport layer too (identifyIfChanged dedupes by fingerprint).\n\tconst userId = props.user?.id ?? null\n\tconst userEmail = props.user?.email ?? null\n\tconst userDisplayName = props.user?.displayName ?? null\n\tconst userTraitsJson = JSON.stringify(props.user?.traits ?? null)\n\tconst userIsNull = props.user === null\n\tuseEffect(() => {\n\t\tconst handle = handleRef.current\n\t\tif (!handle) return\n\t\t// `user: undefined` means \"not supplied, do nothing\". `user: null`\n\t\t// means \"logged out, rotate anonymousId\". We forward both as-is so\n\t\t// vanilla can disambiguate via the `'user' in next` check.\n\t\tif (props.user !== undefined) handle.update({ user: props.user })\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [userId, userEmail, userDisplayName, userTraitsJson, userIsNull])\n\n\treturn null\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/api.ts","../src/colorUtils.ts","../src/identity.ts","../src/plugin.ts","../src/validation.ts","../src/widgetCss.ts","../src/vanilla.ts","../src/react.tsx"],"names":[],"mappings":"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AAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;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","file":"react.js","sourcesContent":["// Shared types used by both the vanilla and React entry points.\n// Keep this file framework-free so the vanilla bundle never pulls react.\n\nexport type FeedbackRating = 1 | 2 | 3 | 4\n\nexport interface FeedbackMetadata {\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\ttimestamp: number\n}\n\nexport interface ScreenshotData {\n\tfileName: string\n\turl: string\n\tfileSize: number\n\twidth?: number\n\theight?: number\n\tmimeType: string\n}\n\nexport interface FeedbackSubmission {\n\tclientId: string\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tpageUrl: string\n\tpageTitle: string\n\treferrer?: string\n\tenvironment?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata?: Record<string, unknown>\n\t// Legacy gzipped + base64-encoded rrweb event stream. The pre-chunked\n\t// session-replay plugin attached this on submit. The chunked-upload\n\t// plugin (>= 0.4.0) does NOT set this — it ships events out-of-band\n\t// via the chunk endpoints and points at the resulting session replay\n\t// via `sessionReplayId` + `replayOffsetMs`. Kept on the wire one\n\t// release for backward compat with old SaaS deployments that only\n\t// know how to ingest the legacy field.\n\treplayEvents?: string\n\t// Pointer to a SessionReplay row created by the session-replay\n\t// plugin's chunked-upload pipeline, plus the offset within that\n\t// recording at submit time so the dashboard can deep-link.\n\tsessionReplayId?: string\n\treplayOffsetMs?: number\n}\n\nexport interface FeedbackData {\n\trating?: FeedbackRating\n\tcomment?: string\n\tuserEmail?: string\n\tscreenshots?: ScreenshotData[]\n\tmetadata: FeedbackMetadata\n}\n\n// Customer-supplied identity for the session-replay / identify pipeline.\n// Use the declarative form: pass `user` on the React widget (the SDK\n// diffs and auto-fires identify), or supply `getUser` on the vanilla\n// init (the SDK polls it at session start). An imperative `identify()`\n// call exists as an escape hatch only and is intentionally not\n// documented as the headline API.\nexport type UseroUserTraitValue = string | number | boolean | null\nexport type UseroUserTraits = Record<string, UseroUserTraitValue>\nexport interface UseroUser {\n\tid: string\n\temail?: string\n\tdisplayName?: string\n\ttraits?: UseroUserTraits\n}\n\nexport type WidgetPosition = 'right' | 'left'\n\nexport interface WidgetTheme {\n\tprimary: string\n\tbackground: string\n\ttext: string\n\tborder: string\n\tshadow: string\n}\n\n// Forward-declared to avoid a circular import. The plugin module imports\n// FeedbackSubmission from this file, so we can't import UseroPlugin back\n// up here without a cycle. Keeping the prop typed as an opaque object with\n// the minimal shape the widget actually inspects works fine for consumers.\nexport interface FeedbackWidgetProps {\n\tclientId: string\n\tposition?: WidgetPosition\n\ttheme?: Partial<WidgetTheme>\n\ttitle?: string\n\tplaceholder?: string\n\tshowEmailOption?: boolean\n\tshowScreenshotOption?: boolean\n\tenvironment?: string\n\tbaseUrl?: string\n\tmetadata?: Record<string, unknown>\n\tplugins?: ReadonlyArray<import('./plugin').UseroPlugin>\n\t// Declarative identity. React: pass the current user (or null on\n\t// logout) and the SDK auto-fires identify when the resolved id\n\t// transitions. Vanilla: pass a getter so the SDK can resolve user at\n\t// session start / chunk boundaries. Pass at most one. The SDK never\n\t// invokes both.\n\tuser?: UseroUser | null\n\tgetUser?: () => UseroUser | null | undefined\n\tonSubmit?: (feedback: FeedbackData) => void\n\tonError?: (error: Error) => void\n\tonOpen?: () => void\n\tonClose?: () => void\n}\n\nexport interface SubmissionResponse {\n\tsuccess: boolean\n\terror?: string\n\tid?: string\n\tmessage?: string\n\tdata?: unknown\n}\n\nexport const EMOJI_MAP: Record<FeedbackRating, string> = {\n\t1: '😞',\n\t2: '😐',\n\t3: '😊',\n\t4: '🤩',\n}\n\nexport const RATING_LABELS: Record<FeedbackRating, string> = {\n\t1: 'Needs work',\n\t2: \"It's okay\",\n\t3: 'Pretty good',\n\t4: 'Amazing!',\n}\n\nexport const EMOJI_BACKGROUNDS: Record<FeedbackRating, string> = {\n\t1: 'linear-gradient(135deg,#ff6b6b14,#ff6b6b1f)',\n\t2: 'linear-gradient(135deg,#9ca3af0f,#9ca3af1a)',\n\t3: 'linear-gradient(135deg,#3b82f614,#3b82f61f)',\n\t4: 'linear-gradient(135deg,#f59e0b14,#f59e0b1f)',\n}\n\nexport const DEFAULT_API_URL = 'https://usero.io'\n\nexport const DEFAULT_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#ffffff',\n\ttext: '#374151',\n\tborder: '#e5e7eb',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',\n}\n\nexport const DARK_THEME: WidgetTheme = {\n\tprimary: '#2563eb',\n\tbackground: '#1f2937',\n\ttext: '#f9fafb',\n\tborder: '#374151',\n\tshadow:\n\t\t'0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2)',\n}\n\nexport function mergeTheme(customTheme: Partial<WidgetTheme> = {}): WidgetTheme {\n\treturn { ...DEFAULT_THEME, ...customTheme }\n}\n","import {\n\tDEFAULT_API_URL,\n\ttype FeedbackSubmission,\n\ttype ScreenshotData,\n\ttype SubmissionResponse,\n} from './types'\n\ninterface JsonErrorBody {\n\terror?: string\n}\n\nfunction isJsonErrorBody(value: unknown): value is JsonErrorBody {\n\treturn typeof value === 'object' && value !== null && 'error' in value\n}\n\ninterface ScreenshotUploadResponseBody {\n\tsuccess: boolean\n\terror?: string\n\tscreenshot?: ScreenshotData\n}\n\nfunction parseScreenshotUploadBody(\n\tvalue: unknown,\n): ScreenshotUploadResponseBody {\n\tif (typeof value !== 'object' || value === null) {\n\t\treturn { success: false, error: 'Invalid response' }\n\t}\n\tconst obj = value as Record<string, unknown>\n\tconst success = obj.success === true\n\tconst error = typeof obj.error === 'string' ? obj.error : undefined\n\tconst rawShot = obj.screenshot\n\tlet screenshot: ScreenshotData | undefined\n\tif (typeof rawShot === 'object' && rawShot !== null) {\n\t\tconst s = rawShot as Record<string, unknown>\n\t\tif (\n\t\t\ttypeof s.fileName === 'string' &&\n\t\t\ttypeof s.url === 'string' &&\n\t\t\ttypeof s.fileSize === 'number' &&\n\t\t\ttypeof s.mimeType === 'string'\n\t\t) {\n\t\t\tscreenshot = {\n\t\t\t\tfileName: s.fileName,\n\t\t\t\turl: s.url,\n\t\t\t\tfileSize: s.fileSize,\n\t\t\t\tmimeType: s.mimeType,\n\t\t\t\twidth: typeof s.width === 'number' ? s.width : undefined,\n\t\t\t\theight: typeof s.height === 'number' ? s.height : undefined,\n\t\t\t}\n\t\t}\n\t}\n\treturn { success, error, screenshot }\n}\n\nexport class FeedbackApiClient {\n\tprivate baseUrl: string\n\n\tconstructor(baseUrl: string = DEFAULT_API_URL) {\n\t\tthis.baseUrl = baseUrl.replace(/\\/$/, '')\n\t}\n\n\tasync submitFeedback(data: FeedbackSubmission): Promise<SubmissionResponse> {\n\t\ttry {\n\t\t\tconst response = await fetch(`${this.baseUrl}/api/feedback`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\tAccept: 'application/json',\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify(data),\n\t\t\t\tsignal: AbortSignal.timeout(10000),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `HTTP ${response.status}: ${response.statusText}`\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData: unknown = await response.json()\n\t\t\t\t\tif (isJsonErrorBody(errorData) && typeof errorData.error === 'string') {\n\t\t\t\t\t\terrorMessage = errorData.error\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore JSON parse errors\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage)\n\t\t\t}\n\n\t\t\tconst result: unknown = await response.json()\n\t\t\tconst message =\n\t\t\t\ttypeof result === 'object' &&\n\t\t\t\tresult !== null &&\n\t\t\t\t'message' in result &&\n\t\t\t\ttypeof (result as { message: unknown }).message === 'string'\n\t\t\t\t\t? (result as { message: string }).message\n\t\t\t\t\t: 'Feedback submitted successfully'\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: result,\n\t\t\t\tmessage,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror:\n\t\t\t\t\terror instanceof Error ? error.message : 'An unexpected error occurred',\n\t\t\t}\n\t\t}\n\t}\n\n\tasync uploadScreenshot(\n\t\tfile: File,\n\t\tclientId: string,\n\t): Promise<ScreenshotData> {\n\t\tconst formData = new FormData()\n\t\tformData.append('screenshot', file)\n\t\tformData.append('clientId', clientId)\n\n\t\tconst response = await fetch(`${this.baseUrl}/api/screenshots`, {\n\t\t\tmethod: 'POST',\n\t\t\tbody: formData,\n\t\t\tsignal: AbortSignal.timeout(30000),\n\t\t})\n\n\t\tlet body: ScreenshotUploadResponseBody = { success: false }\n\t\ttry {\n\t\t\tconst raw: unknown = await response.json()\n\t\t\tbody = parseScreenshotUploadBody(raw)\n\t\t} catch {\n\t\t\t// fall through to error handling below\n\t\t}\n\n\t\tif (!response.ok || !body.success || !body.screenshot) {\n\t\t\tconst message =\n\t\t\t\tbody.error ?? `HTTP ${response.status}: ${response.statusText}`\n\t\t\tthrow new Error(message)\n\t\t}\n\n\t\treturn body.screenshot\n\t}\n\n\tping(): void {\n\t\tfetch(`${this.baseUrl}/api/ping`, {\n\t\t\tsignal: AbortSignal.timeout(5000),\n\t\t}).catch(() => {})\n\t}\n}\n","export function colorNameToHex(color: string): string {\n\tif (color.startsWith('#')) return color\n\tif (typeof document === 'undefined') return color\n\n\tconst canvas = document.createElement('canvas')\n\tconst ctx = canvas.getContext('2d')\n\tif (!ctx) return color\n\n\tctx.fillStyle = color\n\treturn ctx.fillStyle\n}\n\nexport function getGradientEnd(color: string): string {\n\tconst hex = colorNameToHex(color)\n\tif (!hex.startsWith('#') || hex.length < 7) return hex\n\tconst r = parseInt(hex.slice(1, 3), 16)\n\tconst g = parseInt(hex.slice(3, 5), 16)\n\tconst b = parseInt(hex.slice(5, 7), 16)\n\tconst shiftedR = Math.max(0, r - 60)\n\tconst shiftedG = Math.min(255, g + 40)\n\tconst shiftedB = Math.min(255, b + 20)\n\treturn `#${[shiftedR, shiftedG, shiftedB]\n\t\t.map(x => x.toString(16).padStart(2, '0'))\n\t\t.join('')}`\n}\n","// Identity layer for the Usero SDK.\n//\n// Two responsibilities:\n// 1. Mint and persist a stable per-browser `anonymousId` in localStorage\n// so cross-tab + cross-day replays from the same browser stitch\n// together server-side. Falls back to an in-memory id if storage is\n// blocked (sandboxed iframes, Safari Lockdown, full quota). Replay\n// still works in that case, you just lose stitching.\n// 2. Auto-fire POST /api/identify when the resolved user transitions\n// (null -> id, id -> id'). Deduped by an in-memory fingerprint so\n// re-renders with the same user are no-ops on the network.\n//\n// All storage access is wrapped in try/catch and gated behind a one-shot\n// init read. The hot path (replay chunk flush) never touches localStorage.\n\nconst ANON_STORAGE_KEY = 'usero:anonymous-id'\n// Reuse the EXACT key the session-replay plugin has always written\n// (`usero:session-replay:sdk-session-id`) so we adopt per-tab session ids\n// already living in customers' browsers instead of minting a fresh one.\n// Changing this would split a tab's existing replay from its user-test\n// linkage, so it must stay byte-for-byte identical to the replay plugin's\n// historical key.\nconst SDK_SESSION_STORAGE_KEY = 'usero:session-replay:sdk-session-id'\n\nlet cachedAnonymousId: string | null = null\nlet cachedSdkSessionId: string | null = null\n// Last resolved external user id, set by the identify pipeline so any\n// plugin can read the current identity without re-resolving the host's\n// `user` prop. Cleared on logout (anonymousId rotation).\nlet currentUserId: string | null = null\n// Wall-clock epoch (ms) when the session-replay recording started, as\n// published by the replay plugin. Lets other plugins (user-test) compute\n// an offset into the recording without importing the replay module. Null\n// until replay actually starts (or if replay is not loaded at all).\nlet replayStartMs: number | null = null\n// Fingerprint of the last identify we POSTed. Same SDK instance + same\n// resolved user + same traits = no-op. Cleared on logout (anonymousId\n// rotation).\nlet lastIdentifyFingerprint: string | null = null\n\nexport type UserTraitValue = string | number | boolean | null\nexport type UserTraits = Record<string, UserTraitValue>\n\nexport interface UseroUser {\n\tid: string\n\temail?: string\n\tdisplayName?: string\n\ttraits?: UserTraits\n}\n\nfunction generateRandomId(): string {\n\tif (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n\t\treturn crypto.randomUUID()\n\t}\n\tconst bytes = new Uint8Array(16)\n\tif (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n\t\tcrypto.getRandomValues(bytes)\n\t} else {\n\t\tfor (let i = 0; i < bytes.length; i += 1) bytes[i] = Math.floor(Math.random() * 256)\n\t}\n\tlet out = ''\n\tfor (const b of bytes) out += b.toString(16).padStart(2, '0')\n\treturn out\n}\n\nfunction safeReadLocalStorage(key: string): string | null {\n\tif (typeof window === 'undefined') return null\n\ttry {\n\t\treturn window.localStorage?.getItem(key) ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction safeWriteLocalStorage(key: string, value: string): void {\n\tif (typeof window === 'undefined') return\n\ttry {\n\t\twindow.localStorage?.setItem(key, value)\n\t} catch {\n\t\t// Sandboxed iframe / Safari Lockdown / quota. Fall back to memory.\n\t}\n}\n\nfunction safeReadSessionStorage(key: string): string | null {\n\tif (typeof window === 'undefined') return null\n\ttry {\n\t\treturn window.sessionStorage?.getItem(key) ?? null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction safeWriteSessionStorage(key: string, value: string): void {\n\tif (typeof window === 'undefined') return\n\ttry {\n\t\twindow.sessionStorage?.setItem(key, value)\n\t} catch {\n\t\t// Sandboxed iframe / Safari Lockdown / quota. Fall back to memory.\n\t}\n}\n\n/**\n * Returns the stable per-browser anonymousId. Reads localStorage at most\n * once per SDK instance. Subsequent calls hit the in-memory cache, so\n * even hot paths (per-event in replay) are safe to call this.\n */\nexport function getOrMintAnonymousId(): string {\n\tif (cachedAnonymousId) return cachedAnonymousId\n\tconst existing = safeReadLocalStorage(ANON_STORAGE_KEY)\n\t// Sanity filter, not strict validation. We accept anything that looks\n\t// plausibly like an id (>=8 alphanumeric-or-hyphen) so older SDK\n\t// versions that wrote a slightly different shape still stitch. Fresh\n\t// mint is cheap, so we only reject obvious garbage; tightening this\n\t// would force rotation in customer browsers and split otherwise-good\n\t// sibling-session attribution.\n\tif (existing && /^[a-z0-9-]{8,}$/i.test(existing)) {\n\t\tcachedAnonymousId = existing\n\t\treturn existing\n\t}\n\tconst id = generateRandomId()\n\tsafeWriteLocalStorage(ANON_STORAGE_KEY, id)\n\tcachedAnonymousId = id\n\treturn id\n}\n\n/**\n * Rotate the anonymousId. Called on logout (user transitions from a\n * known id to null) so the next anonymous trail does not get auto-merged\n * into the previous person on the next identify().\n */\nexport function rotateAnonymousId(): string {\n\tconst id = generateRandomId()\n\tcachedAnonymousId = id\n\tsafeWriteLocalStorage(ANON_STORAGE_KEY, id)\n\tlastIdentifyFingerprint = null\n\tcurrentUserId = null\n\treturn id\n}\n\n/**\n * Returns the stable per-tab sdkSessionId. Core-owned so every plugin\n * (replay, user-test, future feedback linkage) reads the SAME id for a\n * given tab. Reads sessionStorage at most once per SDK instance; later\n * calls hit the in-memory cache.\n *\n * Backward compat: reuses the `usero:sdk-session-id` key the replay\n * plugin has always written, and the same loose sanity filter, so an\n * id minted by an older replay-only SDK build is adopted as-is rather\n * than rotated (which would split a tab's replay from its user-test).\n */\nexport function getOrMintSdkSessionId(): string {\n\tif (cachedSdkSessionId) return cachedSdkSessionId\n\tconst existing = safeReadSessionStorage(SDK_SESSION_STORAGE_KEY)\n\tif (existing && /^[a-z0-9-]{8,}$/i.test(existing)) {\n\t\tcachedSdkSessionId = existing\n\t\treturn existing\n\t}\n\tconst id = generateRandomId()\n\tsafeWriteSessionStorage(SDK_SESSION_STORAGE_KEY, id)\n\tcachedSdkSessionId = id\n\treturn id\n}\n\n/**\n * The current resolved external user id, or null if no identify has\n * succeeded this session (or after logout). Set by the identify\n * pipeline; read by plugins that want the current identity without\n * re-resolving the host's `user` prop.\n */\nexport function getCurrentUserId(): string | null {\n\treturn currentUserId\n}\n\n/**\n * Published by the session-replay plugin when its recording starts.\n * Other plugins read it via `getReplayStartMs()` to compute an offset\n * into the recording. No-op duplicate publishes keep the first value so\n * the offset stays anchored to the true recording start.\n */\nexport function publishReplayStartMs(epochMs: number): void {\n\tif (replayStartMs === null) replayStartMs = epochMs\n}\n\n/**\n * The wall-clock epoch (ms) when session-replay started, or null if\n * replay never started this session (plugin not loaded, or sampled out).\n * Consumers degrade gracefully when null: ship the sdkSessionId linkage\n * key anyway and omit the offset.\n */\nexport function getReplayStartMs(): number | null {\n\treturn replayStartMs\n}\n\nfunction fingerprintUser(anonymousId: string, user: UseroUser): string {\n\t// Stable across re-renders: keys sorted, traits canonicalised. Cheap\n\t// enough on the hot path (only runs when the SDK thinks the user might\n\t// have changed, never per-event).\n\tconst traits = user.traits ?? {}\n\tconst keys = Object.keys(traits).sort()\n\tconst canonical: Array<[string, UserTraitValue]> = keys.map(k => [k, traits[k] ?? null])\n\treturn JSON.stringify([anonymousId, user.id, user.email ?? null, user.displayName ?? null, canonical])\n}\n\nexport interface IdentifyTransport {\n\tapiUrl: string\n\tclientId: string\n}\n\n/**\n * POST to /api/identify if the (anonymousId, user) fingerprint differs\n * from the last call. Returns true if a network request actually fired.\n * Never throws; failures are best-effort and the caller (the widget /\n * provider) should not treat them as errors.\n *\n * Tab-unload safety: if the page is hidden when this fires (visibility\n * 'hidden' or a pagehide handler), we route the payload through\n * `navigator.sendBeacon` so the request survives unload. Otherwise we\n * use a normal fetch and only cache the fingerprint when the server\n * confirms `accepted: true`. A 200 `{ accepted: false }` (e.g.\n * `unknown_client` for a clientId that becomes valid mid-session) is\n * treated as retryable so the next call re-fires.\n */\nexport async function identifyIfChanged(transport: IdentifyTransport, user: UseroUser): Promise<boolean> {\n\tconst anonymousId = getOrMintAnonymousId()\n\t// Make the resolved id readable by other plugins immediately, even\n\t// before the network round-trip resolves. This is the identity the\n\t// host just told us about; the POST below is best-effort persistence.\n\tcurrentUserId = user.id\n\tconst fp = fingerprintUser(anonymousId, user)\n\tif (fp === lastIdentifyFingerprint) return false\n\n\tconst url = `${transport.apiUrl.replace(/\\/$/, '')}/api/identify`\n\t// Body must stay under the browser's keepalive / sendBeacon cap\n\t// (~64KB across most engines) when this fires on pagehide. That\n\t// transitively caps trait payload size; in practice traits should be\n\t// small typed scalars, not blobs.\n\tconst body = JSON.stringify({\n\t\tclientId: transport.clientId,\n\t\tanonymousId,\n\t\texternalUserId: user.id,\n\t\temail: user.email,\n\t\tdisplayName: user.displayName,\n\t\ttraits: user.traits,\n\t})\n\n\t// If the document is hidden (pagehide / tab close in flight), best-effort\n\t// hand off to sendBeacon. We don't get a response back, so we optimistically\n\t// cache the fingerprint to avoid re-firing on the next page; the server is\n\t// idempotent if the page reload re-runs identify with the same payload.\n\tif (\n\t\ttypeof document !== 'undefined' &&\n\t\tdocument.visibilityState === 'hidden' &&\n\t\ttypeof navigator !== 'undefined' &&\n\t\ttypeof navigator.sendBeacon === 'function'\n\t) {\n\t\ttry {\n\t\t\tconst blob = new Blob([body], { type: 'application/json' })\n\t\t\t// sendBeacon returns false when the user agent refuses to queue\n\t\t\t// the request (size cap, or historically Safari rejecting\n\t\t\t// non-CORS-simple content types). Modern Safari accepts\n\t\t\t// application/json, but we keep a keepalive-fetch fallback so an\n\t\t\t// older WebKit that rejects the beacon still ships the identify.\n\t\t\tif (navigator.sendBeacon(url, blob)) {\n\t\t\t\tlastIdentifyFingerprint = fp\n\t\t\t\treturn true\n\t\t\t}\n\t\t} catch {\n\t\t\t// fall through to keepalive fetch below\n\t\t}\n\t}\n\n\ttry {\n\t\tconst res = await fetch(url, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody,\n\t\t\t// keepalive lets the request survive a tab-close mid-flight on\n\t\t\t// browsers that support it; sendBeacon above is the primary path.\n\t\t\tkeepalive: true,\n\t\t})\n\t\tif (!res.ok) return true\n\t\t// Parse the response: a 200 with `accepted: false` (e.g. unknown\n\t\t// client) is retryable. Only cache the fingerprint when the server\n\t\t// confirmed it actually stored the identity.\n\t\ttry {\n\t\t\tconst json = (await res.json()) as { accepted?: unknown }\n\t\t\tif (json && json.accepted === true) lastIdentifyFingerprint = fp\n\t\t} catch {\n\t\t\t// Server returned 2xx but unparseable body: don't cache, let the\n\t\t\t// next call retry.\n\t\t}\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Clear identify state and rotate anonymousId. Called when the resolved\n * user transitions from a known id to null (logout). The next anonymous\n * trail will get a fresh anonymousId so it does not merge into the\n * previous person.\n */\nexport function handleLogout(): void {\n\trotateAnonymousId()\n}\n\n// Test hooks (not exported from the package public surface).\nexport const __test__ = {\n\tANON_STORAGE_KEY,\n\tSDK_SESSION_STORAGE_KEY,\n\tresetIdentityState: (): void => {\n\t\tcachedAnonymousId = null\n\t\tcachedSdkSessionId = null\n\t\tcurrentUserId = null\n\t\treplayStartMs = null\n\t\tlastIdentifyFingerprint = null\n\t},\n}\n","// Plugin contract for the Usero widget.\n//\n// Plugins are opt-in modules that hook into the widget lifecycle to enrich\n// feedback submissions or react to widget events. They live in subpath\n// exports (e.g. `@usero/sdk/plugins/session-replay`) so consumers who don't\n// import them pay zero bundle cost.\n//\n// Design rules:\n// 1. The plugin contract MUST stay framework-free (no React types).\n// 2. `onInit` runs fire-and-forget so a slow plugin never blocks the\n// widget from rendering. Plugins that need to be ready before the\n// first interaction are responsible for their own gating internally.\n// 3. `onFeedbackSubmit` is awaited and its return value is merged into\n// the outgoing payload. Top-level keys are shallow-merged (later\n// plugins win wholesale); `metadata` is deep-merged one level so two\n// plugins can both contribute keys without clobbering each other.\n// Plugins MUST return quickly (a few hundred ms at most) or risk users\n// abandoning the submit.\n// 4. Plugin errors are caught and logged; they never block a submission.\n\nimport type { FeedbackSubmission } from './types'\n\nexport interface PluginLogger {\n\tdebug: (...args: unknown[]) => void\n\tinfo: (...args: unknown[]) => void\n\twarn: (...args: unknown[]) => void\n\terror: (...args: unknown[]) => void\n}\n\nexport interface PluginContext {\n\tclientId: string\n\tbaseUrl: string\n\t// Per-plugin scratch store. Plugins can stash state across hook calls\n\t// without leaking into globals. The key is the plugin's `name`.\n\tgetStore: <T>() => T | undefined\n\tsetStore: <T>(value: T) => void\n\tlogger: PluginLogger\n\t// Re-resolve the current user via the host's `user` prop or `getUser`\n\t// callback and run it through the identify dedupe pipeline. Plugins\n\t// that run independently of widget interaction (e.g. session-replay\n\t// for replay-only customers who never open the widget) should call\n\t// this at their own boundaries (session start, chunk flush, etc.)\n\t// so mid-session login is visible server-side. The fingerprint\n\t// dedupe in identity.ts makes repeated calls effectively free when\n\t// nothing changed.\n\tresolveUser?: () => void\n\t// ---- Core-owned cross-cutting identity --------------------------------\n\t// These read the single source of truth in identity.ts so every plugin\n\t// (replay, user-test, future feedback linkage) sees the SAME ids without\n\t// importing each other. All optional so older hosts and test doubles that\n\t// predate this surface still satisfy the contract; plugins must tolerate\n\t// their absence and fall back gracefully.\n\t//\n\t// Per-tab session id (sessionStorage `usero:session-replay:sdk-session-id`).\n\t// The robust linkage key: the server resolves a SessionReplay by\n\t// (clientId + sdkSessionId), so any plugin that wants to point at the\n\t// tab's recording sends this.\n\tgetSdkSessionId?: () => string\n\t// Per-browser id (localStorage `usero:anonymous-id`) for cross-session\n\t// stitching.\n\tgetAnonymousId?: () => string\n\t// Current resolved external user id, or null before identify / after\n\t// logout.\n\tgetUserId?: () => string | null\n\t// Wall-clock epoch (ms) when session-replay started, or null if replay\n\t// is not active. Consumers compute an offset into the recording from\n\t// this; when null, they degrade (send the sdkSessionId key, omit offset).\n\tgetReplayStartMs?: () => number | null\n\t// Publish the replay recording start epoch into the core so other\n\t// plugins can compute offsets. Only the replay plugin should call this.\n\tpublishReplayStartMs?: (epochMs: number) => void\n}\n\nexport interface UseroPlugin {\n\t// Stable, unique identifier. Used as the store key and in log prefixes.\n\t// Convention: lowercase kebab-case (e.g. `session-replay`).\n\tname: string\n\tonInit?: (ctx: PluginContext) => void | Promise<void>\n\t// Returns a partial submission patch that gets merged into the outgoing\n\t// payload. Top-level keys are shallow-merged (later plugins win on\n\t// conflict); `metadata` is deep-merged one level so multiple plugins\n\t// can each attach their own metadata keys without clobbering. Return\n\t// `undefined` to contribute nothing.\n\tonFeedbackSubmit?: (\n\t\tctx: PluginContext,\n\t\tsubmission: FeedbackSubmission,\n\t) => Promise<Partial<FeedbackSubmission> | undefined> | Partial<FeedbackSubmission> | undefined\n\tonDestroy?: (ctx: PluginContext) => void\n}\n\nexport function createPluginLogger(name: string): PluginLogger {\n\tconst prefix = `[usero:${name}]`\n\treturn {\n\t\tdebug: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.debug(prefix, ...args)\n\t\t},\n\t\tinfo: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.info(prefix, ...args)\n\t\t},\n\t\twarn: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.warn(prefix, ...args)\n\t\t},\n\t\terror: (...args) => {\n\t\t\tif (typeof console !== 'undefined') console.error(prefix, ...args)\n\t\t},\n\t}\n}\n","import type { FeedbackSubmission } from './types'\n\nexport interface ValidationResult {\n\tisValid: boolean\n\terrors: string[]\n}\n\nexport function validateFeedbackSubmission(\n\tdata: Partial<FeedbackSubmission>,\n): ValidationResult {\n\tconst errors: string[] = []\n\tconst hasRating = data.rating != null\n\tconst hasComment = !!data.comment?.trim()\n\n\tif (!hasRating && !hasComment) {\n\t\terrors.push('Add rating or comment')\n\t}\n\tif (hasRating && data.rating !== undefined && ![1, 2, 3, 4].includes(data.rating)) {\n\t\terrors.push('Invalid rating')\n\t}\n\tif (hasComment && data.comment !== undefined) {\n\t\tif (data.comment.length > 1000) {\n\t\t\terrors.push('Comment too long')\n\t\t}\n\t\tif (/<script[^>]*>.*?<\\/script>/gi.test(data.comment)) {\n\t\t\terrors.push('Invalid comment')\n\t\t}\n\t}\n\n\treturn {\n\t\tisValid: errors.length === 0,\n\t\terrors,\n\t}\n}\n","// CSS used by both entry points.\n//\n// React entry injects it once into <head> via injectFeedbackCSS().\n// Vanilla entry injects it inside a shadow root, so host page styles\n// can't bleed in and our class names can't collide with the host.\n\nexport const FEEDBACK_CSS = `\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.fb-es {\n display: flex;\n justify-content: center;\n gap: 12px;\n padding-bottom: 8px;\n}\n\n.fb-ec {\n border-radius: 16px;\n padding: 0 5px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n border: 3px solid transparent;\n cursor: pointer;\n text-align: center;\n}\n\n.fb-ec--sel {\n border-color: #2563eb;\n transform: scale(1.05);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.2);\n}\n\n.fb-ec--hov:not(.fb-ec--sel) {\n transform: scale(1.05);\n}\n\n.fb-eb {\n background: transparent;\n border: none;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n width: 100%;\n padding: 0;\n transition: all 200ms ease;\n}\n\n.fb-ei {\n font-size: 36px;\n transition: transform 200ms ease;\n}\n\n.fb-ei--hov {\n transform: scale(1.1);\n}\n\n.fb-el {\n font-size: 13px;\n font-weight: 600;\n color: currentColor;\n line-height: 1.2;\n}\n\n.fb-hdr {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-bottom: 4px;\n margin-bottom: 10px;\n}\n\n.fb-msg {\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n margin-bottom: 8px;\n border-radius: 6px;\n}\n\n.fb-msg--header {\n font-size: 12px;\n padding: 4px 8px;\n margin-bottom: 0;\n margin-left: auto;\n margin-right: 8px;\n}\n\n.fb-msg--ok {\n background-color: #f0fdf4;\n border: 1px solid #bbf7d0;\n color: #16a34a;\n}\n\n.fb-msg--err {\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n color: #dc2626;\n}\n\n.fb-sub {\n width: 100%;\n padding: 12px 24px;\n border: none;\n border-radius: 12px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n transition: all 200ms ease;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.fb-sub--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-spin {\n width: 16px;\n height: 16px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n.fb-cnt {\n padding: 20px 24px 16px;\n overflow: auto;\n max-height: calc(90vh - 48px);\n}\n\n.fb-ttl {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n}\n\n.fb-ta {\n width: 100%;\n min-height: 80px;\n padding: 10px;\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n resize: vertical;\n transition: border-color 150ms ease;\n margin-bottom: 2px;\n box-sizing: border-box;\n}\n\n.fb-toolrow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n.fb-charcount {\n font-size: 12px;\n margin-left: auto;\n text-align: right;\n}\n\n.fb-charcount--low {\n color: #dc2626;\n}\n\n.fb-email {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 10px;\n}\n\n.fb-email-lbl {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n}\n\n.fb-email-cb {\n margin: 0;\n cursor: pointer;\n}\n\n.fb-email-inp {\n width: 100%;\n padding: 8px 12px;\n border-radius: 4px;\n font-size: 14px;\n outline: none;\n transition: border-color 150ms ease;\n box-sizing: border-box;\n}\n\n.fb-btn {\n position: fixed;\n width: 50px;\n height: 50px;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n transition: all 300ms cubic-bezier(0.68, -0.55, 0.265, 1.55);\n z-index: 9998;\n color: #ffffff;\n top: 50%;\n transform: translateY(-50%);\n box-shadow: 0 4px 15px rgba(37, 99, 235, 0.3);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-btn--right {\n right: -25px;\n border-radius: 40px 0 0 40px;\n padding-right: 8px;\n box-shadow: -4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--left {\n left: -25px;\n border-radius: 0 40px 40px 0;\n padding-left: 8px;\n box-shadow: 4px 0 15px rgba(37, 99, 235, 0.3);\n}\n\n.fb-btn--right.fb-btn--open {\n right: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-btn--left.fb-btn--open {\n left: -15px;\n transform: translateY(-50%) scale(1.05);\n}\n\n.fb-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0, 0, 0, 0.3);\n transition: opacity 300ms ease;\n z-index: 9999;\n backdrop-filter: blur(8px);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl-base {\n position: fixed;\n top: 10vh;\n width: 400px;\n max-width: 90vw;\n max-height: 60vh;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n transition: transform 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n overflow-x: hidden;\n border-radius: 16px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-sizing: border-box;\n}\n\n.fb-pnl--right { right: 0; }\n.fb-pnl--right.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--right.fb-pnl--closed { transform: translateX(100%); }\n\n.fb-pnl--left { left: 0; }\n.fb-pnl--left.fb-pnl--open { transform: translateX(0px); }\n.fb-pnl--left.fb-pnl--closed { transform: translateX(-100%); }\n\n.fb-close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n opacity: 0.7;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: background-color 150ms ease;\n}\n\n.fb-up {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 8px;\n}\n\n.fb-upb {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n align-self: flex-start;\n padding: 8px 12px;\n border-radius: 8px;\n background: transparent;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background-color 150ms ease, opacity 150ms ease;\n font-family: inherit;\n}\n\n.fb-upb:hover:not(.fb-upb--dis) {\n background-color: rgba(37, 99, 235, 0.06);\n}\n\n.fb-upb--dis {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.fb-ups {\n width: 12px;\n height: 12px;\n border: 2px solid transparent;\n border-top: 2px solid currentColor;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n display: inline-block;\n}\n\n.fb-up-extras {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.fb-upe {\n font-size: 12px;\n color: #dc2626;\n}\n\n.fb-ss {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.fb-sp {\n position: relative;\n width: 64px;\n height: 64px;\n border-radius: 6px;\n overflow: hidden;\n border: 1px solid rgba(0, 0, 0, 0.08);\n}\n\n.fb-si {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.fb-sr {\n position: absolute;\n top: 2px;\n right: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: rgba(0, 0, 0, 0.65);\n color: #fff;\n font-size: 11px;\n line-height: 1;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n}\n\n.fb-sr:hover {\n background: rgba(0, 0, 0, 0.85);\n}\n\n.fb-sl {\n font-size: 11px;\n opacity: 0.6;\n}\n\n@media (max-width: 768px) {\n .fb-pnl-base {\n width: 100% !important;\n max-width: none !important;\n top: 4vh !important;\n max-height: 92vh !important;\n }\n .fb-cnt { padding: 16px 18px 14px !important; max-height: calc(100vh - 40px) !important; }\n .fb-ta { font-size: 16px !important; min-height: 64px !important; }\n .fb-ttl { font-size: 18px !important; }\n .fb-ei { font-size: 24px !important; }\n .fb-el { font-size: 11px !important; }\n .fb-sub { padding: 12px 20px !important; font-size: 16px !important; }\n}\n`\n\nexport function injectFeedbackCSS(): void {\n\tif (typeof document === 'undefined') return\n\tconst styleId = 'usero-feedback-widget-css'\n\tif (document.getElementById(styleId)) return\n\tconst style = document.createElement('style')\n\tstyle.id = styleId\n\tstyle.textContent = FEEDBACK_CSS\n\tdocument.head.appendChild(style)\n}\n","// Framework-free Usero widget. Renders into a shadow root attached to a\n// container <div> on document.body so host page styles cannot bleed in\n// and our class names cannot collide with the host's.\n//\n// API:\n// const widget = initUseroFeedbackWidget({ clientId: '...' })\n// widget.destroy()\n//\n// The endpoint and request shape match the React widget exactly so a\n// feedback row created here is indistinguishable from one created via React.\n\nimport { FeedbackApiClient } from './api'\nimport { getGradientEnd } from './colorUtils'\nimport {\n\tgetCurrentUserId,\n\tgetOrMintAnonymousId,\n\tgetOrMintSdkSessionId,\n\tgetReplayStartMs,\n\thandleLogout as identityHandleLogout,\n\tidentifyIfChanged,\n\tpublishReplayStartMs,\n} from './identity'\nimport {\n\tcreatePluginLogger,\n\ttype PluginContext,\n\ttype UseroPlugin,\n} from './plugin'\nimport { DEFAULT_API_URL, type UseroUser } from './types'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tEMOJI_BACKGROUNDS,\n\tEMOJI_MAP,\n\ttype FeedbackData,\n\ttype FeedbackRating,\n\ttype FeedbackSubmission,\n\ttype FeedbackWidgetProps,\n\tmergeTheme,\n\tRATING_LABELS,\n\ttype ScreenshotData,\n\ttype WidgetPosition,\n\ttype WidgetTheme,\n} from './types'\nimport { validateFeedbackSubmission } from './validation'\nimport { FEEDBACK_CSS } from './widgetCss'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\n\n// Pick the base theme to merge user overrides onto, based on the OS color\n// scheme. Defaults to dark when matchMedia is unavailable (SSR, old browsers)\n// or when neither dark nor light is explicitly preferred.\nfunction resolveBaseTheme(): WidgetTheme {\n\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n\t\treturn DARK_THEME\n\t}\n\tif (window.matchMedia('(prefers-color-scheme: dark)').matches) return DARK_THEME\n\tif (window.matchMedia('(prefers-color-scheme: light)').matches) return DEFAULT_THEME\n\treturn DARK_THEME\n}\n\n// Resolve the effective theme. If the caller passed a partial theme, it wins\n// per-key over the OS-resolved base. If they passed nothing, we just use the\n// OS-resolved base directly.\nexport function resolveTheme(userTheme: Partial<WidgetTheme> | undefined): WidgetTheme {\n\tconst base = resolveBaseTheme()\n\tif (!userTheme) return base\n\treturn { ...base, ...userTheme }\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type {\n\tPluginContext,\n\tPluginLogger,\n\tUseroPlugin,\n} from './plugin'\n\nexport interface UseroWidgetHandle {\n\tdestroy: () => void\n\topen: () => void\n\tclose: () => void\n\t// Hot-swap any subset of props EXCEPT `clientId` and `baseUrl`. Changing\n\t// those requires destroy + re-init (the API client is bound to baseUrl,\n\t// and clientId is the identity of the widget). Callers (e.g. the React\n\t// wrapper) typically route callbacks through this so identity changes on\n\t// re-render don't force a tear-down.\n\tupdate: (next: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>>) => void\n\t// Imperative identify(). Documented as a fallback for setups that\n\t// cannot expose user state via the declarative `user` prop or\n\t// `getUser` getter. Internally just routes through the same dedupe\n\t// pipeline as the declarative path.\n\tidentify: (user: UseroUser | null) => void\n\t// Resolves once every plugin's `onInit` promise has settled (fulfilled\n\t// OR rejected). Intended for end-to-end tests and dogfooding scripts\n\t// that want to trigger a synthetic submit only after plugins are live.\n\t// Plugins with synchronous `onInit` make this resolve on the next\n\t// microtask. If no plugins are registered, it resolves immediately.\n\twhenReady: () => Promise<void>\n}\n\nconst EMAIL_STORAGE_KEY = 'feedback_user_email'\n\nfunction escapeHtml(value: string): string {\n\treturn value.replace(/[&<>\"']/g, ch => {\n\t\tswitch (ch) {\n\t\t\tcase '&':\n\t\t\t\treturn '&'\n\t\t\tcase '<':\n\t\t\t\treturn '<'\n\t\t\tcase '>':\n\t\t\t\treturn '>'\n\t\t\tcase '\"':\n\t\t\t\treturn '"'\n\t\t\tcase \"'\":\n\t\t\t\treturn '''\n\t\t\tdefault:\n\t\t\t\treturn ch\n\t\t}\n\t})\n}\n\n// Merge plugin onFeedbackSubmit patches into a base submission.\n//\n// Top-level keys: shallow-merge, later patches win wholesale.\n// `metadata`: deep-merge one level. Earlier keys are preserved when later\n// patches don't set them; later keys win on conflict. This means two\n// plugins can both contribute `metadata: { ... }` without either erasing\n// the other's keys.\nexport function mergePluginPatches(\n\tbase: FeedbackSubmission,\n\tpatches: ReadonlyArray<Partial<FeedbackSubmission> | undefined>,\n): FeedbackSubmission {\n\tlet result: FeedbackSubmission = base\n\tfor (const patch of patches) {\n\t\tif (!patch || typeof patch !== 'object') continue\n\t\tconst { metadata: patchMetadata, ...rest } = patch\n\t\tresult = { ...result, ...rest }\n\t\tif (patchMetadata && typeof patchMetadata === 'object') {\n\t\t\tresult.metadata = {\n\t\t\t\t...(result.metadata ?? {}),\n\t\t\t\t...patchMetadata,\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\nfunction readStoredEmail(): string {\n\tif (typeof window === 'undefined') return ''\n\ttry {\n\t\treturn window.localStorage.getItem(EMAIL_STORAGE_KEY) ?? ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\nfunction writeStoredEmail(email: string): void {\n\ttry {\n\t\twindow.localStorage.setItem(EMAIL_STORAGE_KEY, email)\n\t} catch {\n\t\t// ignore\n\t}\n}\n\nexport function initUseroFeedbackWidget(\n\tprops: FeedbackWidgetProps,\n): UseroWidgetHandle {\n\tif (typeof document === 'undefined') {\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t\tidentify: () => {},\n\t\t}\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\tif (!clientId || clientId.length < 3) {\n\t\tconst err = new Error('Invalid config. Contact admin.')\n\t\tprops.onError?.(err)\n\t\treturn {\n\t\t\tdestroy: () => {},\n\t\t\topen: () => {},\n\t\t\tclose: () => {},\n\t\t\tupdate: () => {},\n\t\t\twhenReady: () => Promise.resolve(),\n\t\t\tidentify: () => {},\n\t\t}\n\t}\n\n\t// Mutable view of every prop that can be hot-swapped via update(). Read\n\t// these at render time, never destructure into local const above the\n\t// render closures or you'll capture stale values.\n\tlet position: WidgetPosition = props.position ?? 'right'\n\tlet userThemeOverride: Partial<WidgetTheme> | undefined = props.theme\n\tlet theme: WidgetTheme = resolveTheme(userThemeOverride)\n\tlet title: string = props.title ?? 'Share Feedback'\n\tlet placeholder: string = props.placeholder ?? 'Tell us what you think... (optional)'\n\tlet showEmailOption: boolean = props.showEmailOption ?? true\n\tlet showScreenshotOption: boolean = props.showScreenshotOption ?? true\n\tlet environment: string | undefined = props.environment\n\tlet metadata: Record<string, unknown> | undefined = props.metadata\n\tlet onSubmit: FeedbackWidgetProps['onSubmit'] = props.onSubmit\n\tlet onError: FeedbackWidgetProps['onError'] = props.onError\n\tlet onOpen: FeedbackWidgetProps['onOpen'] = props.onOpen\n\tlet onClose: FeedbackWidgetProps['onClose'] = props.onClose\n\tlet getUserFn: FeedbackWidgetProps['getUser'] = props.getUser\n\t// Last `user` prop seen via init or update(). When set (including\n\t// explicit null for logout), it wins over getUserFn on re-resolve.\n\t// `undefined` means \"no `user` prop ever supplied; defer to getUser\".\n\tlet currentUserProp: UseroUser | null | undefined = props.user\n\n\tconst apiClient = new FeedbackApiClient(baseUrl)\n\tconst identifyTransport = { apiUrl: baseUrl ?? DEFAULT_API_URL, clientId }\n\n\t// Track the last id the SDK has seen so we can detect logout\n\t// (id -> null) and rotate the anonymousId. Identify dedupe inside\n\t// identifyIfChanged via a fingerprint guarantees re-runs with the same\n\t// user never POST. We also short-circuit BEFORE calling it when the\n\t// trait object is reference-identical, which only catches hosts that\n\t// memoise their traits object; the common React case of a fresh\n\t// `{ ... }` literal per render falls through to the fingerprint\n\t// dedupe, which is cheap (one stringify, no network) so this is fine.\n\tlet lastUserId: string | null = null\n\tlet lastTraitsRef: UseroUser['traits'] | undefined\n\tlet lastEmail: string | undefined\n\tlet lastDisplayName: string | undefined\n\n\tfunction applyResolvedUser(user: UseroUser | null | undefined): void {\n\t\tconst next = user ?? null\n\t\tif (next) {\n\t\t\tconst unchanged =\n\t\t\t\tnext.id === lastUserId &&\n\t\t\t\tnext.traits === lastTraitsRef &&\n\t\t\t\tnext.email === lastEmail &&\n\t\t\t\tnext.displayName === lastDisplayName\n\t\t\tif (unchanged) return\n\t\t\tvoid identifyIfChanged(identifyTransport, next)\n\t\t\tlastUserId = next.id\n\t\t\tlastTraitsRef = next.traits\n\t\t\tlastEmail = next.email\n\t\t\tlastDisplayName = next.displayName\n\t\t} else if (lastUserId !== null) {\n\t\t\t// Logout transition. Rotate anonymousId so the next anonymous\n\t\t\t// trail doesn't get auto-merged into the previous person on\n\t\t\t// the next identify().\n\t\t\tidentityHandleLogout()\n\t\t\tlastUserId = null\n\t\t\tlastTraitsRef = undefined\n\t\t\tlastEmail = undefined\n\t\t\tlastDisplayName = undefined\n\t\t}\n\t}\n\n\tfunction resolveAndApplyGetUser(): void {\n\t\tif (!getUserFn) return\n\t\ttry {\n\t\t\tapplyResolvedUser(getUserFn() ?? null)\n\t\t} catch {\n\t\t\t// getUser threw; leave the resolved user as it was. Do not\n\t\t\t// rotate, do not fire identify. A throwing getter likely means\n\t\t\t// the host app's auth context is mid-render.\n\t\t}\n\t}\n\n\t// Initial resolve: prefer the imperative `user` prop, fall back to\n\t// the `getUser` callback. Both are safe to call here; we just don't\n\t// fire identify when both are absent.\n\tif (props.user !== undefined) {\n\t\tapplyResolvedUser(props.user)\n\t} else if (getUserFn) {\n\t\tresolveAndApplyGetUser()\n\t}\n\n\t// Plugin registry. Each plugin gets its own context with a private store.\n\t// `onInit` is fired non-blocking so a slow plugin can't delay the first\n\t// paint. Errors are caught so a misbehaving plugin can't tear the widget\n\t// down or block submissions.\n\tconst pluginList: ReadonlyArray<UseroPlugin> = props.plugins ?? []\n\tconst pluginStores = new Map<string, unknown>()\n\tconst pluginContexts = new Map<string, PluginContext>()\n\t// Tracks every onInit's settlement so `whenReady()` can resolve only\n\t// after all plugins have finished initializing. Synchronous onInits\n\t// resolve on the next microtask via Promise.resolve().\n\tconst initPromises: Promise<void>[] = []\n\tfor (const plugin of pluginList) {\n\t\tconst ctx: PluginContext = {\n\t\t\tclientId,\n\t\t\tbaseUrl: baseUrl ?? DEFAULT_API_URL,\n\t\t\tlogger: createPluginLogger(plugin.name),\n\t\t\tgetStore: <T,>() => pluginStores.get(plugin.name) as T | undefined,\n\t\t\tsetStore: <T,>(value: T) => {\n\t\t\t\tpluginStores.set(plugin.name, value)\n\t\t\t},\n\t\t\t// Expose the same user-resolution path the widget uses, so plugins\n\t\t\t// (e.g. session-replay for replay-only installs that never open the\n\t\t\t// widget) can re-poll user state at their own boundaries. Prefers\n\t\t\t// the imperative `user` prop when set, falls back to `getUser`.\n\t\t\tresolveUser: () => {\n\t\t\t\tif (destroyed) return\n\t\t\t\tif (currentUserProp !== undefined) {\n\t\t\t\t\tapplyResolvedUser(currentUserProp)\n\t\t\t\t} else {\n\t\t\t\t\tresolveAndApplyGetUser()\n\t\t\t\t}\n\t\t\t},\n\t\t\t// Core-owned cross-cutting identity. Every plugin reads the same\n\t\t\t// source of truth in identity.ts, so user-test and session-replay\n\t\t\t// agree on the per-tab sdkSessionId without importing each other.\n\t\t\tgetSdkSessionId: () => getOrMintSdkSessionId(),\n\t\t\tgetAnonymousId: () => getOrMintAnonymousId(),\n\t\t\tgetUserId: () => getCurrentUserId(),\n\t\t\tgetReplayStartMs: () => getReplayStartMs(),\n\t\t\tpublishReplayStartMs: (epochMs: number) => publishReplayStartMs(epochMs),\n\t\t}\n\t\tpluginContexts.set(plugin.name, ctx)\n\t\tif (plugin.onInit) {\n\t\t\tconst settled = (async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait plugin.onInit?.(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onInit threw', err)\n\t\t\t\t}\n\t\t\t})()\n\t\t\tinitPromises.push(settled)\n\t\t}\n\t}\n\tconst readyPromise: Promise<void> =\n\t\tinitPromises.length === 0 ? Promise.resolve() : Promise.all(initPromises).then(() => {})\n\n\t// State\n\tlet isOpen = false\n\tlet focusCommentNext = false\n\tlet selectedRating: FeedbackRating | undefined = undefined\n\tlet comment = ''\n\tlet shareEmail = false\n\tlet userEmail = readStoredEmail()\n\tlet isSubmitting = false\n\tlet submitMessage: { type: 'success' | 'error'; text: string } | null = null\n\tlet screenshots: ScreenshotData[] = []\n\tlet isUploadingScreenshot = false\n\tlet screenshotError: string | null = null\n\n\tconst MAX_SCREENSHOTS = 3\n\tconst MAX_SCREENSHOT_BYTES = 10 * 1024 * 1024 // 10MB, matches old React widget\n\n\t// Host element on the page. ShadowRoot keeps host CSS isolated.\n\tconst host = document.createElement('div')\n\thost.setAttribute('data-usero-widget', '')\n\t// position: static so the host element doesn't take any space; the\n\t// fixed-position children inside the shadow root anchor to the viewport.\n\thost.style.cssText = 'all: initial;'\n\tdocument.body.appendChild(host)\n\tconst root = host.attachShadow({ mode: 'open' })\n\n\t// Notify recording plugins (e.g. session-replay) that a shadow root they\n\t// need to observe has just been mounted into the page. rrweb's automatic\n\t// shadow-root traversal only catches roots that exist at record-start\n\t// time (via the initial full snapshot) OR that get attached as part of\n\t// a new node addition observed by its MutationObserver. Our widget host\n\t// is appended to <body> first and `attachShadow` is called immediately\n\t// after, so the observed mutation does not yet have a shadowRoot. The\n\t// session-replay plugin handles this signal by re-taking a full\n\t// snapshot, which causes rrweb to walk into and start observing this\n\t// shadow tree. Dispatched as a CustomEvent on window so the plugin\n\t// stays decoupled from the widget.\n\t// Re-poll getUser at widget interaction boundaries (panel open, mount).\n\t// This catches \"user logged in while widget was idle\" without setting\n\t// up a polling timer that would tick on background tabs. Identify dedupe\n\t// via fingerprint inside identifyIfChanged means same-user re-polls are\n\t// no-ops on the network.\n\tfunction pollGetUser(): void {\n\t\tresolveAndApplyGetUser()\n\t}\n\n\tfunction notifyShadowUpdate(reason: 'mount' | 'panel-open'): void {\n\t\ttry {\n\t\t\twindow.dispatchEvent(\n\t\t\t\tnew CustomEvent('usero:shadow-update', {\n\t\t\t\t\tdetail: { host, root, reason },\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// Older browsers without CustomEvent / dispatchEvent: best-effort.\n\t\t}\n\t}\n\tnotifyShadowUpdate('mount')\n\n\t// Inject styles once into the shadow root.\n\tconst style = document.createElement('style')\n\tstyle.textContent = FEEDBACK_CSS\n\troot.appendChild(style)\n\n\t// Containers\n\tconst buttonEl = document.createElement('button')\n\tconst backdropEl = document.createElement('div')\n\tconst panelEl = document.createElement('div')\n\troot.appendChild(buttonEl)\n\troot.appendChild(backdropEl)\n\troot.appendChild(panelEl)\n\n\tfunction setSubmitMessage(\n\t\tnext: { type: 'success' | 'error'; text: string } | null,\n\t): void {\n\t\tsubmitMessage = next\n\t\trender()\n\t}\n\n\tfunction open(): void {\n\t\tif (isOpen) return\n\t\tisOpen = true\n\t\tfocusCommentNext = true\n\t\t// Reset transient state\n\t\tselectedRating = undefined\n\t\tcomment = ''\n\t\tshareEmail = false\n\t\tsubmitMessage = null\n\t\tscreenshots = []\n\t\tscreenshotError = null\n\t\tisUploadingScreenshot = false\n\t\tapiClient.ping()\n\t\tpollGetUser()\n\t\tonOpen?.()\n\t\trender()\n\t\t// The panel's interactive content is `innerHTML`-ed inside the shadow\n\t\t// root on first render, which IS observable by rrweb's MutationObserver\n\t\t// as long as the shadow root is registered. Re-fire the signal so a\n\t\t// recorder that started before the widget mounted (or before the panel\n\t\t// rendered its first interactive markup) re-snapshots and observes the\n\t\t// shadow root from this point on.\n\t\tnotifyShadowUpdate('panel-open')\n\t}\n\n\tasync function handleScreenshotFile(file: File): Promise<void> {\n\t\tscreenshotError = null\n\t\tif (!file.type.startsWith('image/')) {\n\t\t\tscreenshotError = 'Image files only'\n\t\t\tupdateUploadExtras()\n\t\t\treturn\n\t\t}\n\t\tif (file.size > MAX_SCREENSHOT_BYTES) {\n\t\t\tscreenshotError = 'Max 10MB'\n\t\t\tupdateUploadExtras()\n\t\t\treturn\n\t\t}\n\t\tif (screenshots.length >= MAX_SCREENSHOTS) {\n\t\t\tscreenshotError = `Max ${MAX_SCREENSHOTS} screenshots`\n\t\t\tupdateUploadExtras()\n\t\t\treturn\n\t\t}\n\n\t\tisUploadingScreenshot = true\n\t\t// Surgical updates only. A full render() here would rebuild the panel\n\t\t// innerHTML and destroy the comment textarea the user may be typing in,\n\t\t// stealing focus + caret + any unsynced keystrokes mid-upload.\n\t\tupdateUploadButton()\n\t\tupdateUploadExtras()\n\t\ttry {\n\t\t\tconst uploaded = await apiClient.uploadScreenshot(file, clientId)\n\t\t\tscreenshots = [...screenshots, uploaded]\n\t\t} catch (err) {\n\t\t\tscreenshotError = err instanceof Error ? err.message : 'Upload failed'\n\t\t} finally {\n\t\t\tisUploadingScreenshot = false\n\t\t\tupdateUploadButton()\n\t\t\tupdateUploadExtras()\n\t\t}\n\t}\n\n\tfunction removeScreenshot(index: number): void {\n\t\tscreenshots = screenshots.filter((_, i) => i !== index)\n\t\t// Surgical update so removing a screenshot mid-typing does not blow away\n\t\t// the textarea (matches the upload path's no-full-render rule).\n\t\tupdateUploadButton()\n\t\tupdateUploadExtras()\n\t}\n\n\tfunction close(): void {\n\t\tif (!isOpen) return\n\t\tisOpen = false\n\t\tonClose?.()\n\t\trender()\n\t}\n\n\t// Inner HTML of the upload pick button (label, spinner). Built separately\n\t// from renderPanel so it can be applied surgically without rebuilding the\n\t// panel (and thus the comment textarea) during an upload. The file input is\n\t// a sibling of the button inside the toolrow, so it is NOT touched here.\n\tfunction buildUploadButtonInner(): string {\n\t\treturn isUploadingScreenshot\n\t\t\t? '<span class=\"fb-ups\"></span> Uploading...'\n\t\t\t: '📷 Add screenshot'\n\t}\n\n\tfunction buildUploadButtonHtml(): string {\n\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\tconst btnDisabled = isUploadingScreenshot || atMax\n\t\treturn `\n\t\t\t<input type=\"file\" accept=\"image/*\" data-role=\"screenshot-input\" style=\"display:none;\" aria-label=\"Choose screenshot\" />\n\t\t\t<button type=\"button\" class=\"fb-upb ${btnDisabled ? 'fb-upb--dis' : ''}\" data-role=\"screenshot-pick\" ${btnDisabled ? 'disabled' : ''} style=\"border:1px solid ${theme.border};color:${theme.text};\">\n\t\t\t\t${buildUploadButtonInner()}\n\t\t\t</button>\n\t\t`\n\t}\n\n\tfunction buildUploadExtrasHtml(): string {\n\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\tconst previewsHtml = screenshots\n\t\t\t.map(\n\t\t\t\t(shot, i) => `\n\t\t\t\t\t<div class=\"fb-sp\">\n\t\t\t\t\t\t<img src=\"${escapeHtml(shot.url)}\" alt=\"Screenshot ${i + 1}\" class=\"fb-si\" />\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-sr\" data-role=\"screenshot-remove\" data-index=\"${i}\" aria-label=\"Remove screenshot\">✕</button>\n\t\t\t\t\t</div>\n\t\t\t\t`,\n\t\t\t)\n\t\t\t.join('')\n\t\tconst errorHtml = screenshotError\n\t\t\t? `<div class=\"fb-upe\">⚠ ${escapeHtml(screenshotError)}</div>`\n\t\t\t: ''\n\t\tconst limitHtml = atMax ? `<div class=\"fb-sl\">Max ${MAX_SCREENSHOTS}</div>` : ''\n\t\treturn screenshotError || screenshots.length > 0 || atMax\n\t\t\t? `<div class=\"fb-up-extras\">${errorHtml}${\n\t\t\t\t\tscreenshots.length > 0\n\t\t\t\t\t\t? `<div class=\"fb-ss\">${previewsHtml}</div>`\n\t\t\t\t\t\t: ''\n\t\t\t\t}${limitHtml}</div>`\n\t\t\t: ''\n\t}\n\n\t// Surgically refresh ONLY the pick button (disabled state + label/spinner)\n\t// without rebuilding its parents. Leaves the comment textarea, its focus,\n\t// caret, and any in-progress text untouched. No-op if the panel is not\n\t// currently rendered (e.g. closed) or the screenshot option is off.\n\tfunction updateUploadButton(): void {\n\t\tif (!showScreenshotOption) return\n\t\tconst pickBtn = panelEl.querySelector<HTMLButtonElement>(\n\t\t\t'button[data-role=\"screenshot-pick\"]',\n\t\t)\n\t\tif (!pickBtn) return\n\t\tconst atMax = screenshots.length >= MAX_SCREENSHOTS\n\t\tconst btnDisabled = isUploadingScreenshot || atMax\n\t\tpickBtn.disabled = btnDisabled\n\t\tpickBtn.classList.toggle('fb-upb--dis', btnDisabled)\n\t\tpickBtn.innerHTML = buildUploadButtonInner()\n\t}\n\n\t// Surgically re-render ONLY the upload extras container (error, previews,\n\t// max-limit notice) and reattach the remove-button listeners inside it.\n\t// Nothing outside `.fb-up` is touched, so the textarea survives.\n\tfunction updateUploadExtras(): void {\n\t\tif (!showScreenshotOption) return\n\t\tconst container = panelEl.querySelector<HTMLDivElement>('.fb-up')\n\t\tif (!container) return\n\t\tcontainer.innerHTML = buildUploadExtrasHtml()\n\t\tcontainer\n\t\t\t.querySelectorAll<HTMLButtonElement>('button[data-role=\"screenshot-remove\"]')\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst idx = Number(btn.dataset.index)\n\t\t\t\t\tif (Number.isInteger(idx)) removeScreenshot(idx)\n\t\t\t\t})\n\t\t\t})\n\t}\n\n\tasync function submitForm(): Promise<void> {\n\t\tif (isSubmitting) return\n\t\tisSubmitting = true\n\t\tsubmitMessage = null\n\t\trender()\n\n\t\tconst feedbackData: FeedbackData = {\n\t\t\trating: selectedRating,\n\t\t\tcomment: comment.trim() || undefined,\n\t\t\tuserEmail: shareEmail ? userEmail : undefined,\n\t\t\tscreenshots: screenshots.length > 0 ? screenshots : undefined,\n\t\t\tmetadata: {\n\t\t\t\tpageUrl: window.location.href,\n\t\t\t\tpageTitle: document.title || 'Untitled Page',\n\t\t\t\treferrer: document.referrer || undefined,\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t},\n\t\t}\n\n\t\tconst submission: FeedbackSubmission = {\n\t\t\tclientId,\n\t\t\trating: feedbackData.rating,\n\t\t\tcomment: feedbackData.comment,\n\t\t\tuserEmail: feedbackData.userEmail,\n\t\t\tpageUrl: feedbackData.metadata.pageUrl,\n\t\t\tpageTitle: feedbackData.metadata.pageTitle,\n\t\t\treferrer: feedbackData.metadata.referrer,\n\t\t\tenvironment,\n\t\t}\n\t\tif (screenshots.length > 0) submission.screenshots = screenshots\n\t\tif (metadata !== undefined) submission.metadata = metadata\n\n\t\tconst validation = validateFeedbackSubmission(submission)\n\t\tif (!validation.isValid) {\n\t\t\tisSubmitting = false\n\t\t\tsetSubmitMessage({ type: 'error', text: validation.errors.join(', ') })\n\t\t\treturn\n\t\t}\n\n\t\t// Run plugin onFeedbackSubmit hooks in parallel and merge the\n\t\t// returned partial payloads into the outgoing submission. A plugin\n\t\t// that throws or rejects is logged and skipped — never blocks submit.\n\t\t//\n\t\t// Merge policy:\n\t\t// - `metadata` is DEEP-merged (one level): later plugins' keys\n\t\t// win on conflict, but non-conflicting keys from earlier\n\t\t// plugins are preserved. metadata is the natural collision\n\t\t// point (every plugin wants to attach context) so deep merge\n\t\t// is what users expect.\n\t\t// - Every other top-level key is shallow-merged: later plugins\n\t\t// win wholesale. This is fine in practice because dedicated\n\t\t// keys like `replayEvents` have a single writer.\n\t\tlet enrichedSubmission: FeedbackSubmission = submission\n\t\tif (pluginList.length > 0) {\n\t\t\tconst patchPromises = pluginList.map(async plugin => {\n\t\t\t\tif (!plugin.onFeedbackSubmit) return undefined\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) return undefined\n\t\t\t\ttry {\n\t\t\t\t\treturn await plugin.onFeedbackSubmit(ctx, submission)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onFeedbackSubmit threw', err)\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t})\n\t\t\tconst patches = await Promise.all(patchPromises)\n\t\t\tenrichedSubmission = mergePluginPatches(submission, patches)\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await apiClient.submitFeedback(enrichedSubmission)\n\t\t\tif (response.success) {\n\t\t\t\tif (shareEmail && userEmail) writeStoredEmail(userEmail)\n\t\t\t\tonSubmit?.(feedbackData)\n\t\t\t\tselectedRating = undefined\n\t\t\t\tcomment = ''\n\t\t\t\tshareEmail = false\n\t\t\t\tscreenshots = []\n\t\t\t\tscreenshotError = null\n\t\t\t\tsubmitMessage = { type: 'success', text: 'Thank you!' }\n\t\t\t} else {\n\t\t\t\tconst msg = response.error ?? 'Error occurred. Try again.'\n\t\t\t\tonError?.(new Error(msg))\n\t\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : 'Error occurred. Try again.'\n\t\t\tonError?.(new Error(msg))\n\t\t\tsubmitMessage = { type: 'error', text: msg }\n\t\t} finally {\n\t\t\tisSubmitting = false\n\t\t\trender()\n\t\t}\n\t}\n\n\t// Static button content + styles (only style.background changes once)\n\tfunction renderButton(): void {\n\t\tbuttonEl.className = `fb-btn fb-btn--${position} ${isOpen ? 'fb-btn--open' : ''}`\n\t\tbuttonEl.setAttribute('aria-label', 'Open feedback')\n\t\tbuttonEl.type = 'button'\n\t\tbuttonEl.style.background = `linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)})`\n\t\tbuttonEl.innerHTML = isOpen\n\t\t\t? `<span style=\"font-size:20px;\">✕</span>`\n\t\t\t: ''\n\t}\n\n\tfunction renderBackdrop(): void {\n\t\tbackdropEl.className = 'fb-backdrop'\n\t\tbackdropEl.style.display = isOpen ? 'block' : 'none'\n\t\tbackdropEl.setAttribute('aria-label', 'Close modal')\n\t}\n\n\tfunction renderPanel(): void {\n\t\tpanelEl.className = `fb-pnl-base fb-pnl--${position} ${\n\t\t\tisOpen ? 'fb-pnl--open' : 'fb-pnl--closed'\n\t\t}`\n\t\tpanelEl.style.backgroundColor = theme.background\n\t\tif (position === 'right') {\n\t\t\tpanelEl.style.borderLeft = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderRight = ''\n\t\t} else {\n\t\t\tpanelEl.style.borderRight = `1px solid ${theme.border}`\n\t\t\tpanelEl.style.borderLeft = ''\n\t\t}\n\t\tpanelEl.setAttribute('role', 'dialog')\n\t\tpanelEl.setAttribute('aria-modal', 'true')\n\t\tpanelEl.setAttribute('aria-labelledby', 'usero-feedback-title')\n\n\t\tconst remaining = 1000 - comment.length\n\t\tconst lowChars = remaining < 50\n\n\t\tconst ratingsHtml = ([1, 2, 3, 4] as FeedbackRating[])\n\t\t\t.map(r => {\n\t\t\t\tconst sel = selectedRating === r\n\t\t\t\tconst bg = EMOJI_BACKGROUNDS[r]\n\t\t\t\tconst cls = ['fb-ec', sel && 'fb-ec--sel'].filter(Boolean).join(' ')\n\t\t\t\t// Set color on the button so .fb-el (color: currentColor) inherits\n\t\t\t\t// the themed foreground. Without this it falls back to the UA\n\t\t\t\t// default for <button>, which is black on dark backgrounds.\n\t\t\t\treturn `\n\t\t\t\t\t<div class=\"${cls}\" style=\"background:${bg}\">\n\t\t\t\t\t\t<button type=\"button\" class=\"fb-eb\" data-rating=\"${r}\" role=\"radio\" aria-checked=\"${sel}\" aria-label=\"${r}: ${RATING_LABELS[r]}\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t\t<div class=\"fb-ei\"><span role=\"img\" aria-label=\"${RATING_LABELS[r]}\">${EMOJI_MAP[r]}</span></div>\n\t\t\t\t\t\t\t<div class=\"fb-el\" style=\"color:${theme.text}\">${RATING_LABELS[r]}</div>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t`\n\t\t\t})\n\t\t\t.join('')\n\n\t\tconst messageHtml = submitMessage\n\t\t\t? `<div class=\"fb-msg fb-msg--header ${submitMessage.type === 'success' ? 'fb-msg--ok' : 'fb-msg--err'}\">${submitMessage.type === 'success' ? '✓' : '⚠'} ${escapeHtml(submitMessage.text)}</div>`\n\t\t\t: ''\n\n\t\t// The upload button + char counter share a single horizontal row to\n\t\t// keep the panel compact (matches the legacy react-feedback-collector\n\t\t// layout). Upload extras (error message, previews, max limit) live on\n\t\t// their own row beneath, so they can wrap freely.\n\t\tconst uploadBtnHtml = showScreenshotOption ? buildUploadButtonHtml() : ''\n\t\tconst uploadExtrasHtml = showScreenshotOption ? buildUploadExtrasHtml() : ''\n\n\t\tconst emailBlockHtml = showEmailOption\n\t\t\t? `\n\t\t\t\t<div class=\"fb-email\">\n\t\t\t\t\t<label class=\"fb-email-lbl\" style=\"color:${theme.text}\">\n\t\t\t\t\t\t<input type=\"checkbox\" class=\"fb-email-cb\" data-role=\"share-email\" ${shareEmail ? 'checked' : ''} aria-label=\"Share email\" />\n\t\t\t\t\t\t<span>Share my email</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t${\n\t\t\t\t\t\tshareEmail\n\t\t\t\t\t\t\t? `<input type=\"email\" class=\"fb-email-inp\" data-role=\"email-input\" value=\"${escapeHtml(userEmail)}\" placeholder=\"your.email@example.com\" aria-label=\"Email\" maxlength=\"254\" autocomplete=\"email\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\" />`\n\t\t\t\t\t\t\t: ''\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t`\n\t\t\t: ''\n\n\t\tconst submitDisabled = isSubmitting\n\t\tconst submitStyle = `background:linear-gradient(135deg, ${theme.primary}, ${getGradientEnd(theme.primary)});color:#ffffff;${submitDisabled ? 'opacity:0.6;cursor:not-allowed;' : ''}`\n\n\t\tpanelEl.innerHTML = `\n\t\t\t<div class=\"fb-cnt\">\n\t\t\t\t<div class=\"fb-hdr\" style=\"border-bottom:1px solid ${theme.border}\">\n\t\t\t\t\t<h2 id=\"usero-feedback-title\" class=\"fb-ttl\" style=\"color:${theme.text}\">${escapeHtml(title)}</h2>\n\t\t\t\t\t${messageHtml}\n\t\t\t\t\t<button class=\"fb-close-btn\" data-role=\"close\" style=\"color:${theme.text}\" aria-label=\"Close\" type=\"button\">✕</button>\n\t\t\t\t</div>\n\t\t\t\t<form data-role=\"form\">\n\t\t\t\t\t<div class=\"fb-es\" role=\"radiogroup\" aria-label=\"Rate experience\">${ratingsHtml}</div>\n\t\t\t\t\t<textarea class=\"fb-ta\" data-role=\"comment\" placeholder=\"${escapeHtml(placeholder)}\" aria-label=\"Comments\" maxlength=\"1000\" rows=\"2\" style=\"border:1px solid ${theme.border};color:${theme.text};background-color:${theme.background};\">${escapeHtml(comment)}</textarea>\n\t\t\t\t\t<div class=\"fb-toolrow\">\n\t\t\t\t\t\t${uploadBtnHtml}\n\t\t\t\t\t\t<div class=\"fb-charcount${lowChars ? ' fb-charcount--low' : ''}\" data-role=\"charcount\" style=\"color:${lowChars ? '#dc2626' : theme.text};opacity:${lowChars ? 1 : 0.6};\">${remaining} chars remaining</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t${showScreenshotOption ? `<div class=\"fb-up\">${uploadExtrasHtml}</div>` : ''}\n\t\t\t\t\t${emailBlockHtml}\n\t\t\t\t\t<button class=\"fb-sub ${submitDisabled ? 'fb-sub--dis' : ''}\" type=\"submit\" aria-label=\"Submit\" ${submitDisabled ? 'disabled' : ''} style=\"${submitStyle}\">\n\t\t\t\t\t\t${isSubmitting ? '<span class=\"fb-spin\"></span>' : ''}\n\t\t\t\t\t\t${isSubmitting ? 'Submitting...' : 'Send Feedback 🚀'}\n\t\t\t\t\t</button>\n\t\t\t\t</form>\n\t\t\t</div>\n\t\t`\n\n\t\t// Wire up panel-internal events\n\t\tconst form = panelEl.querySelector<HTMLFormElement>('form[data-role=\"form\"]')\n\t\tform?.addEventListener('submit', e => {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t})\n\n\t\tpanelEl\n\t\t\t.querySelector<HTMLButtonElement>('button[data-role=\"close\"]')\n\t\t\t?.addEventListener('click', close)\n\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>('button[data-rating]')\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst value = btn.dataset.rating\n\t\t\t\t\tif (value === '1' || value === '2' || value === '3' || value === '4') {\n\t\t\t\t\t\tselectedRating = Number(value) as FeedbackRating\n\t\t\t\t\t\tfocusCommentNext = true\n\t\t\t\t\t\trender()\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\n\t\tconst textarea = panelEl.querySelector<HTMLTextAreaElement>(\n\t\t\t'textarea[data-role=\"comment\"]',\n\t\t)\n\t\tif (textarea) {\n\t\t\tif (focusCommentNext) {\n\t\t\t\tfocusCommentNext = false\n\t\t\t\t// Defer to next frame so the browser doesn't scroll the panel\n\t\t\t\t// while it's still animating in.\n\t\t\t\trequestAnimationFrame(() => textarea.focus({ preventScroll: true }))\n\t\t\t}\n\t\t\ttextarea.addEventListener('input', () => {\n\t\t\t\tif (textarea.value.length <= 1000) {\n\t\t\t\t\tcomment = textarea.value\n\t\t\t\t\t// Update char count without full rerender to avoid losing focus.\n\t\t\t\t\t// IMPORTANT: target by stable class. A previous selector\n\t\t\t\t\t// `.fb-cnt form > div > div` matched the first rating tile,\n\t\t\t\t\t// hijacking it with the char-count text on every keystroke.\n\t\t\t\t\tconst counter = panelEl.querySelector<HTMLDivElement>(\n\t\t\t\t\t\t'[data-role=\"charcount\"]',\n\t\t\t\t\t)\n\t\t\t\t\tif (counter) {\n\t\t\t\t\t\tconst left = 1000 - comment.length\n\t\t\t\t\t\tcounter.textContent = `${left} chars remaining`\n\t\t\t\t\t\tcounter.style.color = left < 50 ? '#dc2626' : theme.text\n\t\t\t\t\t\tcounter.style.opacity = left < 50 ? '1' : '0.6'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tconst shareCb = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"share-email\"]',\n\t\t)\n\t\tshareCb?.addEventListener('change', () => {\n\t\t\tshareEmail = shareCb.checked\n\t\t\trender()\n\t\t})\n\n\t\tconst emailInp = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"email-input\"]',\n\t\t)\n\t\temailInp?.addEventListener('input', () => {\n\t\t\tif (emailInp.value.length <= 254) {\n\t\t\t\tuserEmail = emailInp.value\n\t\t\t}\n\t\t})\n\n\t\tconst fileInput = panelEl.querySelector<HTMLInputElement>(\n\t\t\t'input[data-role=\"screenshot-input\"]',\n\t\t)\n\t\tconst pickBtn = panelEl.querySelector<HTMLButtonElement>(\n\t\t\t'button[data-role=\"screenshot-pick\"]',\n\t\t)\n\t\tpickBtn?.addEventListener('click', () => {\n\t\t\tfileInput?.click()\n\t\t})\n\t\tfileInput?.addEventListener('change', () => {\n\t\t\tconst file = fileInput.files?.[0]\n\t\t\tif (!file) return\n\t\t\tvoid handleScreenshotFile(file).finally(() => {\n\t\t\t\tif (fileInput) fileInput.value = ''\n\t\t\t})\n\t\t})\n\t\tpanelEl\n\t\t\t.querySelectorAll<HTMLButtonElement>(\n\t\t\t\t'button[data-role=\"screenshot-remove\"]',\n\t\t\t)\n\t\t\t.forEach(btn => {\n\t\t\t\tbtn.addEventListener('click', () => {\n\t\t\t\t\tconst idx = Number(btn.dataset.index)\n\t\t\t\t\tif (Number.isInteger(idx)) removeScreenshot(idx)\n\t\t\t\t})\n\t\t\t})\n\t}\n\n\tfunction render(): void {\n\t\trenderButton()\n\t\trenderBackdrop()\n\t\trenderPanel()\n\t}\n\n\t// Top-level event listeners\n\tbuttonEl.addEventListener('click', () => {\n\t\tif (isOpen) close()\n\t\telse open()\n\t})\n\tbackdropEl.addEventListener('click', () => {\n\t\t// Don't let an accidental backdrop tap dismiss the panel while an upload\n\t\t// or submit is in flight (it would discard in-progress feedback). The\n\t\t// explicit X and floating toggle buttons remain deliberate exits.\n\t\tif (isUploadingScreenshot || isSubmitting) return\n\t\tclose()\n\t})\n\n\tconst onKeyDown = (e: KeyboardEvent): void => {\n\t\tif (!isOpen) return\n\t\tif (e.key === 'Escape') {\n\t\t\t// Same guard as the backdrop: an in-flight upload/submit shouldn't be\n\t\t\t// abandonable by a stray Escape.\n\t\t\tif (isUploadingScreenshot || isSubmitting) return\n\t\t\tclose()\n\t\t}\n\t\tif (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n\t\t\te.preventDefault()\n\t\t\tvoid submitForm()\n\t\t}\n\t}\n\tdocument.addEventListener('keydown', onKeyDown)\n\n\t// Live OS color-scheme tracking. Only active while the caller has not\n\t// provided an explicit `theme` prop. If they later pass one via update(),\n\t// we detach. If they later clear it (set to undefined), we re-attach.\n\tlet darkMql: MediaQueryList | null = null\n\tlet mqlListener: ((ev: MediaQueryListEvent) => void) | null = null\n\n\tfunction detachMqlListener(): void {\n\t\tif (darkMql && mqlListener) {\n\t\t\tdarkMql.removeEventListener('change', mqlListener)\n\t\t}\n\t\tdarkMql = null\n\t\tmqlListener = null\n\t}\n\n\tfunction attachMqlListener(): void {\n\t\tif (darkMql) return\n\t\tif (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n\t\tdarkMql = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tmqlListener = () => {\n\t\t\t// Only react if user still hasn't overridden the theme.\n\t\t\tif (userThemeOverride !== undefined) return\n\t\t\ttheme = resolveTheme(undefined)\n\t\t\trender()\n\t\t}\n\t\tdarkMql.addEventListener('change', mqlListener)\n\t}\n\n\tif (userThemeOverride === undefined) attachMqlListener()\n\n\t// Initial paint\n\trender()\n\n\tlet destroyed = false\n\treturn {\n\t\tdestroy: () => {\n\t\t\tif (destroyed) return\n\t\t\tdestroyed = true\n\t\t\tdocument.removeEventListener('keydown', onKeyDown)\n\t\t\tdetachMqlListener()\n\t\t\tfor (const plugin of pluginList) {\n\t\t\t\tif (!plugin.onDestroy) continue\n\t\t\t\tconst ctx = pluginContexts.get(plugin.name)\n\t\t\t\tif (!ctx) continue\n\t\t\t\ttry {\n\t\t\t\t\tplugin.onDestroy(ctx)\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.logger.error('onDestroy threw', err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tpluginStores.clear()\n\t\t\tpluginContexts.clear()\n\t\t\thost.remove()\n\t\t},\n\t\topen,\n\t\tclose,\n\t\twhenReady: () => readyPromise,\n\t\tidentify: (user: UseroUser | null) => {\n\t\t\tif (destroyed) return\n\t\t\tcurrentUserProp = user\n\t\t\tapplyResolvedUser(user)\n\t\t},\n\t\tupdate: next => {\n\t\t\tif (destroyed) return\n\t\t\tlet needsRender = false\n\t\t\tif (next.position !== undefined && next.position !== position) {\n\t\t\t\tposition = next.position\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif ('theme' in next) {\n\t\t\t\t// Caller opted in/out of explicit theme control. Track the\n\t\t\t\t// override so the matchMedia listener and any further\n\t\t\t\t// resolutions know whether the user is in charge.\n\t\t\t\tuserThemeOverride = next.theme\n\t\t\t\ttheme = resolveTheme(userThemeOverride)\n\t\t\t\tif (userThemeOverride === undefined) attachMqlListener()\n\t\t\t\telse detachMqlListener()\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.title !== undefined && next.title !== title) {\n\t\t\t\ttitle = next.title\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (next.placeholder !== undefined && next.placeholder !== placeholder) {\n\t\t\t\tplaceholder = next.placeholder\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showEmailOption !== undefined &&\n\t\t\t\tnext.showEmailOption !== showEmailOption\n\t\t\t) {\n\t\t\t\tshowEmailOption = next.showEmailOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tnext.showScreenshotOption !== undefined &&\n\t\t\t\tnext.showScreenshotOption !== showScreenshotOption\n\t\t\t) {\n\t\t\t\tshowScreenshotOption = next.showScreenshotOption\n\t\t\t\tneedsRender = true\n\t\t\t}\n\t\t\t// Non-render-affecting props: just swap refs.\n\t\t\tif ('environment' in next) environment = next.environment\n\t\t\tif ('metadata' in next) metadata = next.metadata\n\t\t\tif ('onSubmit' in next) onSubmit = next.onSubmit\n\t\t\tif ('onError' in next) onError = next.onError\n\t\t\tif ('onOpen' in next) onOpen = next.onOpen\n\t\t\tif ('onClose' in next) onClose = next.onClose\n\t\t\tif ('getUser' in next) getUserFn = next.getUser\n\t\t\t// Identity: React wrapper hot-swaps `user` here on every render.\n\t\t\t// applyResolvedUser dedupes via fingerprint, so passing the same\n\t\t\t// user object is a no-op transport-wise. Track the latest prop\n\t\t\t// so plugin-driven re-resolves (PluginContext.resolveUser) know\n\t\t\t// to prefer the imperative path over getUserFn.\n\t\t\tif ('user' in next) {\n\t\t\t\tcurrentUserProp = next.user\n\t\t\t\tapplyResolvedUser(next.user)\n\t\t\t}\n\t\t\tif (needsRender) render()\n\t\t},\n\t}\n}\n","// Thin React wrapper around the framework-free vanilla widget. Renders\n// nothing into the React tree; the widget mounts a host <div> on\n// document.body and renders into a shadow root. This keeps the React\n// bundle tiny (just the wrapper) and means there is one source of truth\n// for widget UX, the vanilla implementation.\n\nimport { useEffect, useRef } from 'react'\nimport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tinitUseroFeedbackWidget,\n\tmergeTheme,\n\ttype UseroWidgetHandle,\n} from './vanilla'\nimport type { FeedbackData, FeedbackWidgetProps } from './types'\n\nexport {\n\tDARK_THEME,\n\tDEFAULT_THEME,\n\tmergeTheme,\n}\nexport type {\n\tFeedbackData,\n\tFeedbackRating,\n\tFeedbackSubmission,\n\tFeedbackWidgetProps,\n\tScreenshotData,\n\tUseroUser,\n\tUseroUserTraitValue,\n\tUseroUserTraits,\n\tWidgetPosition,\n\tWidgetTheme,\n} from './types'\nexport type { UseroWidgetHandle } from './vanilla'\n\nexport function UseroFeedbackWidget(props: FeedbackWidgetProps): null {\n\tconst handleRef = useRef<UseroWidgetHandle | null>(null)\n\n\t// Latest callbacks live in a ref so identity changes (a new arrow each\n\t// render) never re-init the widget.\n\tconst callbacksRef = useRef({\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t})\n\tcallbacksRef.current = {\n\t\tonSubmit: props.onSubmit,\n\t\tonError: props.onError,\n\t\tonOpen: props.onOpen,\n\t\tonClose: props.onClose,\n\t}\n\n\tconst { clientId, baseUrl } = props\n\n\t// Init / tear-down. We only re-init when clientId or baseUrl change,\n\t// because the API client + widget identity are bound to those.\n\tuseEffect(() => {\n\t\tconst handle = initUseroFeedbackWidget({\n\t\t\t...props,\n\t\t\tonSubmit: (data: FeedbackData) => callbacksRef.current.onSubmit?.(data),\n\t\t\tonError: (err: Error) => callbacksRef.current.onError?.(err),\n\t\t\tonOpen: () => callbacksRef.current.onOpen?.(),\n\t\t\tonClose: () => callbacksRef.current.onClose?.(),\n\t\t})\n\t\thandleRef.current = handle\n\t\treturn () => {\n\t\t\thandle.destroy()\n\t\t\thandleRef.current = null\n\t\t}\n\t\t// Intentionally narrow deps. All other prop changes flow through the\n\t\t// update() effect below.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [clientId, baseUrl])\n\n\t// Hot-swap render-affecting props without re-init.\n\tconst themeJson = JSON.stringify(props.theme ?? null)\n\tconst metadataJson = JSON.stringify(props.metadata ?? null)\n\tuseEffect(() => {\n\t\tconst handle = handleRef.current\n\t\tif (!handle) return\n\t\tconst updates: Partial<Omit<FeedbackWidgetProps, 'clientId' | 'baseUrl'>> = {}\n\t\tif (props.position !== undefined) updates.position = props.position\n\t\tif (props.theme !== undefined) updates.theme = props.theme\n\t\tif (props.title !== undefined) updates.title = props.title\n\t\tif (props.placeholder !== undefined) updates.placeholder = props.placeholder\n\t\tif (props.showEmailOption !== undefined) {\n\t\t\tupdates.showEmailOption = props.showEmailOption\n\t\t}\n\t\tif (props.showScreenshotOption !== undefined) {\n\t\t\tupdates.showScreenshotOption = props.showScreenshotOption\n\t\t}\n\t\tif (props.environment !== undefined) updates.environment = props.environment\n\t\tif (props.metadata !== undefined) updates.metadata = props.metadata\n\t\thandle.update(updates)\n\t\t// theme/metadata compared by serialized identity since they're\n\t\t// objects; primitives use direct dep tracking.\n\t}, [\n\t\tprops.position,\n\t\tthemeJson,\n\t\tprops.title,\n\t\tprops.placeholder,\n\t\tprops.showEmailOption,\n\t\tprops.showScreenshotOption,\n\t\tprops.environment,\n\t\tmetadataJson,\n\t])\n\n\t// Identity: diff the resolved user by id + email + serialised traits.\n\t// Re-renders that pass the same logical user are no-ops at the\n\t// transport layer too (identifyIfChanged dedupes by fingerprint).\n\tconst userId = props.user?.id ?? null\n\tconst userEmail = props.user?.email ?? null\n\tconst userDisplayName = props.user?.displayName ?? null\n\tconst userTraitsJson = JSON.stringify(props.user?.traits ?? null)\n\tconst userIsNull = props.user === null\n\tuseEffect(() => {\n\t\tconst handle = handleRef.current\n\t\tif (!handle) return\n\t\t// `user: undefined` means \"not supplied, do nothing\". `user: null`\n\t\t// means \"logged out, rotate anonymousId\". We forward both as-is so\n\t\t// vanilla can disambiguate via the `'user' in next` check.\n\t\tif (props.user !== undefined) handle.update({ user: props.user })\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [userId, userEmail, userDisplayName, userTraitsJson, userIsNull])\n\n\treturn null\n}\n"]}
|