@usero/sdk 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types.ts","../../src/plugins/user-test.ts"],"names":[],"mappings":"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","file":"user-test.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","// User-testing-mode plugin for the Usero widget.\n//\n// Activates ONLY when the host page URL carries `?usero_test=<slug>`. When\n// active, it:\n// 1. Creates a UserTestSession on the SaaS side via\n// POST /api/user-test-sessions\n// 2. Starts a MediaRecorder on the user's microphone (Opus in WebM) and\n// ships chunks every `chunkSeconds` to\n// PUT /api/user-test-sessions/:id/chunk?index=N\n// 3. Renders a small floating \"recording\" indicator with a Finish button\n// bottom-center so the tester can stop on their own.\n// 4. On Finish (or `pagehide`), flushes any buffered chunks and calls\n// POST /api/user-test-sessions/:id/finalise.\n//\n// Mic-permission denied is non-fatal: the session is still created (the\n// session-replay plugin keeps recording in parallel) and the indicator\n// shows a \"no audio\" hint. The SaaS side detects audio presence from the\n// first chunk; if no chunks land, hasAudio stays false there too.\n//\n// Bundle hygiene: this module is a subpath export and does NOT depend on\n// rrweb or any other heavy dep — just the native MediaRecorder API. The\n// floating UI is shadow-DOM scoped so host page CSS can't leak in.\n//\n// Privacy: only the microphone is recorded. We never read DOM text, never\n// touch the camera, and never persist audio in the browser past the\n// IndexedDB fallback (cleared on successful upload).\n\nimport type { UseroPlugin, PluginContext } from '../plugin'\nimport { DEFAULT_API_URL } from '../types'\n\nexport interface UserTestOptions {\n\t// URL query param the welcome page appends to redirect testers back.\n\t// Default `usero_test`. Match SaaS side if you ever change it.\n\tqueryParam?: string\n\t// Audio chunk length in seconds. Smaller = more partial-data resilience\n\t// but more requests. Default 30.\n\tchunkSeconds?: number\n\t// API origin. Override for self-hosted or local dev. Defaults to the\n\t// shared SDK constant (https://usero.io).\n\tapiUrl?: string\n\t// Override the tester-name shown on the SaaS side. Normally the welcome\n\t// page collects this and stores it in localStorage; the plugin reads it\n\t// from there. This option lets a host site bypass that.\n\ttesterName?: string\n\t// Hide the floating indicator. The plugin still records and finalises\n\t// on `pagehide`, but the tester gets no on-page UI. Useful if the host\n\t// page wants to render its own.\n\thideIndicator?: boolean\n}\n\ninterface UserTestTask {\n\tid: string\n\tprompt: string\n\tsortOrder: number\n}\n\ninterface RecorderStore {\n\tcancelled: boolean\n\tslug: string\n\tsessionId: string | null\n\tclientId: string | null\n\trecorder: MediaRecorder | null\n\tstream: MediaStream | null\n\tchunkIndex: number\n\tuploadQueue: Promise<void>\n\tpendingUploads: number\n\tstartedAt: number\n\tindicator: HTMLElement | null\n\tindicatorRoot: ShadowRoot | null\n\tindicatorState: 'recording' | 'finishing' | 'done' | 'no-audio' | 'error'\n\tpageHideHandler: (() => void) | null\n\toptions: Required<UserTestOptions>\n\ttasks: UserTestTask[]\n\ttasksPanelOpen: boolean\n\toutsidePointerHandler: ((event: PointerEvent) => void) | null\n\tkeydownHandler: ((event: KeyboardEvent) => void) | null\n}\n\nconst DEFAULT_OPTIONS: Required<Omit<UserTestOptions, 'testerName' | 'apiUrl'>> & {\n\ttesterName: string\n\tapiUrl: string\n} = {\n\tqueryParam: 'usero_test',\n\tchunkSeconds: 30,\n\tapiUrl: DEFAULT_API_URL,\n\ttesterName: '',\n\thideIndicator: false,\n}\n\nconst TESTER_NAME_STORAGE_KEY = 'usero:user-test:tester-name'\nconst TASKS_PANEL_OPEN_STORAGE_KEY = 'usero:user-test:tasks-panel-open'\nconst IDB_NAME = 'usero-user-test'\nconst IDB_STORE = 'pending-chunks'\n\ninterface PendingChunk {\n\tid: string\n\tsessionId: string\n\tapiUrl: string\n\tchunkIndex: number\n\tblob: Blob\n\tcreatedAt: number\n}\n\nfunction readTesterName(override: string): string | undefined {\n\tif (override) return override\n\ttry {\n\t\tconst stored = window.localStorage?.getItem(TESTER_NAME_STORAGE_KEY)\n\t\tif (stored && stored.trim()) return stored.trim().slice(0, 120)\n\t} catch {\n\t\t// Storage access can throw in some sandboxed iframes — ignore.\n\t}\n\treturn undefined\n}\n\nfunction getTestSlug(queryParam: string): string | null {\n\tif (typeof window === 'undefined' || typeof window.location === 'undefined') return null\n\ttry {\n\t\tconst params = new URLSearchParams(window.location.search)\n\t\tconst slug = params.get(queryParam)\n\t\tif (!slug) return null\n\t\tconst cleaned = slug.trim().slice(0, 64)\n\t\tif (!/^[a-z0-9-]+$/i.test(cleaned)) return null\n\t\treturn cleaned\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction isMediaRecorderSupported(): boolean {\n\treturn typeof window !== 'undefined' && typeof window.MediaRecorder !== 'undefined' && typeof navigator !== 'undefined' && !!navigator.mediaDevices?.getUserMedia\n}\n\nfunction pickMimeType(): string | undefined {\n\tconst candidates = ['audio/webm;codecs=opus', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/mp4']\n\tfor (const candidate of candidates) {\n\t\tif (typeof MediaRecorder !== 'undefined' && MediaRecorder.isTypeSupported?.(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\t}\n\treturn undefined\n}\n\n// IndexedDB helpers. Best-effort, never throw upstream — if IDB is missing\n// or quota-blown we just lose offline resilience but the live upload path\n// still runs.\nfunction idbOpen(): Promise<IDBDatabase | null> {\n\treturn new Promise(resolve => {\n\t\tif (typeof indexedDB === 'undefined') {\n\t\t\tresolve(null)\n\t\t\treturn\n\t\t}\n\t\ttry {\n\t\t\tconst req = indexedDB.open(IDB_NAME, 1)\n\t\t\treq.onupgradeneeded = (): void => {\n\t\t\t\tconst db = req.result\n\t\t\t\tif (!db.objectStoreNames.contains(IDB_STORE)) {\n\t\t\t\t\tdb.createObjectStore(IDB_STORE, { keyPath: 'id' })\n\t\t\t\t}\n\t\t\t}\n\t\t\treq.onsuccess = (): void => resolve(req.result)\n\t\t\treq.onerror = (): void => resolve(null)\n\t\t} catch {\n\t\t\tresolve(null)\n\t\t}\n\t})\n}\n\nasync function idbStashChunk(chunk: PendingChunk): Promise<void> {\n\tconst db = await idbOpen()\n\tif (!db) return\n\tawait new Promise<void>(resolve => {\n\t\ttry {\n\t\t\tconst tx = db.transaction(IDB_STORE, 'readwrite')\n\t\t\ttx.objectStore(IDB_STORE).put(chunk)\n\t\t\ttx.oncomplete = (): void => resolve()\n\t\t\ttx.onerror = (): void => resolve()\n\t\t\ttx.onabort = (): void => resolve()\n\t\t} catch {\n\t\t\tresolve()\n\t\t}\n\t})\n\tdb.close()\n}\n\nasync function idbDeleteChunk(id: string): Promise<void> {\n\tconst db = await idbOpen()\n\tif (!db) return\n\tawait new Promise<void>(resolve => {\n\t\ttry {\n\t\t\tconst tx = db.transaction(IDB_STORE, 'readwrite')\n\t\t\ttx.objectStore(IDB_STORE).delete(id)\n\t\t\ttx.oncomplete = (): void => resolve()\n\t\t\ttx.onerror = (): void => resolve()\n\t\t\ttx.onabort = (): void => resolve()\n\t\t} catch {\n\t\t\tresolve()\n\t\t}\n\t})\n\tdb.close()\n}\n\nasync function idbListChunks(sessionId: string): Promise<PendingChunk[]> {\n\tconst db = await idbOpen()\n\tif (!db) return []\n\tconst items = await new Promise<PendingChunk[]>(resolve => {\n\t\ttry {\n\t\t\tconst tx = db.transaction(IDB_STORE, 'readonly')\n\t\t\tconst req = tx.objectStore(IDB_STORE).getAll()\n\t\t\treq.onsuccess = (): void => {\n\t\t\t\tconst all = (req.result as PendingChunk[]) ?? []\n\t\t\t\tresolve(all.filter(c => c.sessionId === sessionId))\n\t\t\t}\n\t\t\treq.onerror = (): void => resolve([])\n\t\t} catch {\n\t\t\tresolve([])\n\t\t}\n\t})\n\tdb.close()\n\treturn items\n}\n\nasync function uploadChunkWithRetry(\n\tapiUrl: string,\n\tsessionId: string,\n\tindex: number,\n\tblob: Blob,\n\tlogger: PluginContext['logger'],\n\tmaxAttempts = 5,\n): Promise<boolean> {\n\tconst url = `${apiUrl.replace(/\\/$/, '')}/api/user-test-sessions/${encodeURIComponent(sessionId)}/chunk?index=${index}`\n\tlet attempt = 0\n\twhile (attempt < maxAttempts) {\n\t\ttry {\n\t\t\tconst res = await fetch(url, {\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tbody: blob,\n\t\t\t\theaders: { 'Content-Type': blob.type || 'audio/webm' },\n\t\t\t\tkeepalive: blob.size <= 60 * 1024, // browsers cap keepalive bodies\n\t\t\t})\n\t\t\tif (res.ok) return true\n\t\t\t// 4xx (other than 413) won't get better with retries; bail early.\n\t\t\tif (res.status >= 400 && res.status < 500 && res.status !== 408 && res.status !== 429) {\n\t\t\t\tlogger.error(`chunk ${index} rejected with ${res.status}`)\n\t\t\t\treturn false\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tlogger.warn(`chunk ${index} upload attempt ${attempt + 1} failed`, err)\n\t\t}\n\t\tattempt += 1\n\t\tconst backoff = Math.min(15000, 500 * 2 ** attempt) + Math.floor(Math.random() * 250)\n\t\tawait new Promise(resolve => setTimeout(resolve, backoff))\n\t}\n\treturn false\n}\n\nfunction buildIndicator(host: HTMLElement, store: RecorderStore, onFinish: () => void, onToggleTasks: () => void): ShadowRoot {\n\tconst root = host.attachShadow({ mode: 'closed' })\n\tconst style = document.createElement('style')\n\t// Keep this CSS small. Pulse is the only animation. Bottom-center,\n\t// safe-area aware, semi-transparent so it doesn't block the page.\n\tstyle.textContent = `\n\t\t:host { all: initial; }\n\t\t.anchor {\n\t\t\tposition: fixed;\n\t\t\tbottom: calc(env(safe-area-inset-bottom, 0px) + 16px);\n\t\t\tleft: 50%; transform: translateX(-50%);\n\t\t\tdisplay: flex; flex-direction: column; align-items: center; gap: 8px;\n\t\t\tz-index: 2147483646; max-width: calc(100vw - 32px);\n\t\t\tfont: 13px/1 -apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif;\n\t\t\tcolor: #fff;\n\t\t}\n\t\t.bar {\n\t\t\tdisplay: inline-flex; align-items: center; gap: 10px;\n\t\t\tpadding: 8px 14px 8px 12px;\n\t\t\tbackground: rgba(17,17,17,0.78);\n\t\t\tborder-radius: 999px;\n\t\t\tbox-shadow: 0 8px 24px rgba(0,0,0,0.18);\n\t\t\tbackdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);\n\t\t\tmax-width: 100%;\n\t\t}\n\t\t.panel {\n\t\t\tbackground: rgba(17,17,17,0.88);\n\t\t\tborder-radius: 14px; padding: 12px 14px 12px 8px;\n\t\t\tline-height: 1.45;\n\t\t\tbox-shadow: 0 12px 32px rgba(0,0,0,0.28);\n\t\t\tmax-height: min(60vh, 480px);\n\t\t\tmax-width: min(420px, calc(100vw - 32px));\n\t\t\twidth: max-content; overflow-y: auto;\n\t\t}\n\t\t.panel[hidden] { display: none; }\n\t\t.panel ol { margin: 0; padding-left: 26px; }\n\t\t.panel li { margin: 0 0 8px; }\n\t\t.panel li:last-child { margin: 0; }\n\t\t.dot {\n\t\t\twidth: 8px; height: 8px; border-radius: 50%;\n\t\t\tbackground: #ef4444;\n\t\t\tbox-shadow: 0 0 0 0 rgba(239, 68, 68, 0.6);\n\t\t\tanimation: pulse 1.6s ease-out infinite;\n\t\t}\n\t\t.dot[data-state=\"no-audio\"] { background: #fbbf24; animation: none; }\n\t\t.dot[data-state=\"finishing\"] { background: #fbbf24; animation: none; }\n\t\t.dot[data-state=\"done\"] { background: #10b981; animation: none; }\n\t\t.dot[data-state=\"error\"] { background: #ef4444; animation: none; }\n\t\t.label { font-weight: 500; letter-spacing: 0.01em; }\n\t\t.spacer { width: 1px; height: 16px; background: rgba(255,255,255,0.18); margin: 0 2px; }\n\t\t.btn {\n\t\t\tappearance: none; border: 0; background: rgba(255,255,255,0.12);\n\t\t\tcolor: #fff; font: inherit; font-weight: 600;\n\t\t\tpadding: 6px 12px; border-radius: 999px; cursor: pointer;\n\t\t\ttransition: background 0.15s ease;\n\t\t}\n\t\t.btn:hover { background: rgba(255,255,255,0.22); }\n\t\t.btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }\n\t\t.btn[disabled] { opacity: 0.5; cursor: progress; }\n\t\t.tasks-btn[aria-expanded=\"true\"] { background: rgba(255,255,255,0.24); }\n\t\t@media (max-width: 420px) { .btn { padding: 9px 14px; min-height: 40px; } }\n\t\t.thanks {\n\t\t\tposition: fixed; inset: 0;\n\t\t\tdisplay: grid; place-items: center;\n\t\t\tbackground: rgba(15, 15, 17, 0.78);\n\t\t\tbackdrop-filter: blur(6px);\n\t\t\t-webkit-backdrop-filter: blur(6px);\n\t\t\tcolor: #fff;\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif;\n\t\t\tz-index: 2147483647;\n\t\t\tpadding: 24px;\n\t\t\ttext-align: center;\n\t\t}\n\t\t.thanks-card {\n\t\t\tbackground: #fff; color: #111;\n\t\t\tborder-radius: 16px; padding: 28px 24px;\n\t\t\tmax-width: 360px; width: 100%;\n\t\t\tbox-shadow: 0 20px 50px rgba(0,0,0,0.25);\n\t\t}\n\t\t.thanks h2 { margin: 0 0 8px; font-size: 20px; }\n\t\t.thanks p { margin: 0; font-size: 14px; line-height: 1.45; color: #4b5563; }\n\t\t.thanks .check {\n\t\t\twidth: 44px; height: 44px; border-radius: 50%;\n\t\t\tbackground: #10b981; color: #fff;\n\t\t\tdisplay: grid; place-items: center;\n\t\t\tmargin: 0 auto 12px;\n\t\t\tfont-size: 22px;\n\t\t}\n\t\t@keyframes pulse {\n\t\t\t0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.55); }\n\t\t\t70% { box-shadow: 0 0 0 10px rgba(239,68,68,0); }\n\t\t\t100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); }\n\t\t}\n\t\t@media (prefers-reduced-motion: reduce) {\n\t\t\t.dot { animation: none; }\n\t\t}\n\t`\n\tconst anchor = document.createElement('div')\n\tanchor.className = 'anchor'\n\n\tconst panel = document.createElement('div')\n\tpanel.className = 'panel'\n\tpanel.hidden = true\n\n\tconst bar = document.createElement('div')\n\tbar.className = 'bar'\n\tbar.setAttribute('role', 'status')\n\tbar.setAttribute('aria-live', 'polite')\n\n\tconst dot = document.createElement('span')\n\tdot.className = 'dot'\n\tdot.setAttribute('data-state', store.indicatorState)\n\n\tconst label = document.createElement('span')\n\tlabel.className = 'label'\n\tlabel.textContent = 'Recording'\n\n\tconst spacer = document.createElement('span')\n\tspacer.className = 'spacer'\n\n\tbar.appendChild(dot)\n\tbar.appendChild(label)\n\tbar.appendChild(spacer)\n\n\tconst btn = document.createElement('button')\n\tbtn.type = 'button'\n\tbtn.className = 'btn finish-btn'\n\tbtn.textContent = 'Finish'\n\tbtn.addEventListener('click', onFinish)\n\tbar.appendChild(btn)\n\n\tif (store.tasks.length > 0) installTasksToggle(bar, btn, store, onToggleTasks)\n\n\tanchor.appendChild(panel)\n\tanchor.appendChild(bar)\n\n\troot.appendChild(style)\n\troot.appendChild(anchor)\n\treturn root\n}\n\nfunction installTasksToggle(bar: HTMLElement, finishBtn: HTMLElement, store: RecorderStore, onToggleTasks: () => void): void {\n\tconst tasksBtn = document.createElement('button')\n\ttasksBtn.type = 'button'\n\ttasksBtn.className = 'btn tasks-btn'\n\ttasksBtn.textContent = `Tasks (${store.tasks.length})`\n\ttasksBtn.setAttribute('aria-expanded', store.tasksPanelOpen ? 'true' : 'false')\n\ttasksBtn.addEventListener('click', onToggleTasks)\n\tbar.insertBefore(tasksBtn, finishBtn)\n}\n\nfunction renderTasksPanel(store: RecorderStore): void {\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst panel = root.querySelector('.panel')\n\tif (!(panel instanceof HTMLElement)) return\n\t// Build content once.\n\tif (!panel.firstChild && store.tasks.length > 0) {\n\t\tconst ol = document.createElement('ol')\n\t\tfor (const task of store.tasks) {\n\t\t\tconst li = document.createElement('li')\n\t\t\tli.textContent = task.prompt\n\t\t\tol.appendChild(li)\n\t\t}\n\t\tpanel.appendChild(ol)\n\t}\n\tpanel.hidden = !store.tasksPanelOpen\n\tconst tasksBtn = root.querySelector('.tasks-btn')\n\tif (tasksBtn instanceof HTMLElement) {\n\t\ttasksBtn.setAttribute('aria-expanded', store.tasksPanelOpen ? 'true' : 'false')\n\t}\n}\n\nfunction readTasksPanelOpen(): boolean {\n\ttry { return window.sessionStorage?.getItem(TASKS_PANEL_OPEN_STORAGE_KEY) === '1' } catch { return false }\n}\nfunction writeTasksPanelOpen(open: boolean): void {\n\ttry { window.sessionStorage?.setItem(TASKS_PANEL_OPEN_STORAGE_KEY, open ? '1' : '0') } catch { /* ignore */ }\n}\n\nfunction renderIndicatorState(store: RecorderStore): void {\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst dot = root.querySelector('.dot')\n\tconst label = root.querySelector('.label')\n\tconst btn = root.querySelector<HTMLButtonElement>('.finish-btn')\n\tif (!(dot instanceof HTMLElement) || !(label instanceof HTMLElement) || !btn) return\n\tdot.setAttribute('data-state', store.indicatorState)\n\tswitch (store.indicatorState) {\n\t\tcase 'recording':\n\t\t\tlabel.textContent = 'Recording'\n\t\t\tbtn.textContent = 'Finish'\n\t\t\tbtn.disabled = false\n\t\t\tbreak\n\t\tcase 'no-audio':\n\t\t\tlabel.textContent = 'No mic, replay only'\n\t\t\tbtn.textContent = 'Finish'\n\t\t\tbtn.disabled = false\n\t\t\tbreak\n\t\tcase 'finishing':\n\t\t\tlabel.textContent = 'Saving'\n\t\t\tbtn.textContent = 'Saving'\n\t\t\tbtn.disabled = true\n\t\t\tbreak\n\t\tcase 'done':\n\t\t\tlabel.textContent = 'Saved'\n\t\t\tbtn.textContent = 'Done'\n\t\t\tbtn.disabled = true\n\t\t\tbreak\n\t\tcase 'error':\n\t\t\tlabel.textContent = 'Save failed'\n\t\t\tbtn.textContent = 'Retry'\n\t\t\tbtn.disabled = false\n\t\t\tbreak\n\t}\n}\n\nfunction showThanksScreen(root: ShadowRoot): void {\n\tconst overlay = document.createElement('div')\n\toverlay.className = 'thanks'\n\toverlay.innerHTML = `\n\t\t<div class=\"thanks-card\">\n\t\t\t<div class=\"check\" aria-hidden=\"true\">&#10003;</div>\n\t\t\t<h2>Thanks for testing</h2>\n\t\t\t<p>Your session was saved. You can close this tab.</p>\n\t\t</div>\n\t`\n\troot.appendChild(overlay)\n}\n\nfunction parseTasks(raw: unknown): UserTestTask[] {\n\tif (!Array.isArray(raw)) return []\n\tconst out = raw.flatMap((item: unknown): UserTestTask[] => {\n\t\tconst t = item as { id?: unknown; prompt?: unknown; sortOrder?: unknown }\n\t\tif (!t || typeof t.id !== 'string' || typeof t.prompt !== 'string' || typeof t.sortOrder !== 'number') return []\n\t\treturn [{ id: t.id, prompt: t.prompt, sortOrder: t.sortOrder }]\n\t})\n\tout.sort((a, b) => a.sortOrder - b.sortOrder)\n\treturn out\n}\n\nasync function createSession(\n\tapiUrl: string,\n\tslug: string,\n\ttesterName: string | undefined,\n): Promise<{ sessionId: string; clientId: string; tasks: UserTestTask[] } | null> {\n\ttry {\n\t\tconst res = await fetch(`${apiUrl.replace(/\\/$/, '')}/api/user-test-sessions`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ slug, ...(testerName ? { testerName } : {}) }),\n\t\t})\n\t\tif (!res.ok) return null\n\t\tconst json = (await res.json()) as { sessionId?: unknown; clientId?: unknown; tasks?: unknown }\n\t\tif (typeof json.sessionId !== 'string' || typeof json.clientId !== 'string') return null\n\t\treturn { sessionId: json.sessionId, clientId: json.clientId, tasks: parseTasks(json.tasks) }\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function finaliseSession(\n\tapiUrl: string,\n\tsessionId: string,\n\tdurationSeconds: number,\n): Promise<boolean> {\n\ttry {\n\t\tconst res = await fetch(`${apiUrl.replace(/\\/$/, '')}/api/user-test-sessions/${encodeURIComponent(sessionId)}/finalise`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ durationSeconds: Math.max(0, Math.round(durationSeconds)) }),\n\t\t\tkeepalive: true,\n\t\t})\n\t\treturn res.ok\n\t} catch {\n\t\treturn false\n\t}\n}\n\nasync function flushPendingFromIdb(store: RecorderStore, ctx: PluginContext): Promise<void> {\n\tif (!store.sessionId) return\n\tconst pending = await idbListChunks(store.sessionId)\n\tfor (const chunk of pending) {\n\t\tconst ok = await uploadChunkWithRetry(chunk.apiUrl, chunk.sessionId, chunk.chunkIndex, chunk.blob, ctx.logger, 3)\n\t\tif (ok) await idbDeleteChunk(chunk.id)\n\t}\n}\n\nfunction enqueueChunk(store: RecorderStore, ctx: PluginContext, blob: Blob): void {\n\tif (store.cancelled || !store.sessionId || blob.size === 0) return\n\tconst index = store.chunkIndex\n\tstore.chunkIndex += 1\n\tstore.pendingUploads += 1\n\tconst sessionId = store.sessionId\n\tconst apiUrl = store.options.apiUrl\n\n\tstore.uploadQueue = store.uploadQueue.then(async () => {\n\t\tconst ok = await uploadChunkWithRetry(apiUrl, sessionId, index, blob, ctx.logger)\n\t\tif (!ok) {\n\t\t\tctx.logger.warn(`chunk ${index} stashed for offline retry`)\n\t\t\tawait idbStashChunk({\n\t\t\t\tid: `${sessionId}:${index}:${Date.now()}`,\n\t\t\t\tsessionId,\n\t\t\t\tapiUrl,\n\t\t\t\tchunkIndex: index,\n\t\t\t\tblob,\n\t\t\t\tcreatedAt: Date.now(),\n\t\t\t})\n\t\t}\n\t\tstore.pendingUploads -= 1\n\t})\n}\n\nasync function startRecording(store: RecorderStore, ctx: PluginContext): Promise<void> {\n\tif (!isMediaRecorderSupported()) {\n\t\tctx.logger.warn('MediaRecorder not supported, continuing without audio')\n\t\tstore.indicatorState = 'no-audio'\n\t\trenderIndicatorState(store)\n\t\treturn\n\t}\n\tlet stream: MediaStream\n\ttry {\n\t\tstream = await navigator.mediaDevices.getUserMedia({ audio: true })\n\t} catch (err) {\n\t\tctx.logger.warn('mic permission denied or unavailable', err)\n\t\tstore.indicatorState = 'no-audio'\n\t\trenderIndicatorState(store)\n\t\treturn\n\t}\n\tstore.stream = stream\n\tconst mimeType = pickMimeType()\n\tlet recorder: MediaRecorder\n\ttry {\n\t\trecorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream)\n\t} catch (err) {\n\t\tctx.logger.error('MediaRecorder construction failed', err)\n\t\tstream.getTracks().forEach(t => t.stop())\n\t\tstore.stream = null\n\t\tstore.indicatorState = 'no-audio'\n\t\trenderIndicatorState(store)\n\t\treturn\n\t}\n\tstore.recorder = recorder\n\trecorder.addEventListener('dataavailable', event => {\n\t\tif (event.data && event.data.size > 0) {\n\t\t\tenqueueChunk(store, ctx, event.data)\n\t\t}\n\t})\n\trecorder.addEventListener('error', event => {\n\t\tctx.logger.error('MediaRecorder error', event)\n\t})\n\t// `timeslice` makes the recorder emit a self-contained chunk every N ms.\n\trecorder.start(store.options.chunkSeconds * 1000)\n}\n\nfunction stopRecording(store: RecorderStore): void {\n\tconst recorder = store.recorder\n\tif (recorder && recorder.state !== 'inactive') {\n\t\ttry {\n\t\t\trecorder.requestData()\n\t\t} catch {\n\t\t\t// requestData throws if state is invalid; ignore.\n\t\t}\n\t\ttry {\n\t\t\trecorder.stop()\n\t\t} catch {\n\t\t\t// already stopped\n\t\t}\n\t}\n\tstore.recorder = null\n\tif (store.stream) {\n\t\tstore.stream.getTracks().forEach(t => t.stop())\n\t\tstore.stream = null\n\t}\n}\n\nasync function finishFlow(store: RecorderStore, ctx: PluginContext, opts: { showThanks: boolean }): Promise<void> {\n\tif (store.cancelled) return\n\tif (store.indicatorState === 'finishing' || store.indicatorState === 'done') return\n\tstore.indicatorState = 'finishing'\n\trenderIndicatorState(store)\n\n\tstopRecording(store)\n\t// Wait for the queued uploads to drain. Each upload already has its own\n\t// retry/backoff; this just lets them finish before finalise fires.\n\tawait store.uploadQueue\n\tawait flushPendingFromIdb(store, ctx)\n\n\tconst durationSeconds = (Date.now() - store.startedAt) / 1000\n\tif (store.sessionId) {\n\t\tconst ok = await finaliseSession(store.options.apiUrl, store.sessionId, durationSeconds)\n\t\tstore.indicatorState = ok ? 'done' : 'error'\n\t} else {\n\t\tstore.indicatorState = 'error'\n\t}\n\trenderIndicatorState(store)\n\n\tif (opts.showThanks && store.indicatorRoot && store.indicatorState === 'done') {\n\t\tshowThanksScreen(store.indicatorRoot)\n\t}\n}\n\nexport function userTest(options: UserTestOptions = {}): UseroPlugin {\n\tconst merged: Required<UserTestOptions> = {\n\t\tqueryParam: options.queryParam ?? DEFAULT_OPTIONS.queryParam,\n\t\tchunkSeconds: options.chunkSeconds ?? DEFAULT_OPTIONS.chunkSeconds,\n\t\tapiUrl: options.apiUrl ?? DEFAULT_OPTIONS.apiUrl,\n\t\ttesterName: options.testerName ?? DEFAULT_OPTIONS.testerName,\n\t\thideIndicator: options.hideIndicator ?? DEFAULT_OPTIONS.hideIndicator,\n\t}\n\n\treturn {\n\t\tname: 'user-test',\n\t\tonInit(ctx) {\n\t\t\tif (typeof window === 'undefined' || typeof document === 'undefined') return\n\t\t\tconst slug = getTestSlug(merged.queryParam)\n\t\t\tif (!slug) return\n\n\t\t\tconst apiUrl = merged.apiUrl || ctx.baseUrl || DEFAULT_API_URL\n\t\t\tconst store: RecorderStore = {\n\t\t\t\tcancelled: false,\n\t\t\t\tslug,\n\t\t\t\tsessionId: null,\n\t\t\t\tclientId: null,\n\t\t\t\trecorder: null,\n\t\t\t\tstream: null,\n\t\t\t\tchunkIndex: 0,\n\t\t\t\tuploadQueue: Promise.resolve(),\n\t\t\t\tpendingUploads: 0,\n\t\t\t\tstartedAt: Date.now(),\n\t\t\t\tindicator: null,\n\t\t\t\tindicatorRoot: null,\n\t\t\t\tindicatorState: 'recording',\n\t\t\t\tpageHideHandler: null,\n\t\t\t\toptions: { ...merged, apiUrl },\n\t\t\t\ttasks: [],\n\t\t\t\ttasksPanelOpen: readTasksPanelOpen(),\n\t\t\t\toutsidePointerHandler: null,\n\t\t\t\tkeydownHandler: null,\n\t\t\t}\n\t\t\tctx.setStore(store)\n\n\t\t\tconst onFinish = (): void => {\n\t\t\t\tvoid finishFlow(store, ctx, { showThanks: true })\n\t\t\t}\n\n\t\t\tconst setPanelOpen = (open: boolean): void => {\n\t\t\t\tif (store.tasksPanelOpen === open) return\n\t\t\t\tstore.tasksPanelOpen = open\n\t\t\t\twriteTasksPanelOpen(open)\n\t\t\t\trenderTasksPanel(store)\n\t\t\t}\n\n\t\t\tconst onToggleTasks = (): void => setPanelOpen(!store.tasksPanelOpen)\n\n\t\t\tif (!merged.hideIndicator) {\n\t\t\t\tconst host = document.createElement('div')\n\t\t\t\thost.setAttribute('data-usero-user-test', 'true')\n\t\t\t\tdocument.body.appendChild(host)\n\t\t\t\tstore.indicator = host\n\t\t\t\tstore.indicatorRoot = buildIndicator(host, store, onFinish, onToggleTasks)\n\t\t\t\trenderIndicatorState(store)\n\t\t\t}\n\n\t\t\t// Outside-click + Escape close the tasks panel. Listen on document\n\t\t\t// (composedPath checks shadow ancestry so taps on the panel/pill\n\t\t\t// itself don't dismiss).\n\t\t\tconst outsidePointer = (event: PointerEvent): void => {\n\t\t\t\tif (!store.tasksPanelOpen) return\n\t\t\t\tconst host = store.indicator\n\t\t\t\tif (!host) return\n\t\t\t\tconst path = event.composedPath()\n\t\t\t\tif (!path.includes(host)) setPanelOpen(false)\n\t\t\t}\n\t\t\tconst onKeydown = (event: KeyboardEvent): void => {\n\t\t\t\tif (event.key === 'Escape' && store.tasksPanelOpen) setPanelOpen(false)\n\t\t\t}\n\t\t\tstore.outsidePointerHandler = outsidePointer\n\t\t\tstore.keydownHandler = onKeydown\n\t\t\tdocument.addEventListener('pointerdown', outsidePointer, true)\n\t\t\tdocument.addEventListener('keydown', onKeydown)\n\n\t\t\tconst pageHide = (): void => {\n\t\t\t\t// Best-effort flush + finalise. We don't await here; the browser\n\t\t\t\t// is shutting the page down. `keepalive: true` on finalise lets\n\t\t\t\t// the request race the unload.\n\t\t\t\tvoid finishFlow(store, ctx, { showThanks: false })\n\t\t\t}\n\t\t\tstore.pageHideHandler = pageHide\n\t\t\twindow.addEventListener('pagehide', pageHide)\n\n\t\t\tvoid (async (): Promise<void> => {\n\t\t\t\tconst created = await createSession(apiUrl, slug, readTesterName(merged.testerName))\n\t\t\t\tif (store.cancelled) return\n\t\t\t\tif (!created) {\n\t\t\t\t\tctx.logger.error('failed to create user-test session')\n\t\t\t\t\tstore.indicatorState = 'error'\n\t\t\t\t\trenderIndicatorState(store)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tstore.sessionId = created.sessionId\n\t\t\t\tstore.clientId = created.clientId\n\t\t\t\tstore.tasks = created.tasks\n\t\t\t\tif (store.tasks.length > 0 && store.indicatorRoot && !merged.hideIndicator) {\n\t\t\t\t\tconst bar = store.indicatorRoot.querySelector('.bar')\n\t\t\t\t\tconst finishBtn = bar?.querySelector('.finish-btn')\n\t\t\t\t\tif (bar instanceof HTMLElement && finishBtn instanceof HTMLElement && !bar.querySelector('.tasks-btn')) {\n\t\t\t\t\t\tinstallTasksToggle(bar, finishBtn, store, onToggleTasks)\n\t\t\t\t\t}\n\t\t\t\t\trenderTasksPanel(store)\n\t\t\t\t}\n\t\t\t\tawait startRecording(store, ctx)\n\t\t\t\trenderIndicatorState(store)\n\t\t\t})()\n\t\t},\n\t\tonDestroy(ctx) {\n\t\t\tconst store = ctx.getStore<RecorderStore>()\n\t\t\tif (!store) return\n\t\t\tstore.cancelled = true\n\t\t\tif (store.pageHideHandler) {\n\t\t\t\twindow.removeEventListener('pagehide', store.pageHideHandler)\n\t\t\t\tstore.pageHideHandler = null\n\t\t\t}\n\t\t\tstopRecording(store)\n\t\t\tif (store.outsidePointerHandler) {\n\t\t\t\tdocument.removeEventListener('pointerdown', store.outsidePointerHandler, true)\n\t\t\t\tstore.outsidePointerHandler = null\n\t\t\t}\n\t\t\tif (store.keydownHandler) {\n\t\t\t\tdocument.removeEventListener('keydown', store.keydownHandler)\n\t\t\t\tstore.keydownHandler = null\n\t\t\t}\n\t\t\tif (store.indicator && store.indicator.parentNode) {\n\t\t\t\tstore.indicator.parentNode.removeChild(store.indicator)\n\t\t\t}\n\t\t\tstore.indicator = null\n\t\t\tstore.indicatorRoot = null\n\t\t},\n\t}\n}\n\n// Internal helpers exposed for tests only. Not part of the public API.\nexport const __test__ = { getTestSlug, pickMimeType, isMediaRecorderSupported }\n"]}
1
+ {"version":3,"sources":["../../src/types.ts","../../src/plugins/user-test.ts"],"names":[],"mappings":"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","file":"user-test.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","// User-testing-mode plugin for the Usero widget.\n//\n// Activates ONLY when the host page URL carries `?usero_test=<slug>`. When\n// active, it:\n// 1. Creates a UserTestSession on the SaaS side via\n// POST /api/user-test-sessions\n// 2. Starts a MediaRecorder on the user's microphone (Opus in WebM) and\n// ships chunks every `chunkSeconds` to\n// PUT /api/user-test-sessions/:id/chunk?index=N\n// 3. Renders a small floating \"recording\" indicator with a Finish button\n// bottom-center so the tester can stop on their own.\n// 4. On Finish (or `pagehide`), flushes any buffered chunks and calls\n// POST /api/user-test-sessions/:id/finalise.\n//\n// Mic-permission denied is non-fatal: the session is still created (the\n// session-replay plugin keeps recording in parallel) and the indicator\n// shows a \"no audio\" hint. The SaaS side detects audio presence from the\n// first chunk; if no chunks land, hasAudio stays false there too.\n//\n// Bundle hygiene: this module is a subpath export and does NOT depend on\n// rrweb or any other heavy dep — just the native MediaRecorder API. The\n// floating UI is shadow-DOM scoped so host page CSS can't leak in.\n//\n// Privacy: only the microphone is recorded. We never read DOM text, never\n// touch the camera, and never persist audio in the browser past the\n// IndexedDB fallback (cleared on successful upload).\n\nimport type { UseroPlugin, PluginContext } from '../plugin'\nimport { DEFAULT_API_URL } from '../types'\n\nexport interface UserTestOptions {\n\t// URL query param the welcome page appends to redirect testers back.\n\t// Default `usero_test`. Match SaaS side if you ever change it.\n\tqueryParam?: string\n\t// Audio chunk length in seconds. Smaller = more partial-data resilience\n\t// but more requests. Default 30.\n\tchunkSeconds?: number\n\t// API origin. Override for self-hosted or local dev. Defaults to the\n\t// shared SDK constant (https://usero.io).\n\tapiUrl?: string\n\t// Override the tester-name shown on the SaaS side. Normally the welcome\n\t// page collects this and stores it in localStorage; the plugin reads it\n\t// from there. This option lets a host site bypass that.\n\ttesterName?: string\n\t// Hide the floating indicator. The plugin still records and finalises\n\t// on `pagehide`, but the tester gets no on-page UI. Useful if the host\n\t// page wants to render its own.\n\thideIndicator?: boolean\n}\n\ninterface UserTestTask {\n\tid: string\n\tprompt: string\n\tsortOrder: number\n}\n\ninterface MutedSegment {\n\tstartMs: number\n\tendMs: number\n}\n\ninterface InFlightNote {\n\tatMs: number\n\ttext: string\n}\n\ninterface RecorderStore {\n\tcancelled: boolean\n\tslug: string\n\tsessionId: string | null\n\tclientId: string | null\n\trecorder: MediaRecorder | null\n\tstream: MediaStream | null\n\tchunkIndex: number\n\tuploadQueue: Promise<void>\n\tpendingUploads: number\n\tstartedAt: number\n\tindicator: HTMLElement | null\n\tindicatorRoot: ShadowRoot | null\n\tindicatorState: 'recording' | 'finishing' | 'done' | 'no-audio' | 'error'\n\tpageHideHandler: (() => void) | null\n\toptions: Required<UserTestOptions>\n\ttasks: UserTestTask[]\n\ttasksPanelOpen: boolean\n\toutsidePointerHandler: ((event: PointerEvent) => void) | null\n\tkeydownHandler: ((event: KeyboardEvent) => void) | null\n\t// Mic mute\n\thasMicPermission: boolean\n\tmuted: boolean\n\tmutedSinceMs: number | null\n\tmutedSegments: MutedSegment[]\n\tmuteToastShown: boolean\n\t// In-flight notes\n\tnotes: InFlightNote[]\n\tnotesPopoverOpen: boolean\n\tnotePopoverAtMs: number | null\n\t// End-of-test comment (collected on thanks screen)\n\tendNote: string\n}\n\nconst DEFAULT_OPTIONS: Required<Omit<UserTestOptions, 'testerName' | 'apiUrl'>> & {\n\ttesterName: string\n\tapiUrl: string\n} = {\n\tqueryParam: 'usero_test',\n\tchunkSeconds: 30,\n\tapiUrl: DEFAULT_API_URL,\n\ttesterName: '',\n\thideIndicator: false,\n}\n\nconst TESTER_NAME_STORAGE_KEY = 'usero:user-test:tester-name'\nconst TASKS_PANEL_OPEN_STORAGE_KEY = 'usero:user-test:tasks-panel-open'\nconst IDB_NAME = 'usero-user-test'\nconst IDB_STORE = 'pending-chunks'\n\ninterface PendingChunk {\n\tid: string\n\tsessionId: string\n\tapiUrl: string\n\tchunkIndex: number\n\tblob: Blob\n\tcreatedAt: number\n}\n\nfunction readTesterName(override: string): string | undefined {\n\tif (override) return override\n\ttry {\n\t\tconst stored = window.localStorage?.getItem(TESTER_NAME_STORAGE_KEY)\n\t\tif (stored && stored.trim()) return stored.trim().slice(0, 120)\n\t} catch {\n\t\t// Storage access can throw in some sandboxed iframes — ignore.\n\t}\n\treturn undefined\n}\n\nfunction getTestSlug(queryParam: string): string | null {\n\tif (typeof window === 'undefined' || typeof window.location === 'undefined') return null\n\ttry {\n\t\tconst params = new URLSearchParams(window.location.search)\n\t\tconst slug = params.get(queryParam)\n\t\tif (!slug) return null\n\t\tconst cleaned = slug.trim().slice(0, 64)\n\t\tif (!/^[a-z0-9-]+$/i.test(cleaned)) return null\n\t\treturn cleaned\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction isMediaRecorderSupported(): boolean {\n\treturn typeof window !== 'undefined' && typeof window.MediaRecorder !== 'undefined' && typeof navigator !== 'undefined' && !!navigator.mediaDevices?.getUserMedia\n}\n\nfunction pickMimeType(): string | undefined {\n\tconst candidates = ['audio/webm;codecs=opus', 'audio/webm', 'audio/ogg;codecs=opus', 'audio/mp4']\n\tfor (const candidate of candidates) {\n\t\tif (typeof MediaRecorder !== 'undefined' && MediaRecorder.isTypeSupported?.(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\t}\n\treturn undefined\n}\n\n// IndexedDB helpers. Best-effort, never throw upstream — if IDB is missing\n// or quota-blown we just lose offline resilience but the live upload path\n// still runs.\nfunction idbOpen(): Promise<IDBDatabase | null> {\n\treturn new Promise(resolve => {\n\t\tif (typeof indexedDB === 'undefined') {\n\t\t\tresolve(null)\n\t\t\treturn\n\t\t}\n\t\ttry {\n\t\t\tconst req = indexedDB.open(IDB_NAME, 1)\n\t\t\treq.onupgradeneeded = (): void => {\n\t\t\t\tconst db = req.result\n\t\t\t\tif (!db.objectStoreNames.contains(IDB_STORE)) {\n\t\t\t\t\tdb.createObjectStore(IDB_STORE, { keyPath: 'id' })\n\t\t\t\t}\n\t\t\t}\n\t\t\treq.onsuccess = (): void => resolve(req.result)\n\t\t\treq.onerror = (): void => resolve(null)\n\t\t} catch {\n\t\t\tresolve(null)\n\t\t}\n\t})\n}\n\nasync function idbStashChunk(chunk: PendingChunk): Promise<void> {\n\tconst db = await idbOpen()\n\tif (!db) return\n\tawait new Promise<void>(resolve => {\n\t\ttry {\n\t\t\tconst tx = db.transaction(IDB_STORE, 'readwrite')\n\t\t\ttx.objectStore(IDB_STORE).put(chunk)\n\t\t\ttx.oncomplete = (): void => resolve()\n\t\t\ttx.onerror = (): void => resolve()\n\t\t\ttx.onabort = (): void => resolve()\n\t\t} catch {\n\t\t\tresolve()\n\t\t}\n\t})\n\tdb.close()\n}\n\nasync function idbDeleteChunk(id: string): Promise<void> {\n\tconst db = await idbOpen()\n\tif (!db) return\n\tawait new Promise<void>(resolve => {\n\t\ttry {\n\t\t\tconst tx = db.transaction(IDB_STORE, 'readwrite')\n\t\t\ttx.objectStore(IDB_STORE).delete(id)\n\t\t\ttx.oncomplete = (): void => resolve()\n\t\t\ttx.onerror = (): void => resolve()\n\t\t\ttx.onabort = (): void => resolve()\n\t\t} catch {\n\t\t\tresolve()\n\t\t}\n\t})\n\tdb.close()\n}\n\nasync function idbListChunks(sessionId: string): Promise<PendingChunk[]> {\n\tconst db = await idbOpen()\n\tif (!db) return []\n\tconst items = await new Promise<PendingChunk[]>(resolve => {\n\t\ttry {\n\t\t\tconst tx = db.transaction(IDB_STORE, 'readonly')\n\t\t\tconst req = tx.objectStore(IDB_STORE).getAll()\n\t\t\treq.onsuccess = (): void => {\n\t\t\t\tconst all = (req.result as PendingChunk[]) ?? []\n\t\t\t\tresolve(all.filter(c => c.sessionId === sessionId))\n\t\t\t}\n\t\t\treq.onerror = (): void => resolve([])\n\t\t} catch {\n\t\t\tresolve([])\n\t\t}\n\t})\n\tdb.close()\n\treturn items\n}\n\nasync function uploadChunkWithRetry(\n\tapiUrl: string,\n\tsessionId: string,\n\tindex: number,\n\tblob: Blob,\n\tlogger: PluginContext['logger'],\n\tmaxAttempts = 5,\n): Promise<boolean> {\n\tconst url = `${apiUrl.replace(/\\/$/, '')}/api/user-test-sessions/${encodeURIComponent(sessionId)}/chunk?index=${index}`\n\tlet attempt = 0\n\twhile (attempt < maxAttempts) {\n\t\ttry {\n\t\t\tconst res = await fetch(url, {\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tbody: blob,\n\t\t\t\theaders: { 'Content-Type': blob.type || 'audio/webm' },\n\t\t\t\tkeepalive: blob.size <= 60 * 1024, // browsers cap keepalive bodies\n\t\t\t})\n\t\t\tif (res.ok) return true\n\t\t\t// 4xx (other than 413) won't get better with retries; bail early.\n\t\t\tif (res.status >= 400 && res.status < 500 && res.status !== 408 && res.status !== 429) {\n\t\t\t\tlogger.error(`chunk ${index} rejected with ${res.status}`)\n\t\t\t\treturn false\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tlogger.warn(`chunk ${index} upload attempt ${attempt + 1} failed`, err)\n\t\t}\n\t\tattempt += 1\n\t\tconst backoff = Math.min(15000, 500 * 2 ** attempt) + Math.floor(Math.random() * 250)\n\t\tawait new Promise(resolve => setTimeout(resolve, backoff))\n\t}\n\treturn false\n}\n\ninterface IndicatorCallbacks {\n\tonFinish: () => void\n\tonToggleTasks: () => void\n\tonToggleMute: () => void\n\tonOpenNote: () => void\n}\n\nfunction buildIndicator(host: HTMLElement, store: RecorderStore, callbacks: IndicatorCallbacks): ShadowRoot {\n\tconst root = host.attachShadow({ mode: 'closed' })\n\tconst style = document.createElement('style')\n\t// Compact, glassy dark pill. Mic chip is now a real button with three\n\t// states (recording / muted / no-mic). Notes button sits beside it.\n\tstyle.textContent = `\n\t\t:host { all: initial; }\n\t\t.anchor {\n\t\t\tposition: fixed;\n\t\t\tbottom: calc(env(safe-area-inset-bottom, 0px) + 16px);\n\t\t\tleft: 50%; transform: translateX(-50%);\n\t\t\tdisplay: flex; flex-direction: column; align-items: center; gap: 8px;\n\t\t\tz-index: 2147483646; max-width: calc(100vw - 32px);\n\t\t\tfont: 13px/1 -apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif;\n\t\t\tcolor: #fff;\n\t\t}\n\t\t.bar {\n\t\t\tdisplay: inline-flex; align-items: center; gap: 6px;\n\t\t\tpadding: 6px 8px 6px 6px;\n\t\t\tbackground: rgba(17,17,17,0.82);\n\t\t\tborder: 1px solid rgba(255,255,255,0.08);\n\t\t\tborder-radius: 999px;\n\t\t\tbox-shadow: 0 8px 24px rgba(0,0,0,0.22);\n\t\t\tbackdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);\n\t\t\tmax-width: 100%;\n\t\t}\n\t\t.panel {\n\t\t\tbackground: rgba(17,17,17,0.92);\n\t\t\tborder: 1px solid rgba(255,255,255,0.08);\n\t\t\tborder-radius: 14px; padding: 12px 14px 12px 8px;\n\t\t\tline-height: 1.45;\n\t\t\tbox-shadow: 0 12px 32px rgba(0,0,0,0.32);\n\t\t\tmax-height: min(60vh, 480px);\n\t\t\tmax-width: min(420px, calc(100vw - 32px));\n\t\t\twidth: max-content; overflow-y: auto;\n\t\t}\n\t\t.panel[hidden] { display: none; }\n\t\t.panel ol { margin: 0; padding-left: 26px; }\n\t\t.panel li { margin: 0 0 8px; }\n\t\t.panel li:last-child { margin: 0; }\n\n\t\t/* Mic chip: pill-within-pill with dot + label, doubles as mute toggle. */\n\t\t.mic {\n\t\t\tdisplay: inline-flex; align-items: center; gap: 7px;\n\t\t\tmin-height: 32px; min-width: 44px;\n\t\t\tpadding: 0 11px 0 10px;\n\t\t\tborder-radius: 999px;\n\t\t\tbackground: rgba(255,255,255,0.06);\n\t\t\tborder: 1px solid rgba(255,255,255,0.06);\n\t\t\tcolor: #fff; font: inherit;\n\t\t\tcursor: pointer; appearance: none;\n\t\t\ttransition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;\n\t\t}\n\t\t.mic:hover { background: rgba(255,255,255,0.12); }\n\t\t.mic:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }\n\t\t.mic[data-mic-state=\"muted\"] {\n\t\t\tbackground: rgba(251, 191, 36, 0.18);\n\t\t\tborder-color: rgba(251, 191, 36, 0.45);\n\t\t\tcolor: #fcd34d;\n\t\t}\n\t\t.mic[data-mic-state=\"muted\"]:hover { background: rgba(251, 191, 36, 0.26); }\n\t\t.mic[data-mic-state=\"none\"] {\n\t\t\tbackground: rgba(255,255,255,0.04);\n\t\t\tcolor: rgba(255,255,255,0.55);\n\t\t\tcursor: default;\n\t\t}\n\t\t.mic[data-mic-state=\"none\"]:hover { background: rgba(255,255,255,0.04); }\n\t\t.mic-icon { width: 13px; height: 13px; display: inline-block; flex-shrink: 0; }\n\t\t.mic-label { font-weight: 500; letter-spacing: 0.01em; white-space: nowrap; }\n\n\t\t.dot {\n\t\t\twidth: 7px; height: 7px; border-radius: 50%;\n\t\t\tbackground: #ef4444;\n\t\t\tbox-shadow: 0 0 0 0 rgba(239, 68, 68, 0.6);\n\t\t\tanimation: pulse 1.6s ease-out infinite;\n\t\t\tflex-shrink: 0;\n\t\t}\n\t\t.dot[data-state=\"no-audio\"] { background: #fbbf24; animation: none; }\n\t\t.dot[data-state=\"finishing\"] { background: #fbbf24; animation: none; }\n\t\t.dot[data-state=\"done\"] { background: #10b981; animation: none; }\n\t\t.dot[data-state=\"error\"] { background: #ef4444; animation: none; }\n\n\t\t.btn {\n\t\t\tappearance: none; border: 0; background: rgba(255,255,255,0.10);\n\t\t\tcolor: #fff; font: inherit; font-weight: 600;\n\t\t\tpadding: 6px 12px; min-height: 32px; border-radius: 999px; cursor: pointer;\n\t\t\ttransition: background 0.15s ease, transform 0.06s ease;\n\t\t\tdisplay: inline-flex; align-items: center; gap: 6px;\n\t\t}\n\t\t.btn:hover { background: rgba(255,255,255,0.20); }\n\t\t.btn:active { transform: scale(0.97); }\n\t\t.btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }\n\t\t.btn[disabled] { opacity: 0.5; cursor: progress; }\n\t\t.tasks-btn[aria-expanded=\"true\"] { background: rgba(255,255,255,0.24); }\n\n\t\t/* Note button: icon-only, matches mic chip footprint */\n\t\t.note-btn {\n\t\t\twidth: 32px; min-height: 32px; padding: 0;\n\t\t\tbackground: rgba(255,255,255,0.06);\n\t\t\tborder: 1px solid rgba(255,255,255,0.06);\n\t\t\tborder-radius: 999px;\n\t\t\tdisplay: inline-flex; align-items: center; justify-content: center; gap: 4px;\n\t\t\tcolor: #fff; font: inherit; cursor: pointer; appearance: none;\n\t\t\ttransition: background 0.15s ease, border-color 0.15s ease, width 0.18s ease;\n\t\t\toverflow: hidden;\n\t\t}\n\t\t.note-btn:hover { background: rgba(255,255,255,0.14); }\n\t\t.note-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }\n\t\t.note-btn[data-has-notes=\"true\"] { width: auto; padding: 0 10px 0 9px; gap: 6px; }\n\t\t.note-btn[aria-expanded=\"true\"] { background: rgba(255,255,255,0.22); border-color: rgba(255,255,255,0.18); }\n\t\t.note-icon { width: 14px; height: 14px; display: inline-block; }\n\t\t.note-count { font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }\n\n\t\t.spacer { width: 1px; height: 18px; background: rgba(255,255,255,0.14); margin: 0 1px; }\n\n\t\t@media (max-width: 480px) {\n\t\t\t.bar { gap: 4px; padding: 5px 6px 5px 5px; }\n\t\t\t.btn { padding: 7px 12px; min-height: 38px; }\n\t\t\t.mic, .note-btn { min-height: 38px; }\n\t\t\t.note-btn { width: 38px; }\n\t\t\t.note-btn[data-has-notes=\"true\"] { width: auto; }\n\t\t}\n\n\t\t/* First-mute helper toast: sits above the pill, auto-dismisses */\n\t\t.toast {\n\t\t\tbackground: rgba(17,17,17,0.92);\n\t\t\tborder: 1px solid rgba(251, 191, 36, 0.45);\n\t\t\tcolor: #fff;\n\t\t\tpadding: 9px 14px; border-radius: 12px;\n\t\t\tmax-width: min(340px, calc(100vw - 32px));\n\t\t\tbox-shadow: 0 12px 28px rgba(0,0,0,0.28);\n\t\t\ttext-align: center; line-height: 1.4;\n\t\t\tanimation: toast-in 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);\n\t\t}\n\t\t.toast[data-leaving=\"true\"] { animation: toast-out 0.24s ease forwards; }\n\t\t.toast strong { color: #fcd34d; font-weight: 600; }\n\t\t@keyframes toast-in {\n\t\t\tfrom { opacity: 0; transform: translateY(6px); }\n\t\t\tto { opacity: 1; transform: translateY(0); }\n\t\t}\n\t\t@keyframes toast-out {\n\t\t\tto { opacity: 0; transform: translateY(4px); }\n\t\t}\n\n\t\t/* Notes popover */\n\t\t.note-popover {\n\t\t\tbackground: rgba(17,17,17,0.94);\n\t\t\tborder: 1px solid rgba(255,255,255,0.10);\n\t\t\tborder-radius: 14px; padding: 12px;\n\t\t\twidth: min(340px, calc(100vw - 32px));\n\t\t\tbox-shadow: 0 18px 40px rgba(0,0,0,0.36);\n\t\t\tdisplay: flex; flex-direction: column; gap: 10px;\n\t\t\tanimation: pop-in 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);\n\t\t}\n\t\t.note-popover[hidden] { display: none; }\n\t\t@keyframes pop-in {\n\t\t\tfrom { opacity: 0; transform: translateY(6px) scale(0.98); }\n\t\t\tto { opacity: 1; transform: translateY(0) scale(1); }\n\t\t}\n\t\t.note-head {\n\t\t\tcolor: rgba(255,255,255,0.7); font-size: 12px;\n\t\t\tfont-weight: 500; letter-spacing: 0.02em;\n\t\t}\n\t\t.note-textarea {\n\t\t\twidth: 100%; box-sizing: border-box;\n\t\t\tmin-height: 80px; resize: vertical;\n\t\t\tpadding: 10px 11px;\n\t\t\tbackground: rgba(0,0,0,0.35);\n\t\t\tborder: 1px solid rgba(255,255,255,0.10);\n\t\t\tborder-radius: 10px;\n\t\t\tcolor: #fff; font: inherit; font-size: 13.5px;\n\t\t\tline-height: 1.45;\n\t\t\ttransition: border-color 0.15s ease;\n\t\t}\n\t\t.note-textarea:focus { outline: none; border-color: rgba(255,255,255,0.32); }\n\t\t.note-textarea::placeholder { color: rgba(255,255,255,0.42); }\n\t\t.note-actions {\n\t\t\tdisplay: flex; align-items: center; justify-content: space-between; gap: 8px;\n\t\t}\n\t\t.note-actions .hint {\n\t\t\tcolor: rgba(255,255,255,0.45); font-size: 11px;\n\t\t}\n\t\t.note-actions .group { display: inline-flex; gap: 6px; }\n\t\t.note-actions .btn { padding: 6px 12px; font-size: 12.5px; min-height: 32px; }\n\t\t.btn-primary { background: #fff !important; color: #111; }\n\t\t.btn-primary:hover { background: rgba(255,255,255,0.85) !important; }\n\t\t.btn-ghost { background: transparent; color: rgba(255,255,255,0.7); }\n\t\t.btn-ghost:hover { background: rgba(255,255,255,0.10); color: #fff; }\n\n\t\t/* Thanks overlay + end-of-test note */\n\t\t.thanks {\n\t\t\tposition: fixed; inset: 0;\n\t\t\tdisplay: grid; place-items: center;\n\t\t\tbackground: rgba(15, 15, 17, 0.78);\n\t\t\tbackdrop-filter: blur(6px);\n\t\t\t-webkit-backdrop-filter: blur(6px);\n\t\t\tcolor: #fff;\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", system-ui, sans-serif;\n\t\t\tz-index: 2147483647;\n\t\t\tpadding: 24px;\n\t\t\ttext-align: center;\n\t\t}\n\t\t.thanks-card {\n\t\t\tbackground: #fff; color: #111;\n\t\t\tborder-radius: 18px; padding: 28px 24px;\n\t\t\tmax-width: 420px; width: 100%;\n\t\t\tbox-shadow: 0 20px 50px rgba(0,0,0,0.25);\n\t\t\ttext-align: left;\n\t\t}\n\t\t.thanks-card .head { text-align: center; }\n\t\t.thanks h2 { margin: 0 0 6px; font-size: 20px; }\n\t\t.thanks .lede { margin: 0 0 18px; font-size: 14px; line-height: 1.45; color: #4b5563; text-align: center; }\n\t\t.thanks .check {\n\t\t\twidth: 44px; height: 44px; border-radius: 50%;\n\t\t\tbackground: #10b981; color: #fff;\n\t\t\tdisplay: grid; place-items: center;\n\t\t\tmargin: 0 auto 12px;\n\t\t\tfont-size: 22px;\n\t\t}\n\t\t.thanks .end-label {\n\t\t\tdisplay: block; margin: 0 0 8px;\n\t\t\tfont-size: 13px; font-weight: 500; color: #374151;\n\t\t}\n\t\t.thanks .end-textarea {\n\t\t\twidth: 100%; box-sizing: border-box;\n\t\t\tmin-height: 96px; resize: vertical;\n\t\t\tpadding: 11px 12px;\n\t\t\tbackground: #f9fafb;\n\t\t\tborder: 1px solid #e5e7eb;\n\t\t\tborder-radius: 10px;\n\t\t\tfont: inherit; font-size: 14px; line-height: 1.5;\n\t\t\tcolor: #111;\n\t\t\ttransition: border-color 0.15s ease, background 0.15s ease;\n\t\t}\n\t\t.thanks .end-textarea:focus {\n\t\t\toutline: none; border-color: #111; background: #fff;\n\t\t}\n\t\t.thanks .end-textarea::placeholder { color: #9ca3af; }\n\t\t.thanks .end-actions {\n\t\t\tdisplay: flex; gap: 10px; margin-top: 14px;\n\t\t}\n\t\t.thanks .end-actions button {\n\t\t\tflex: 1;\n\t\t\tappearance: none; border: 1px solid #e5e7eb;\n\t\t\tbackground: #fff; color: #111;\n\t\t\tpadding: 11px 14px; border-radius: 10px;\n\t\t\tfont: inherit; font-weight: 600; font-size: 14px;\n\t\t\tcursor: pointer;\n\t\t\ttransition: background 0.15s ease, border-color 0.15s ease;\n\t\t}\n\t\t.thanks .end-actions button:hover { background: #f3f4f6; }\n\t\t.thanks .end-actions button.primary {\n\t\t\tbackground: #111; color: #fff; border-color: #111;\n\t\t}\n\t\t.thanks .end-actions button.primary:hover { background: #1f2937; border-color: #1f2937; }\n\t\t.thanks .end-actions button:focus-visible { outline: 2px solid #111; outline-offset: 2px; }\n\t\t.thanks .end-hint {\n\t\t\tmargin: 10px 0 0; font-size: 11.5px; color: #9ca3af; text-align: center;\n\t\t}\n\t\t.thanks .end-sent {\n\t\t\tmargin-top: 14px; text-align: center; color: #4b5563; font-size: 13px;\n\t\t}\n\n\t\t@keyframes pulse {\n\t\t\t0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.55); }\n\t\t\t70% { box-shadow: 0 0 0 10px rgba(239,68,68,0); }\n\t\t\t100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); }\n\t\t}\n\t\t@media (prefers-reduced-motion: reduce) {\n\t\t\t.dot { animation: none; }\n\t\t\t.toast, .note-popover { animation: none; }\n\t\t}\n\t`\n\tconst anchor = document.createElement('div')\n\tanchor.className = 'anchor'\n\n\tconst panel = document.createElement('div')\n\tpanel.className = 'panel'\n\tpanel.hidden = true\n\n\t// Toast slot: helper messages render here above the bar.\n\tconst toastSlot = document.createElement('div')\n\ttoastSlot.className = 'toast-slot'\n\n\t// Notes popover slot: rendered above the bar when open.\n\tconst notePopover = document.createElement('div')\n\tnotePopover.className = 'note-popover'\n\tnotePopover.hidden = true\n\n\tconst bar = document.createElement('div')\n\tbar.className = 'bar'\n\tbar.setAttribute('role', 'status')\n\tbar.setAttribute('aria-live', 'polite')\n\n\t// Mic chip = real button. Three states driven by data-mic-state.\n\tconst micBtn = document.createElement('button')\n\tmicBtn.type = 'button'\n\tmicBtn.className = 'mic'\n\tmicBtn.setAttribute('data-mic-state', 'recording')\n\tmicBtn.setAttribute('aria-pressed', 'false')\n\tmicBtn.setAttribute('aria-label', 'Mute microphone')\n\n\tconst dot = document.createElement('span')\n\tdot.className = 'dot'\n\tdot.setAttribute('data-state', store.indicatorState)\n\n\tconst micIcon = document.createElement('span')\n\tmicIcon.className = 'mic-icon'\n\tmicIcon.innerHTML = MIC_ICON_SVG\n\tmicIcon.setAttribute('aria-hidden', 'true')\n\n\tconst micLabel = document.createElement('span')\n\tmicLabel.className = 'mic-label'\n\tmicLabel.textContent = 'Recording'\n\n\tmicBtn.appendChild(dot)\n\tmicBtn.appendChild(micIcon)\n\tmicBtn.appendChild(micLabel)\n\tmicBtn.addEventListener('click', callbacks.onToggleMute)\n\tbar.appendChild(micBtn)\n\n\t// Notes button: icon-only by default, grows to show count once notes exist.\n\tconst noteBtn = document.createElement('button')\n\tnoteBtn.type = 'button'\n\tnoteBtn.className = 'note-btn'\n\tnoteBtn.setAttribute('aria-label', 'Add a timestamped note')\n\tnoteBtn.setAttribute('aria-expanded', 'false')\n\tnoteBtn.setAttribute('data-has-notes', 'false')\n\tnoteBtn.innerHTML = `<span class=\"note-icon\" aria-hidden=\"true\">${NOTE_ICON_SVG}</span><span class=\"note-count\" hidden></span>`\n\tnoteBtn.addEventListener('click', callbacks.onOpenNote)\n\tbar.appendChild(noteBtn)\n\n\tconst spacer = document.createElement('span')\n\tspacer.className = 'spacer'\n\tbar.appendChild(spacer)\n\n\tconst btn = document.createElement('button')\n\tbtn.type = 'button'\n\tbtn.className = 'btn finish-btn'\n\tbtn.textContent = 'Finish'\n\tbtn.addEventListener('click', callbacks.onFinish)\n\tbar.appendChild(btn)\n\n\tif (store.tasks.length > 0) installTasksToggle(bar, btn, store, callbacks.onToggleTasks)\n\n\tanchor.appendChild(panel)\n\tanchor.appendChild(toastSlot)\n\tanchor.appendChild(notePopover)\n\tanchor.appendChild(bar)\n\n\troot.appendChild(style)\n\troot.appendChild(anchor)\n\treturn root\n}\n\n// Inline SVGs kept tiny. currentColor so they inherit the chip text color.\nconst MIC_ICON_SVG = `<svg viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\"><path d=\"M8 1.5a2 2 0 0 0-2 2v4a2 2 0 1 0 4 0v-4a2 2 0 0 0-2-2Z\" fill=\"currentColor\"/><path d=\"M4 7.5a4 4 0 0 0 8 0M8 11.5v3M5.5 14.5h5\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\"/></svg>`\nconst MIC_MUTED_ICON_SVG = `<svg viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\"><path d=\"M8 1.5a2 2 0 0 0-2 2v3.2L10 11V3.5a2 2 0 0 0-2-2Z\" fill=\"currentColor\"/><path d=\"M4 7.5a4 4 0 0 0 6.5 3.12M12 7.5a4 4 0 0 1-.3 1.5M8 11.5v3M5.5 14.5h5M2 2l12 12\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\"/></svg>`\nconst NOTE_ICON_SVG = `<svg viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\"><path d=\"M3 3.5A1.5 1.5 0 0 1 4.5 2h7A1.5 1.5 0 0 1 13 3.5V10a1.5 1.5 0 0 1-1.5 1.5H7L4 14v-2.5h-.5A1.5 1.5 0 0 1 2 10V3.5A1.5 1.5 0 0 1 3.5 3\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`\n\nfunction installTasksToggle(bar: HTMLElement, finishBtn: HTMLElement, store: RecorderStore, onToggleTasks: () => void): void {\n\tconst tasksBtn = document.createElement('button')\n\ttasksBtn.type = 'button'\n\ttasksBtn.className = 'btn tasks-btn'\n\ttasksBtn.textContent = `Tasks (${store.tasks.length})`\n\ttasksBtn.setAttribute('aria-expanded', store.tasksPanelOpen ? 'true' : 'false')\n\ttasksBtn.addEventListener('click', onToggleTasks)\n\tbar.insertBefore(tasksBtn, finishBtn)\n}\n\nfunction renderTasksPanel(store: RecorderStore): void {\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst panel = root.querySelector('.panel')\n\tif (!(panel instanceof HTMLElement)) return\n\t// Build content once.\n\tif (!panel.firstChild && store.tasks.length > 0) {\n\t\tconst ol = document.createElement('ol')\n\t\tfor (const task of store.tasks) {\n\t\t\tconst li = document.createElement('li')\n\t\t\tli.textContent = task.prompt\n\t\t\tol.appendChild(li)\n\t\t}\n\t\tpanel.appendChild(ol)\n\t}\n\tpanel.hidden = !store.tasksPanelOpen\n\tconst tasksBtn = root.querySelector('.tasks-btn')\n\tif (tasksBtn instanceof HTMLElement) {\n\t\ttasksBtn.setAttribute('aria-expanded', store.tasksPanelOpen ? 'true' : 'false')\n\t}\n}\n\nfunction readTasksPanelOpen(): boolean {\n\ttry { return window.sessionStorage?.getItem(TASKS_PANEL_OPEN_STORAGE_KEY) === '1' } catch { return false }\n}\nfunction writeTasksPanelOpen(open: boolean): void {\n\ttry { window.sessionStorage?.setItem(TASKS_PANEL_OPEN_STORAGE_KEY, open ? '1' : '0') } catch { /* ignore */ }\n}\n\nfunction micChipState(store: RecorderStore): 'recording' | 'muted' | 'none' | 'inactive' {\n\tif (store.indicatorState === 'finishing' || store.indicatorState === 'done' || store.indicatorState === 'error') {\n\t\treturn 'inactive'\n\t}\n\tif (!store.hasMicPermission) return 'none'\n\treturn store.muted ? 'muted' : 'recording'\n}\n\nfunction renderIndicatorState(store: RecorderStore): void {\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst dot = root.querySelector('.dot')\n\tconst mic = root.querySelector<HTMLButtonElement>('.mic')\n\tconst micIcon = root.querySelector('.mic-icon')\n\tconst micLabel = root.querySelector('.mic-label')\n\tconst btn = root.querySelector<HTMLButtonElement>('.finish-btn')\n\tif (!(dot instanceof HTMLElement) || !mic || !(micIcon instanceof HTMLElement) || !(micLabel instanceof HTMLElement) || !btn) return\n\n\tdot.setAttribute('data-state', store.indicatorState)\n\tconst chipState = micChipState(store)\n\tmic.setAttribute('data-mic-state', chipState === 'inactive' ? 'none' : chipState)\n\n\t// Finish-button copy is driven by the indicatorState (network / lifecycle).\n\tswitch (store.indicatorState) {\n\t\tcase 'recording':\n\t\tcase 'no-audio':\n\t\t\tbtn.textContent = 'Finish'\n\t\t\tbtn.disabled = false\n\t\t\tbreak\n\t\tcase 'finishing':\n\t\t\tbtn.textContent = 'Saving'\n\t\t\tbtn.disabled = true\n\t\t\tbreak\n\t\tcase 'done':\n\t\t\tbtn.textContent = 'Done'\n\t\t\tbtn.disabled = true\n\t\t\tbreak\n\t\tcase 'error':\n\t\t\tbtn.textContent = 'Retry'\n\t\t\tbtn.disabled = false\n\t\t\tbreak\n\t}\n\n\t// Mic chip copy + icon. Replay continues in all states; the chip only\n\t// describes the audio track.\n\tswitch (chipState) {\n\t\tcase 'recording':\n\t\t\tmicIcon.innerHTML = MIC_ICON_SVG\n\t\t\tmicLabel.textContent = 'Recording'\n\t\t\tmic.setAttribute('aria-label', 'Mute microphone')\n\t\t\tmic.setAttribute('aria-pressed', 'false')\n\t\t\tmic.removeAttribute('tabindex')\n\t\t\tbreak\n\t\tcase 'muted':\n\t\t\tmicIcon.innerHTML = MIC_MUTED_ICON_SVG\n\t\t\tmicLabel.textContent = 'Muted'\n\t\t\tmic.setAttribute('aria-label', 'Unmute microphone')\n\t\t\tmic.setAttribute('aria-pressed', 'true')\n\t\t\tmic.removeAttribute('tabindex')\n\t\t\tbreak\n\t\tcase 'none':\n\t\t\tmicIcon.innerHTML = MIC_MUTED_ICON_SVG\n\t\t\tmicLabel.textContent = 'No mic, replay only'\n\t\t\tmic.setAttribute('aria-label', 'Microphone not granted, replay only')\n\t\t\tmic.setAttribute('aria-pressed', 'false')\n\t\t\tmic.setAttribute('tabindex', '-1')\n\t\t\tbreak\n\t\tcase 'inactive':\n\t\t\tmicIcon.innerHTML = MIC_ICON_SVG\n\t\t\tmicLabel.textContent =\n\t\t\t\tstore.indicatorState === 'finishing' ? 'Saving' :\n\t\t\t\tstore.indicatorState === 'done' ? 'Saved' :\n\t\t\t\t'Save failed'\n\t\t\tmic.setAttribute('aria-label', 'Recording stopped')\n\t\t\tmic.setAttribute('aria-pressed', 'false')\n\t\t\tmic.setAttribute('tabindex', '-1')\n\t\t\tbreak\n\t}\n}\n\nfunction renderNotesCount(store: RecorderStore): void {\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst noteBtn = root.querySelector('.note-btn')\n\tconst count = root.querySelector('.note-count')\n\tif (!(noteBtn instanceof HTMLElement) || !(count instanceof HTMLElement)) return\n\tconst n = store.notes.length\n\tnoteBtn.setAttribute('data-has-notes', n > 0 ? 'true' : 'false')\n\tif (n > 0) {\n\t\tcount.textContent = String(n)\n\t\tcount.hidden = false\n\t\tnoteBtn.setAttribute('aria-label', `Add a timestamped note (${n} so far)`)\n\t} else {\n\t\tcount.textContent = ''\n\t\tcount.hidden = true\n\t\tnoteBtn.setAttribute('aria-label', 'Add a timestamped note')\n\t}\n}\n\nfunction showMuteToast(store: RecorderStore): void {\n\tif (store.muteToastShown) return\n\tstore.muteToastShown = true\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst slot = root.querySelector('.toast-slot')\n\tif (!(slot instanceof HTMLElement)) return\n\tslot.innerHTML = ''\n\tconst toast = document.createElement('div')\n\ttoast.className = 'toast'\n\ttoast.setAttribute('role', 'status')\n\ttoast.innerHTML = `<strong>Mic off.</strong> Screen is still recording. Tap to unmute.`\n\tslot.appendChild(toast)\n\twindow.setTimeout(() => {\n\t\ttoast.setAttribute('data-leaving', 'true')\n\t\twindow.setTimeout(() => { toast.remove() }, 260)\n\t}, 3000)\n}\n\nfunction openNotePopover(store: RecorderStore, onSave: (text: string) => void, onCancel: () => void): void {\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst pop = root.querySelector('.note-popover')\n\tconst noteBtn = root.querySelector('.note-btn')\n\tif (!(pop instanceof HTMLElement) || !(noteBtn instanceof HTMLElement)) return\n\n\tstore.notesPopoverOpen = true\n\tstore.notePopoverAtMs = Date.now() - store.startedAt\n\tnoteBtn.setAttribute('aria-expanded', 'true')\n\n\tpop.innerHTML = ''\n\tconst head = document.createElement('div')\n\thead.className = 'note-head'\n\thead.innerHTML = `<span>Add a note</span>`\n\n\tconst form = document.createElement('form')\n\tform.style.cssText = 'display:flex;flex-direction:column;gap:10px;margin:0;'\n\tform.noValidate = true\n\n\tconst ta = document.createElement('textarea')\n\tta.className = 'note-textarea'\n\tta.placeholder = 'What just happened? Confusing? Surprising? Broken?'\n\tta.rows = 3\n\tta.setAttribute('aria-label', 'Note text')\n\n\tconst actions = document.createElement('div')\n\tactions.className = 'note-actions'\n\tconst hint = document.createElement('span')\n\thint.className = 'hint'\n\thint.innerHTML = '<kbd style=\"font-family:inherit\">Cmd</kbd>+Enter to save'\n\tconst group = document.createElement('div')\n\tgroup.className = 'group'\n\tconst cancelBtn = document.createElement('button')\n\tcancelBtn.type = 'button'\n\tcancelBtn.className = 'btn btn-ghost'\n\tcancelBtn.textContent = 'Cancel'\n\tconst saveBtn = document.createElement('button')\n\tsaveBtn.type = 'submit'\n\tsaveBtn.className = 'btn btn-primary'\n\tsaveBtn.textContent = 'Save'\n\tgroup.appendChild(cancelBtn)\n\tgroup.appendChild(saveBtn)\n\tactions.appendChild(hint)\n\tactions.appendChild(group)\n\n\tform.appendChild(ta)\n\tform.appendChild(actions)\n\n\tpop.appendChild(head)\n\tpop.appendChild(form)\n\tpop.hidden = false\n\n\tconst submit = (): void => {\n\t\tconst text = ta.value.trim()\n\t\tif (!text) { onCancel(); return }\n\t\tonSave(text)\n\t}\n\tform.addEventListener('submit', e => { e.preventDefault(); submit() })\n\tcancelBtn.addEventListener('click', () => onCancel())\n\tta.addEventListener('keydown', e => {\n\t\tif ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n\t\t\te.preventDefault()\n\t\t\tsubmit()\n\t\t} else if (e.key === 'Escape') {\n\t\t\te.preventDefault()\n\t\t\tonCancel()\n\t\t}\n\t})\n\n\t// Autofocus on next frame so animation can finish without scroll jank.\n\twindow.requestAnimationFrame(() => { ta.focus({ preventScroll: true }) })\n}\n\nfunction closeNotePopover(store: RecorderStore): void {\n\tconst root = store.indicatorRoot\n\tif (!root) return\n\tconst pop = root.querySelector('.note-popover')\n\tconst noteBtn = root.querySelector('.note-btn')\n\tif (pop instanceof HTMLElement) {\n\t\tpop.hidden = true\n\t\tpop.innerHTML = ''\n\t}\n\tif (noteBtn instanceof HTMLElement) noteBtn.setAttribute('aria-expanded', 'false')\n\tstore.notesPopoverOpen = false\n\tstore.notePopoverAtMs = null\n}\n\nfunction showThanksScreen(\n\troot: ShadowRoot,\n\topts: { onSubmitNote: (text: string) => Promise<void> | void; onSkip: () => void },\n): void {\n\tconst overlay = document.createElement('div')\n\toverlay.className = 'thanks'\n\n\tconst card = document.createElement('div')\n\tcard.className = 'thanks-card'\n\n\tconst head = document.createElement('div')\n\thead.className = 'head'\n\thead.innerHTML = `\n\t\t<div class=\"check\" aria-hidden=\"true\">&#10003;</div>\n\t\t<h2>Thanks for testing</h2>\n\t\t<p class=\"lede\">Your session was saved. One last thing if you have a moment.</p>\n\t`\n\n\tconst form = document.createElement('form')\n\tform.noValidate = true\n\tform.innerHTML = `\n\t\t<label class=\"end-label\" for=\"usero-end-note\">Anything you would add?</label>\n\t\t<textarea\n\t\t\tid=\"usero-end-note\"\n\t\t\tclass=\"end-textarea\"\n\t\t\trows=\"4\"\n\t\t\tplaceholder=\"Confusing bits, things you liked, what you'd change...\"\n\t\t></textarea>\n\t\t<div class=\"end-actions\">\n\t\t\t<button type=\"button\" class=\"skip\">Skip</button>\n\t\t\t<button type=\"submit\" class=\"primary\">Send</button>\n\t\t</div>\n\t\t<p class=\"end-hint\">Cmd or Ctrl plus Enter to send. Either button is fine.</p>\n\t`\n\n\tcard.appendChild(head)\n\tcard.appendChild(form)\n\toverlay.appendChild(card)\n\troot.appendChild(overlay)\n\n\tconst ta = form.querySelector<HTMLTextAreaElement>('#usero-end-note')\n\tconst skipBtn = form.querySelector<HTMLButtonElement>('button.skip')\n\tif (!ta || !skipBtn) return\n\n\tconst swapToSent = (message: string): void => {\n\t\tform.remove()\n\t\tconst sent = document.createElement('p')\n\t\tsent.className = 'end-sent'\n\t\tsent.textContent = message\n\t\tcard.appendChild(sent)\n\t}\n\n\tconst submit = async (): Promise<void> => {\n\t\tconst text = ta.value.trim()\n\t\tta.disabled = true\n\t\tskipBtn.disabled = true\n\t\tconst submitBtn = form.querySelector<HTMLButtonElement>('button.primary')\n\t\tif (submitBtn) submitBtn.disabled = true\n\t\tif (text) {\n\t\t\tawait opts.onSubmitNote(text)\n\t\t\tswapToSent('Thanks. You can close this tab.')\n\t\t} else {\n\t\t\topts.onSkip()\n\t\t\tswapToSent('All good. You can close this tab.')\n\t\t}\n\t}\n\n\tform.addEventListener('submit', e => { e.preventDefault(); void submit() })\n\tskipBtn.addEventListener('click', () => { ta.value = ''; void submit() })\n\tta.addEventListener('keydown', e => {\n\t\tif ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n\t\t\te.preventDefault()\n\t\t\tvoid submit()\n\t\t}\n\t})\n\n\twindow.requestAnimationFrame(() => { ta.focus({ preventScroll: true }) })\n}\n\nfunction parseTasks(raw: unknown): UserTestTask[] {\n\tif (!Array.isArray(raw)) return []\n\tconst out = raw.flatMap((item: unknown): UserTestTask[] => {\n\t\tconst t = item as { id?: unknown; prompt?: unknown; sortOrder?: unknown }\n\t\tif (!t || typeof t.id !== 'string' || typeof t.prompt !== 'string' || typeof t.sortOrder !== 'number') return []\n\t\treturn [{ id: t.id, prompt: t.prompt, sortOrder: t.sortOrder }]\n\t})\n\tout.sort((a, b) => a.sortOrder - b.sortOrder)\n\treturn out\n}\n\nasync function createSession(\n\tapiUrl: string,\n\tslug: string,\n\ttesterName: string | undefined,\n): Promise<{ sessionId: string; clientId: string; tasks: UserTestTask[] } | null> {\n\ttry {\n\t\tconst res = await fetch(`${apiUrl.replace(/\\/$/, '')}/api/user-test-sessions`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ slug, ...(testerName ? { testerName } : {}) }),\n\t\t})\n\t\tif (!res.ok) return null\n\t\tconst json = (await res.json()) as { sessionId?: unknown; clientId?: unknown; tasks?: unknown }\n\t\tif (typeof json.sessionId !== 'string' || typeof json.clientId !== 'string') return null\n\t\treturn { sessionId: json.sessionId, clientId: json.clientId, tasks: parseTasks(json.tasks) }\n\t} catch {\n\t\treturn null\n\t}\n}\n\nasync function finaliseSession(\n\tapiUrl: string,\n\tsessionId: string,\n\tdurationSeconds: number,\n\textras: { mutedSegments?: MutedSegment[]; endNote?: string | null } = {},\n): Promise<boolean> {\n\ttry {\n\t\tconst body: Record<string, unknown> = {\n\t\t\tdurationSeconds: Math.max(0, Math.round(durationSeconds)),\n\t\t}\n\t\tif (extras.mutedSegments && extras.mutedSegments.length > 0) {\n\t\t\tbody.mutedSegments = extras.mutedSegments\n\t\t}\n\t\tconst trimmedEndNote = extras.endNote?.trim()\n\t\tif (trimmedEndNote) body.endNote = trimmedEndNote\n\t\tconst res = await fetch(`${apiUrl.replace(/\\/$/, '')}/api/user-test-sessions/${encodeURIComponent(sessionId)}/finalise`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify(body),\n\t\t\tkeepalive: true,\n\t\t})\n\t\treturn res.ok\n\t} catch {\n\t\treturn false\n\t}\n}\n\nasync function postNote(\n\tapiUrl: string,\n\tsessionId: string,\n\tatMs: number,\n\ttext: string,\n\tlogger: PluginContext['logger'],\n): Promise<boolean> {\n\ttry {\n\t\tconst res = await fetch(`${apiUrl.replace(/\\/$/, '')}/api/user-test-sessions/${encodeURIComponent(sessionId)}/notes`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ atMs: Math.max(0, Math.round(atMs)), text }),\n\t\t\tkeepalive: true,\n\t\t})\n\t\tif (!res.ok) {\n\t\t\tlogger.warn(`note POST rejected with ${res.status}`)\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t} catch (err) {\n\t\tlogger.warn('note POST failed', err)\n\t\treturn false\n\t}\n}\n\n\nasync function flushPendingFromIdb(store: RecorderStore, ctx: PluginContext): Promise<void> {\n\tif (!store.sessionId) return\n\tconst pending = await idbListChunks(store.sessionId)\n\tfor (const chunk of pending) {\n\t\tconst ok = await uploadChunkWithRetry(chunk.apiUrl, chunk.sessionId, chunk.chunkIndex, chunk.blob, ctx.logger, 3)\n\t\tif (ok) await idbDeleteChunk(chunk.id)\n\t}\n}\n\nfunction enqueueChunk(store: RecorderStore, ctx: PluginContext, blob: Blob): void {\n\tif (store.cancelled || !store.sessionId || blob.size === 0) return\n\tconst index = store.chunkIndex\n\tstore.chunkIndex += 1\n\tstore.pendingUploads += 1\n\tconst sessionId = store.sessionId\n\tconst apiUrl = store.options.apiUrl\n\n\tstore.uploadQueue = store.uploadQueue.then(async () => {\n\t\tconst ok = await uploadChunkWithRetry(apiUrl, sessionId, index, blob, ctx.logger)\n\t\tif (!ok) {\n\t\t\tctx.logger.warn(`chunk ${index} stashed for offline retry`)\n\t\t\tawait idbStashChunk({\n\t\t\t\tid: `${sessionId}:${index}:${Date.now()}`,\n\t\t\t\tsessionId,\n\t\t\t\tapiUrl,\n\t\t\t\tchunkIndex: index,\n\t\t\t\tblob,\n\t\t\t\tcreatedAt: Date.now(),\n\t\t\t})\n\t\t}\n\t\tstore.pendingUploads -= 1\n\t})\n}\n\nasync function startRecording(store: RecorderStore, ctx: PluginContext): Promise<void> {\n\tif (!isMediaRecorderSupported()) {\n\t\tctx.logger.warn('MediaRecorder not supported, continuing without audio')\n\t\tstore.indicatorState = 'no-audio'\n\t\trenderIndicatorState(store)\n\t\treturn\n\t}\n\tlet stream: MediaStream\n\ttry {\n\t\tstream = await navigator.mediaDevices.getUserMedia({ audio: true })\n\t} catch (err) {\n\t\tctx.logger.warn('mic permission denied or unavailable', err)\n\t\tstore.indicatorState = 'no-audio'\n\t\trenderIndicatorState(store)\n\t\treturn\n\t}\n\tstore.stream = stream\n\tstore.hasMicPermission = true\n\tconst mimeType = pickMimeType()\n\tlet recorder: MediaRecorder\n\ttry {\n\t\trecorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream)\n\t} catch (err) {\n\t\tctx.logger.error('MediaRecorder construction failed', err)\n\t\tstream.getTracks().forEach(t => t.stop())\n\t\tstore.stream = null\n\t\tstore.indicatorState = 'no-audio'\n\t\trenderIndicatorState(store)\n\t\treturn\n\t}\n\tstore.recorder = recorder\n\trecorder.addEventListener('dataavailable', event => {\n\t\tif (event.data && event.data.size > 0) {\n\t\t\tenqueueChunk(store, ctx, event.data)\n\t\t}\n\t})\n\trecorder.addEventListener('error', event => {\n\t\tctx.logger.error('MediaRecorder error', event)\n\t})\n\t// `timeslice` makes the recorder emit a self-contained chunk every N ms.\n\trecorder.start(store.options.chunkSeconds * 1000)\n}\n\nfunction toggleMute(store: RecorderStore): boolean {\n\tif (!store.stream || !store.hasMicPermission) return false\n\tconst tracks = store.stream.getAudioTracks()\n\tif (tracks.length === 0) return false\n\tconst nowMs = Date.now() - store.startedAt\n\tif (!store.muted) {\n\t\t// Going muted: disable each audio track. MediaRecorder keeps running;\n\t\t// the disabled track produces silence in the resulting WebM. We do NOT\n\t\t// pause the recorder so the single-stream lifecycle stays simple.\n\t\tfor (const t of tracks) t.enabled = false\n\t\tstore.muted = true\n\t\tstore.mutedSinceMs = nowMs\n\t} else {\n\t\t// Coming back: close the muted segment, re-enable.\n\t\tconst startMs = store.mutedSinceMs ?? nowMs\n\t\tif (nowMs > startMs) {\n\t\t\tstore.mutedSegments.push({ startMs, endMs: nowMs })\n\t\t}\n\t\tstore.mutedSinceMs = null\n\t\tstore.muted = false\n\t\tfor (const t of tracks) t.enabled = true\n\t}\n\treturn true\n}\n\nfunction flushMuteIfActive(store: RecorderStore): void {\n\tif (!store.muted || store.mutedSinceMs === null) return\n\tconst nowMs = Date.now() - store.startedAt\n\tif (nowMs > store.mutedSinceMs) {\n\t\tstore.mutedSegments.push({ startMs: store.mutedSinceMs, endMs: nowMs })\n\t}\n\tstore.mutedSinceMs = null\n}\n\nfunction stopRecording(store: RecorderStore): void {\n\tconst recorder = store.recorder\n\tif (recorder && recorder.state !== 'inactive') {\n\t\ttry {\n\t\t\trecorder.requestData()\n\t\t} catch {\n\t\t\t// requestData throws if state is invalid; ignore.\n\t\t}\n\t\ttry {\n\t\t\trecorder.stop()\n\t\t} catch {\n\t\t\t// already stopped\n\t\t}\n\t}\n\tstore.recorder = null\n\tif (store.stream) {\n\t\tstore.stream.getTracks().forEach(t => t.stop())\n\t\tstore.stream = null\n\t}\n}\n\nasync function finishFlow(store: RecorderStore, ctx: PluginContext, opts: { showThanks: boolean }): Promise<void> {\n\tif (store.cancelled) return\n\tif (store.indicatorState === 'finishing' || store.indicatorState === 'done') return\n\tstore.indicatorState = 'finishing'\n\tflushMuteIfActive(store)\n\trenderIndicatorState(store)\n\n\tstopRecording(store)\n\t// Wait for the queued uploads to drain. Each upload already has its own\n\t// retry/backoff; this just lets them finish before finalise fires.\n\tawait store.uploadQueue\n\tawait flushPendingFromIdb(store, ctx)\n\n\tconst durationSeconds = (Date.now() - store.startedAt) / 1000\n\tif (store.sessionId) {\n\t\t// First finalise carries durationSeconds + mutedSegments. End-of-test\n\t\t// note (if any) is sent via a second finalise call from the thanks\n\t\t// screen so the participant can compose it after the network round-trip.\n\t\tconst ok = await finaliseSession(store.options.apiUrl, store.sessionId, durationSeconds, {\n\t\t\tmutedSegments: store.mutedSegments,\n\t\t})\n\t\tstore.indicatorState = ok ? 'done' : 'error'\n\t} else {\n\t\tstore.indicatorState = 'error'\n\t}\n\trenderIndicatorState(store)\n\n\tif (opts.showThanks && store.indicatorRoot && store.indicatorState === 'done') {\n\t\tshowThanksScreen(store.indicatorRoot, {\n\t\t\tonSubmitNote: async text => {\n\t\t\t\tif (!store.sessionId) return\n\t\t\t\tstore.endNote = text\n\t\t\t\tawait finaliseSession(store.options.apiUrl, store.sessionId, durationSeconds, {\n\t\t\t\t\tmutedSegments: store.mutedSegments,\n\t\t\t\t\tendNote: text,\n\t\t\t\t})\n\t\t\t},\n\t\t\tonSkip: () => { /* nothing to send */ },\n\t\t})\n\t}\n}\n\nexport function userTest(options: UserTestOptions = {}): UseroPlugin {\n\tconst merged: Required<UserTestOptions> = {\n\t\tqueryParam: options.queryParam ?? DEFAULT_OPTIONS.queryParam,\n\t\tchunkSeconds: options.chunkSeconds ?? DEFAULT_OPTIONS.chunkSeconds,\n\t\tapiUrl: options.apiUrl ?? DEFAULT_OPTIONS.apiUrl,\n\t\ttesterName: options.testerName ?? DEFAULT_OPTIONS.testerName,\n\t\thideIndicator: options.hideIndicator ?? DEFAULT_OPTIONS.hideIndicator,\n\t}\n\n\treturn {\n\t\tname: 'user-test',\n\t\tonInit(ctx) {\n\t\t\tif (typeof window === 'undefined' || typeof document === 'undefined') return\n\t\t\tconst slug = getTestSlug(merged.queryParam)\n\t\t\tif (!slug) return\n\n\t\t\tconst apiUrl = merged.apiUrl || ctx.baseUrl || DEFAULT_API_URL\n\t\t\tconst store: RecorderStore = {\n\t\t\t\tcancelled: false,\n\t\t\t\tslug,\n\t\t\t\tsessionId: null,\n\t\t\t\tclientId: null,\n\t\t\t\trecorder: null,\n\t\t\t\tstream: null,\n\t\t\t\tchunkIndex: 0,\n\t\t\t\tuploadQueue: Promise.resolve(),\n\t\t\t\tpendingUploads: 0,\n\t\t\t\tstartedAt: Date.now(),\n\t\t\t\tindicator: null,\n\t\t\t\tindicatorRoot: null,\n\t\t\t\tindicatorState: 'recording',\n\t\t\t\tpageHideHandler: null,\n\t\t\t\toptions: { ...merged, apiUrl },\n\t\t\t\ttasks: [],\n\t\t\t\ttasksPanelOpen: readTasksPanelOpen(),\n\t\t\t\toutsidePointerHandler: null,\n\t\t\t\tkeydownHandler: null,\n\t\t\t\thasMicPermission: false,\n\t\t\t\tmuted: false,\n\t\t\t\tmutedSinceMs: null,\n\t\t\t\tmutedSegments: [],\n\t\t\t\tmuteToastShown: false,\n\t\t\t\tnotes: [],\n\t\t\t\tnotesPopoverOpen: false,\n\t\t\t\tnotePopoverAtMs: null,\n\t\t\t\tendNote: '',\n\t\t\t}\n\t\t\tctx.setStore(store)\n\n\t\t\tconst onFinish = (): void => {\n\t\t\t\tvoid finishFlow(store, ctx, { showThanks: true })\n\t\t\t}\n\n\t\t\tconst setPanelOpen = (open: boolean): void => {\n\t\t\t\tif (store.tasksPanelOpen === open) return\n\t\t\t\tstore.tasksPanelOpen = open\n\t\t\t\twriteTasksPanelOpen(open)\n\t\t\t\trenderTasksPanel(store)\n\t\t\t}\n\n\t\t\tconst onToggleTasks = (): void => setPanelOpen(!store.tasksPanelOpen)\n\n\t\t\tconst onToggleMute = (): void => {\n\t\t\t\tif (!store.hasMicPermission) return\n\t\t\t\tconst ok = toggleMute(store)\n\t\t\t\tif (!ok) return\n\t\t\t\tif (store.muted) showMuteToast(store)\n\t\t\t\trenderIndicatorState(store)\n\t\t\t}\n\n\t\t\tconst closeNote = (): void => closeNotePopover(store)\n\t\t\tconst onOpenNote = (): void => {\n\t\t\t\tif (store.notesPopoverOpen) { closeNote(); return }\n\t\t\t\topenNotePopover(\n\t\t\t\t\tstore,\n\t\t\t\t\ttext => {\n\t\t\t\t\t\tconst atMs = store.notePopoverAtMs ?? Math.max(0, Date.now() - store.startedAt)\n\t\t\t\t\t\tstore.notes.push({ atMs, text })\n\t\t\t\t\t\tcloseNote()\n\t\t\t\t\t\trenderNotesCount(store)\n\t\t\t\t\t\t// Fire-and-forget; UI never blocks on the POST. Failures\n\t\t\t\t\t\t// surface as a warning in logs, the note is also captured\n\t\t\t\t\t\t// in-memory and will go out in finalise via mutedSegments-\n\t\t\t\t\t\t// style pickup once the server supports batched recovery.\n\t\t\t\t\t\tif (store.sessionId) {\n\t\t\t\t\t\t\tvoid postNote(store.options.apiUrl, store.sessionId, atMs, text, ctx.logger)\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t() => closeNote(),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif (!merged.hideIndicator) {\n\t\t\t\tconst host = document.createElement('div')\n\t\t\t\thost.setAttribute('data-usero-user-test', 'true')\n\t\t\t\tdocument.body.appendChild(host)\n\t\t\t\tstore.indicator = host\n\t\t\t\tstore.indicatorRoot = buildIndicator(host, store, {\n\t\t\t\t\tonFinish,\n\t\t\t\t\tonToggleTasks,\n\t\t\t\t\tonToggleMute,\n\t\t\t\t\tonOpenNote,\n\t\t\t\t})\n\t\t\t\trenderIndicatorState(store)\n\t\t\t\trenderNotesCount(store)\n\t\t\t}\n\n\t\t\t// Outside-click + Escape close the tasks panel. Listen on document\n\t\t\t// (composedPath checks shadow ancestry so taps on the panel/pill\n\t\t\t// itself don't dismiss).\n\t\t\tconst outsidePointer = (event: PointerEvent): void => {\n\t\t\t\tconst host = store.indicator\n\t\t\t\tif (!host) return\n\t\t\t\tconst path = event.composedPath()\n\t\t\t\tif (path.includes(host)) return\n\t\t\t\tif (store.tasksPanelOpen) setPanelOpen(false)\n\t\t\t\tif (store.notesPopoverOpen) closeNote()\n\t\t\t}\n\t\t\tconst onKeydown = (event: KeyboardEvent): void => {\n\t\t\t\tif (event.key !== 'Escape') return\n\t\t\t\tif (store.tasksPanelOpen) setPanelOpen(false)\n\t\t\t\tif (store.notesPopoverOpen) closeNote()\n\t\t\t}\n\t\t\tstore.outsidePointerHandler = outsidePointer\n\t\t\tstore.keydownHandler = onKeydown\n\t\t\tdocument.addEventListener('pointerdown', outsidePointer, true)\n\t\t\tdocument.addEventListener('keydown', onKeydown)\n\n\t\t\tconst pageHide = (): void => {\n\t\t\t\t// Best-effort flush + finalise. We don't await here; the browser\n\t\t\t\t// is shutting the page down. `keepalive: true` on finalise lets\n\t\t\t\t// the request race the unload.\n\t\t\t\tvoid finishFlow(store, ctx, { showThanks: false })\n\t\t\t}\n\t\t\tstore.pageHideHandler = pageHide\n\t\t\twindow.addEventListener('pagehide', pageHide)\n\n\t\t\tvoid (async (): Promise<void> => {\n\t\t\t\tconst created = await createSession(apiUrl, slug, readTesterName(merged.testerName))\n\t\t\t\tif (store.cancelled) return\n\t\t\t\tif (!created) {\n\t\t\t\t\tctx.logger.error('failed to create user-test session')\n\t\t\t\t\tstore.indicatorState = 'error'\n\t\t\t\t\trenderIndicatorState(store)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tstore.sessionId = created.sessionId\n\t\t\t\tstore.clientId = created.clientId\n\t\t\t\tstore.tasks = created.tasks\n\t\t\t\tif (store.tasks.length > 0 && store.indicatorRoot && !merged.hideIndicator) {\n\t\t\t\t\tconst bar = store.indicatorRoot.querySelector('.bar')\n\t\t\t\t\tconst finishBtn = bar?.querySelector('.finish-btn')\n\t\t\t\t\tif (bar instanceof HTMLElement && finishBtn instanceof HTMLElement && !bar.querySelector('.tasks-btn')) {\n\t\t\t\t\t\tinstallTasksToggle(bar, finishBtn, store, onToggleTasks)\n\t\t\t\t\t}\n\t\t\t\t\trenderTasksPanel(store)\n\t\t\t\t}\n\t\t\t\tawait startRecording(store, ctx)\n\t\t\t\trenderIndicatorState(store)\n\t\t\t})()\n\t\t},\n\t\tonDestroy(ctx) {\n\t\t\tconst store = ctx.getStore<RecorderStore>()\n\t\t\tif (!store) return\n\t\t\tstore.cancelled = true\n\t\t\tif (store.pageHideHandler) {\n\t\t\t\twindow.removeEventListener('pagehide', store.pageHideHandler)\n\t\t\t\tstore.pageHideHandler = null\n\t\t\t}\n\t\t\tstopRecording(store)\n\t\t\tif (store.outsidePointerHandler) {\n\t\t\t\tdocument.removeEventListener('pointerdown', store.outsidePointerHandler, true)\n\t\t\t\tstore.outsidePointerHandler = null\n\t\t\t}\n\t\t\tif (store.keydownHandler) {\n\t\t\t\tdocument.removeEventListener('keydown', store.keydownHandler)\n\t\t\t\tstore.keydownHandler = null\n\t\t\t}\n\t\t\tif (store.indicator && store.indicator.parentNode) {\n\t\t\t\tstore.indicator.parentNode.removeChild(store.indicator)\n\t\t\t}\n\t\t\tstore.indicator = null\n\t\t\tstore.indicatorRoot = null\n\t\t},\n\t}\n}\n\n// Internal helpers exposed for tests only. Not part of the public API.\nexport const __test__ = { getTestSlug, pickMimeType, isMediaRecorderSupported }\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usero/sdk",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Usero SDK. Drop-in feedback widget (vanilla JS, React, or script tag) plus future plugins like session replay. Zero config, framework-free, tiny.",
5
5
  "license": "MIT",
6
6
  "author": "Will Smith <will@willsmithte.com>",