@obsrviq/widgets 0.3.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.
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.js +465 -0
- package/dist/index.js.map +1 -0
- package/dist/obsrviq-replay.global.js +3821 -0
- package/dist/obsrviq-replay.global.js.map +1 -0
- package/package.json +48 -0
- package/src/ObsrviqCopilot.tsx +95 -0
- package/src/ObsrviqInsights.tsx +115 -0
- package/src/ObsrviqRecommendations.tsx +75 -0
- package/src/ObsrviqReplay.tsx +237 -0
- package/src/ObsrviqScore.tsx +78 -0
- package/src/client.ts +64 -0
- package/src/common.tsx +39 -0
- package/src/embed-css.ts +3 -0
- package/src/global.ts +71 -0
- package/src/index.ts +12 -0
- package/styles.css +264 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ObsrviqReplay.tsx","../src/common.tsx","../src/ObsrviqInsights.tsx","../src/client.ts","../src/ObsrviqRecommendations.tsx","../src/ObsrviqScore.tsx","../src/ObsrviqCopilot.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { ReplayPlayer } from '@obsrviq/player';\nimport { ThemeScope, type BaseWidgetProps } from './common.js';\n\ntype ClipBounds = {\n fromEvent?: string;\n toEvent?: string;\n fromMs?: number;\n toMs?: number;\n fromUtc?: number;\n toUtc?: number;\n loop?: boolean;\n};\n\n/** What to render when the recording can't be shown (not found / load error):\n * 'message' (default) shows a small note; 'hide' renders nothing so the embed\n * collapses on the host page (pair with `onError` to hide your own wrapper). */\nexport type UnavailableFallback = 'message' | 'hide';\n\nexport interface ObsrviqReplayProps extends BaseWidgetProps {\n /** The session to play. Optional if `userId` is given — then the session is\n * resolved from the user + clip bounds (UTC window / event names). */\n sessionId?: string;\n /** Resolve the session from this user instead of a session id. */\n userId?: string;\n /** Optional site scope for `userId` resolution; omit to search the whole tenant. */\n siteId?: string;\n startAtMs?: number;\n /** Play only a segment: bound by two custom-event names, our-clock ms, or UTC. */\n clip?: ClipBounds;\n /** Focus mode the player opens in ('stage' = Watch). Overrides the site default. */\n defaultMode?: 'balanced' | 'stage' | 'debug';\n /** Restrict the focus-mode toggle to this allowlist; a single entry hides it. */\n allowedModes?: Array<'balanced' | 'stage' | 'debug'>;\n /** Playback speed the player opens at (clamped to the nearest offered speed). */\n defaultSpeed?: number;\n /** Show the fullscreen control + `F` shortcut. Default true. */\n allowFullscreen?: boolean;\n /** Base for \"Copy link\" deep-links (this embed's URL has no session id). A\n * `:id` template, or a base we append `/sessions/:id` to. Omit → console host. */\n shareUrl?: string;\n onEnded?: () => void;\n /** Called once when the recording can't be shown — `reason` is 'not_found'\n * (no such session / no match for the user) or 'error' (load/network/auth).\n * Use it to hide your own container, log, retry, etc. */\n onError?: (info: { reason: 'not_found' | 'error'; message: string }) => void;\n /** What to render when unavailable. Default 'message'. Use 'hide' to collapse. */\n fallback?: UnavailableFallback;\n height?: number | string;\n}\n\nfunction authHeaders(token?: string, apiKey?: string): Record<string, string> {\n if (token) return { authorization: `Bearer ${token}` };\n if (apiKey) return { authorization: `Bearer ${apiKey}`, 'x-obsrviq-key': apiKey };\n return {};\n}\n\ninterface Resolved {\n sessionId: string | null;\n loading: boolean;\n error: string | null;\n notFound: boolean;\n}\n\n/** Resolve a session id from a user (+ clip bounds) via /v1/sessions/locate. */\nfunction useResolvedSession(\n enabled: boolean,\n opts: {\n apiBaseUrl: string;\n token?: string;\n apiKey?: string;\n userId?: string;\n siteId?: string;\n clip?: ClipBounds;\n },\n): Resolved {\n const { apiBaseUrl, token, apiKey, userId, siteId, clip } = opts;\n const [state, setState] = useState<Resolved>({\n sessionId: null,\n loading: enabled,\n error: null,\n notFound: false,\n });\n // Stable signature of just the locate inputs (so we don't refetch every render).\n const sig = JSON.stringify([userId, siteId, clip?.fromUtc, clip?.toUtc, clip?.fromEvent, clip?.toEvent]);\n\n useEffect(() => {\n if (!enabled || !userId) return;\n const ctrl = new AbortController();\n setState({ sessionId: null, loading: true, error: null, notFound: false });\n const q = new URLSearchParams({ userId });\n if (siteId) q.set('siteId', siteId);\n if (clip?.fromUtc != null && clip?.toUtc != null) {\n q.set('fromUtc', String(clip.fromUtc));\n q.set('toUtc', String(clip.toUtc));\n } else if (clip?.fromEvent) {\n q.set('fromEvent', clip.fromEvent);\n if (clip.toEvent) q.set('toEvent', clip.toEvent);\n }\n const base = apiBaseUrl.replace(/\\/$/, '');\n fetch(`${base}/v1/sessions/locate?${q.toString()}`, {\n headers: authHeaders(token, apiKey),\n signal: ctrl.signal,\n })\n .then(async (r) => {\n if (!r.ok) {\n const notFound = r.status === 404;\n throw Object.assign(\n new Error(notFound ? 'No matching recording for that user.' : `Lookup failed (${r.status}).`),\n { notFound },\n );\n }\n return r.json() as Promise<{ sessionId: string }>;\n })\n .then((j) => {\n if (!ctrl.signal.aborted) setState({ sessionId: j.sessionId, loading: false, error: null, notFound: false });\n })\n .catch((e: unknown) => {\n if (ctrl.signal.aborted) return;\n const notFound = !!(e as { notFound?: boolean })?.notFound;\n setState({\n sessionId: null,\n loading: false,\n error: e instanceof Error ? e.message : 'Lookup failed.',\n notFound,\n });\n });\n return () => ctrl.abort();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, sig, apiBaseUrl]);\n\n return state;\n}\n\nconst msgStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n padding: 16,\n textAlign: 'center',\n color: 'var(--lum-muted)',\n fontSize: 14,\n} as const;\n\n/** The replay player itself, embeddable and white-label (§12). */\nexport function ObsrviqReplay({\n sessionId,\n userId,\n siteId,\n apiBaseUrl,\n apiKey,\n token,\n theme,\n startAtMs,\n clip,\n defaultMode,\n allowedModes,\n defaultSpeed,\n allowFullscreen,\n shareUrl,\n onEnded,\n onError,\n fallback = 'message',\n height = 560,\n}: ObsrviqReplayProps) {\n const needResolve = !sessionId && !!userId;\n const resolved = useResolvedSession(needResolve, { apiBaseUrl, token, apiKey, userId, siteId, clip });\n const [playerError, setPlayerError] = useState<{ reason: 'not_found' | 'error'; message: string } | null>(null);\n const effectiveId = sessionId ?? resolved.sessionId;\n\n // A fresh session id clears any prior player error.\n useEffect(() => setPlayerError(null), [effectiveId]);\n\n // Notify the host once per distinct failure — independent of how we render it.\n const reportedRef = useRef<string | null>(null);\n useEffect(() => {\n let info: { reason: 'not_found' | 'error'; message: string } | null = null;\n if (!sessionId && !userId) info = { reason: 'error', message: 'Provide a sessionId or a userId.' };\n else if (resolved.error) info = { reason: resolved.notFound ? 'not_found' : 'error', message: resolved.error };\n else if (playerError) info = playerError;\n if (info) {\n if (reportedRef.current !== info.message) {\n reportedRef.current = info.message;\n onError?.(info);\n }\n } else {\n reportedRef.current = null;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [sessionId, userId, resolved.error, resolved.notFound, playerError]);\n\n // No session to hand the player (bad config, still resolving, or no match).\n if (!effectiveId) {\n if (fallback === 'hide') return null;\n const msg =\n !sessionId && !userId\n ? 'Provide a sessionId or a userId to play a recording.'\n : needResolve && resolved.loading\n ? 'Finding the recording…'\n : (resolved.error ?? 'Recording unavailable.');\n return (\n <ThemeScope theme={theme} className=\"lum-widget--replay\">\n <div style={{ height }}>\n <div style={msgStyle}>{msg}</div>\n </div>\n </ThemeScope>\n );\n }\n\n // We have a session. If it fails to load and we're hiding, collapse the embed;\n // otherwise keep the player mounted so it shows its own (retry-capable) error UI.\n if (playerError && fallback === 'hide') return null;\n\n return (\n <ThemeScope theme={theme} className=\"lum-widget--replay\">\n <div style={{ height }}>\n <ReplayPlayer\n sessionId={effectiveId}\n apiBaseUrl={apiBaseUrl}\n apiKey={apiKey}\n token={token}\n startAtMs={startAtMs}\n clip={clip}\n defaultMode={defaultMode}\n allowedModes={allowedModes}\n defaultSpeed={defaultSpeed}\n allowFullscreen={allowFullscreen}\n shareUrl={shareUrl}\n onEnded={onEnded}\n onError={(info) => setPlayerError(info)}\n embedded\n />\n </div>\n </ThemeScope>\n );\n}\n","import type { CSSProperties, ReactNode } from 'react';\n\n/** Light/dark color scheme, or an object of `--lum-*` overrides to white-label. */\nexport type WidgetTheme = 'light' | 'dark' | Record<string, string>;\n\n/** Wraps a widget so its color scheme and any host CSS-var overrides (§16) apply\n * in scope. A string picks the built-in light/dark scheme (via `data-lum-theme`,\n * which works even on a host page of the opposite scheme); an object sets\n * specific `--lum-*` custom properties inline. */\nexport function ThemeScope({\n theme,\n className,\n children,\n}: {\n theme?: WidgetTheme;\n className?: string;\n children: ReactNode;\n}) {\n const scheme = typeof theme === 'string' ? theme : undefined;\n const overrides = theme && typeof theme === 'object' ? (theme as CSSProperties) : undefined;\n return (\n <div\n className={`lum-root lum lum-widget ${className ?? ''}`}\n data-lum-theme={scheme}\n style={overrides}\n >\n {children}\n </div>\n );\n}\n\nexport interface BaseWidgetProps {\n apiBaseUrl: string;\n apiKey?: string;\n token?: string;\n /** `'light'` or `'dark'` to pick a color scheme (default follows the page —\n * dark for the standalone embed), or an object of `--lum-*` overrides. */\n theme?: WidgetTheme;\n}\n","import { useEffect, useState } from 'react';\nimport type { InsightCard } from '@obsrviq/types';\nimport { Badge, Button, EmptyState, ErrorState, Skeleton, ToastProvider, useToast } from '@obsrviq/ui';\nimport { ThemeScope, type BaseWidgetProps } from './common.js';\nimport { apiGet, apiPost } from './client.js';\n\nexport interface ObsrviqInsightsProps extends BaseWidgetProps {\n siteId: string;\n max?: number;\n onApply?: (card: InsightCard) => void;\n onDismiss?: (card: InsightCard) => void;\n}\n\nconst SEVERITY_TONE: Record<InsightCard['severity'], 'info' | 'warn' | 'error'> = {\n info: 'info',\n low: 'info',\n medium: 'warn',\n high: 'error',\n};\n\nexport function ObsrviqInsights(props: ObsrviqInsightsProps) {\n return (\n <ThemeScope theme={props.theme} className=\"lum-widget--insights\">\n <ToastProvider>\n <InsightsInner {...props} />\n </ToastProvider>\n </ThemeScope>\n );\n}\n\nfunction InsightsInner({ siteId, apiBaseUrl, apiKey, token, max = 5, onApply, onDismiss }: ObsrviqInsightsProps) {\n const cfg = { apiBaseUrl, apiKey, token };\n const [cards, setCards] = useState<InsightCard[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const toast = useToast();\n\n useEffect(() => {\n let alive = true;\n apiGet<{ items: InsightCard[] }>(cfg, `/v1/insights?siteId=${siteId}`)\n .then((r) => alive && setCards(r.items))\n .catch((e) => alive && setError(e.message));\n return () => {\n alive = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteId]);\n\n const act = async (card: InsightCard, verb: 'apply' | 'dismiss') => {\n setCards((cs) => (cs ?? []).map((c) => (c.id === card.id ? { ...c, status: verb === 'apply' ? 'applied' : 'dismissed' } : c)));\n try {\n await apiPost(cfg, `/v1/insights/${card.id}/${verb}`);\n toast(verb === 'apply' ? 'Applied' : 'Dismissed', verb === 'apply' ? 'ok' : 'default');\n (verb === 'apply' ? onApply : onDismiss)?.(card);\n } catch {\n toast('Could not update — try again', 'error');\n }\n };\n\n if (error)\n return <ErrorState title=\"We couldn't load insights.\">{error}</ErrorState>;\n if (!cards)\n return (\n <div className=\"lum-w-cards\">\n {Array.from({ length: 3 }).map((_, i) => (\n <div className=\"lum-w-card\" key={i}>\n <Skeleton width=\"60%\" height={16} />\n <Skeleton width=\"100%\" height={40} />\n </div>\n ))}\n </div>\n );\n\n const visible = cards.filter((c) => c.status !== 'dismissed').slice(0, max);\n if (visible.length === 0)\n return <EmptyState title=\"No insights yet\">As soon as visitors arrive, recommendations will appear here.</EmptyState>;\n\n return (\n <div className=\"lum-w-cards\">\n {visible.map((c) => (\n <article className=\"lum-w-card\" key={c.id}>\n <header className=\"lum-w-card__head\">\n <Badge tone={SEVERITY_TONE[c.severity]}>{c.severity}</Badge>\n <strong>{c.title}</strong>\n </header>\n <p className=\"lum-w-card__what\">{c.what}</p>\n <p className=\"lum-w-card__why lum-muted\">{c.why}</p>\n <p className=\"lum-w-card__rec\">{c.recommendation}</p>\n <div className=\"lum-w-card__meta\">\n {c.expectedImpact && (\n <Badge tone=\"ok\">\n {c.expectedImpact.metric} {c.expectedImpact.lift}\n </Badge>\n )}\n <Badge>effort: {c.effort}</Badge>\n {c.evidence.length > 0 && <span className=\"lum-muted\">{c.evidence.length} sessions</span>}\n </div>\n <footer className=\"lum-w-card__actions\">\n {c.status === 'applied' ? (\n <Badge tone=\"ok\">Applied</Badge>\n ) : (\n <>\n <Button variant=\"primary\" size=\"sm\" onClick={() => act(c, 'apply')}>\n Apply\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={() => act(c, 'dismiss')}>\n Dismiss\n </Button>\n </>\n )}\n </footer>\n </article>\n ))}\n </div>\n );\n}\n","import type { CopilotChunk } from '@obsrviq/types';\n\nexport interface WidgetConfig {\n apiBaseUrl: string;\n /** sk_ server key OR a console JWT. */\n apiKey?: string;\n token?: string;\n}\n\nexport function headers(cfg: WidgetConfig): Record<string, string> {\n const key = cfg.token || cfg.apiKey;\n return key ? { authorization: `Bearer ${key}` } : {};\n}\n\nexport async function apiGet<T>(cfg: WidgetConfig, path: string): Promise<T> {\n const res = await fetch(`${cfg.apiBaseUrl.replace(/\\/$/, '')}${path}`, { headers: headers(cfg) });\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\n return (await res.json()) as T;\n}\n\nexport async function apiPost<T>(cfg: WidgetConfig, path: string, body?: unknown): Promise<T> {\n const res = await fetch(`${cfg.apiBaseUrl.replace(/\\/$/, '')}${path}`, {\n method: 'POST',\n headers: { ...headers(cfg), 'content-type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\n return (await res.json()) as T;\n}\n\n/** Stream the copilot SSE endpoint, yielding parsed CopilotChunks. */\nexport async function* copilotStream(\n cfg: WidgetConfig,\n siteId: string,\n question: string,\n): AsyncGenerator<CopilotChunk> {\n const res = await fetch(`${cfg.apiBaseUrl.replace(/\\/$/, '')}/v1/copilot/ask`, {\n method: 'POST',\n headers: { ...headers(cfg), 'content-type': 'application/json' },\n body: JSON.stringify({ siteId, question }),\n });\n if (!res.ok || !res.body) throw new Error(`copilot ${res.status}`);\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n const t = line.trim();\n if (!t.startsWith('data:')) continue;\n const data = t.slice(5).trim();\n if (data === '[DONE]') return;\n try {\n yield JSON.parse(data) as CopilotChunk;\n } catch {\n /* ignore */\n }\n }\n }\n}\n","import { useEffect, useState } from 'react';\nimport type { InsightCard } from '@obsrviq/types';\nimport { Badge, Button, EmptyState, ErrorState, Skeleton } from '@obsrviq/ui';\nimport { ThemeScope, type BaseWidgetProps } from './common.js';\nimport { apiGet, apiPost } from './client.js';\n\nexport interface ObsrviqRecommendationsProps extends BaseWidgetProps {\n siteId: string;\n onAction?: (rec: InsightCard) => void;\n}\n\n/** A prioritized recommendation queue (impact × confidence / effort, §14). */\nexport function ObsrviqRecommendations({ siteId, apiBaseUrl, apiKey, token, theme, onAction }: ObsrviqRecommendationsProps) {\n const cfg = { apiBaseUrl, apiKey, token };\n const [items, setItems] = useState<InsightCard[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let alive = true;\n apiGet<{ items: InsightCard[] }>(cfg, `/v1/insights?siteId=${siteId}`)\n .then((r) => alive && setItems(r.items))\n .catch((e) => alive && setError(e.message));\n return () => {\n alive = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteId]);\n\n const run = async (rec: InsightCard) => {\n setItems((xs) => (xs ?? []).filter((x) => x.id !== rec.id));\n try {\n await apiPost(cfg, `/v1/insights/${rec.id}/apply`);\n } catch {\n /* keep optimistic */\n }\n onAction?.(rec);\n };\n\n return (\n <ThemeScope theme={theme} className=\"lum-widget--recs\">\n {error ? (\n <ErrorState title=\"We couldn't load recommendations.\">{error}</ErrorState>\n ) : !items ? (\n <div className=\"lum-w-queue\">\n {Array.from({ length: 3 }).map((_, i) => (\n <Skeleton key={i} height={48} />\n ))}\n </div>\n ) : items.filter((i) => i.status === 'new' || i.status === 'viewed').length === 0 ? (\n <EmptyState title=\"You're all caught up\">No open recommendations right now.</EmptyState>\n ) : (\n <ol className=\"lum-w-queue\">\n {items\n .filter((i) => i.status === 'new' || i.status === 'viewed')\n .map((rec, i) => (\n <li className=\"lum-w-queue__item\" key={rec.id}>\n <span className=\"lum-w-queue__rank lum-mono\">{i + 1}</span>\n <div className=\"lum-w-queue__body\">\n <div className=\"lum-w-queue__title\">{rec.title}</div>\n <div className=\"lum-w-queue__meta\">\n <Badge tone={rec.severity === 'high' ? 'error' : rec.severity === 'medium' ? 'warn' : 'info'}>{rec.severity}</Badge>\n {rec.expectedImpact && <Badge tone=\"ok\">{rec.expectedImpact.lift}</Badge>}\n <Badge>effort: {rec.effort}</Badge>\n </div>\n </div>\n <Button size=\"sm\" variant=\"primary\" onClick={() => run(rec)}>\n {rec.action.type === 'one_click_apply' ? 'Apply' : rec.action.type === 'open_experiment' ? 'Experiment' : 'Review'}\n </Button>\n </li>\n ))}\n </ol>\n )}\n </ThemeScope>\n );\n}\n","import { useEffect, useState } from 'react';\nimport type { Score, ScoreType } from '@obsrviq/types';\nimport { Skeleton } from '@obsrviq/ui';\nimport { ThemeScope, type BaseWidgetProps } from './common.js';\nimport { apiGet } from './client.js';\n\nexport interface ObsrviqScoreProps extends BaseWidgetProps {\n siteId: string;\n type: ScoreType;\n size?: number;\n}\n\nconst LABEL: Record<ScoreType, string> = {\n accessibility: 'Accessibility',\n performance: 'Performance',\n 'ai-visibility': 'AI Visibility',\n};\nconst RATING_COLOR: Record<Score['rating'], string> = {\n good: 'var(--lum-ok)',\n 'needs-improvement': 'var(--lum-warn)',\n poor: 'var(--lum-error)',\n};\n\nexport function ObsrviqScore({ siteId, type, apiBaseUrl, apiKey, token, theme, size = 120 }: ObsrviqScoreProps) {\n const cfg = { apiBaseUrl, apiKey, token };\n const [score, setScore] = useState<Score | null>(null);\n\n useEffect(() => {\n let alive = true;\n apiGet<Score>(cfg, `/v1/scores?siteId=${siteId}&type=${type}`)\n .then((s) => alive && setScore(s))\n .catch(() => alive && setScore(null));\n return () => {\n alive = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteId, type]);\n\n const r = size / 2 - 8;\n const c = 2 * Math.PI * r;\n const value = score?.value ?? 0;\n const color = score ? RATING_COLOR[score.rating] : 'var(--lum-muted)';\n\n return (\n <ThemeScope theme={theme} className=\"lum-widget--score\">\n <div className=\"lum-w-score\" style={{ width: size }}>\n {!score ? (\n <Skeleton width={size} height={size} radius={size / 2} />\n ) : (\n <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} role=\"img\" aria-label={`${LABEL[type]} score ${value}`}>\n <circle cx={size / 2} cy={size / 2} r={r} fill=\"none\" stroke=\"var(--lum-viz-grid)\" strokeWidth={9} />\n <circle\n className=\"lum-w-score__arc\"\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n stroke={color}\n strokeWidth={9}\n strokeLinecap=\"round\"\n strokeDasharray={c}\n strokeDashoffset={c - (value / 100) * c}\n transform={`rotate(-90 ${size / 2} ${size / 2})`}\n style={{ ['--lum-arc-c' as string]: c }}\n />\n <text x=\"50%\" y=\"48%\" textAnchor=\"middle\" dominantBaseline=\"middle\" fontSize={size * 0.26} fill=\"var(--lum-text)\" fontWeight=\"700\" fontFamily=\"var(--lum-font-display)\" letterSpacing=\"-0.02em\">\n {value}\n </text>\n <text x=\"50%\" y=\"68%\" textAnchor=\"middle\" fill=\"var(--lum-muted)\" fontSize={size * 0.1}>\n / 100\n </text>\n </svg>\n )}\n <div className=\"lum-w-score__label\">{LABEL[type]}</div>\n </div>\n </ThemeScope>\n );\n}\n","import { useRef, useState } from 'react';\nimport { Send } from 'lucide-react';\nimport { ThemeScope, type BaseWidgetProps } from './common.js';\nimport { copilotStream } from './client.js';\n\nexport interface ObsrviqCopilotProps extends BaseWidgetProps {\n siteId: string;\n placeholder?: string;\n}\n\ninterface Turn {\n q: string;\n a: string;\n evidence: string[];\n streaming: boolean;\n}\n\n/** Embeddable copilot — NL Q&A grounded in the tenant's data (§14). */\nexport function ObsrviqCopilot({ siteId, apiBaseUrl, apiKey, token, theme, placeholder = 'Ask about your visitors…' }: ObsrviqCopilotProps) {\n const cfg = { apiBaseUrl, apiKey, token };\n const [input, setInput] = useState('');\n const [turns, setTurns] = useState<Turn[]>([]);\n const [busy, setBusy] = useState(false);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const ask = async () => {\n const q = input.trim();\n if (!q || busy) return;\n setInput('');\n setBusy(true);\n const idx = turns.length;\n setTurns((t) => [...t, { q, a: '', evidence: [], streaming: true }]);\n try {\n for await (const chunk of copilotStream(cfg, siteId, q)) {\n if (chunk.kind === 'token') {\n setTurns((t) => t.map((x, i) => (i === idx ? { ...x, a: x.a + chunk.text } : x)));\n } else if (chunk.kind === 'evidence') {\n setTurns((t) => t.map((x, i) => (i === idx ? { ...x, evidence: chunk.evidence.map((e) => e.ref) } : x)));\n } else if (chunk.kind === 'error') {\n setTurns((t) => t.map((x, i) => (i === idx ? { ...x, a: x.a + `\\n[error: ${chunk.message}]` } : x)));\n }\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }\n } catch (e) {\n setTurns((t) => t.map((x, i) => (i === idx ? { ...x, a: x.a + `\\n[connection error]` } : x)));\n } finally {\n setTurns((t) => t.map((x, i) => (i === idx ? { ...x, streaming: false } : x)));\n setBusy(false);\n }\n };\n\n return (\n <ThemeScope theme={theme} className=\"lum-widget--copilot\">\n <div className=\"lum-w-copilot\">\n <div className=\"lum-w-copilot__log\" ref={scrollRef}>\n {turns.length === 0 && (\n <div className=\"lum-w-copilot__hint lum-muted\">\n Try “Where are users struggling?” or “What's causing errors?”\n </div>\n )}\n {turns.map((t, i) => (\n <div key={i} className=\"lum-w-copilot__turn\">\n <div className=\"lum-w-copilot__q\">{t.q}</div>\n <div className=\"lum-w-copilot__a\">\n {t.a}\n {t.streaming && <span className=\"lum-w-copilot__caret\" />}\n {t.evidence.length > 0 && (\n <div className=\"lum-w-copilot__ev lum-muted\">Evidence: {t.evidence.length} session(s)</div>\n )}\n </div>\n </div>\n ))}\n </div>\n <form\n className=\"lum-w-copilot__bar\"\n onSubmit={(e) => {\n e.preventDefault();\n void ask();\n }}\n >\n <input\n className=\"lum-pl-search\"\n value={input}\n onChange={(e) => setInput(e.target.value)}\n placeholder={placeholder}\n aria-label=\"Ask the copilot\"\n />\n <button className=\"lum-btn lum-btn--primary lum-btn--sm\" type=\"submit\" disabled={busy} aria-label=\"Send\">\n <Send size={15} />\n </button>\n </form>\n </div>\n </ThemeScope>\n );\n}\n"],"mappings":";AAAA,SAAS,WAAW,QAAQ,gBAAgB;AAC5C,SAAS,oBAAoB;;;ACoBzB;AAZG,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,SAAS,OAAO,UAAU,WAAW,QAAQ;AACnD,QAAM,YAAY,SAAS,OAAO,UAAU,WAAY,QAA0B;AAClF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,2BAA2B,aAAa,EAAE;AAAA,MACrD,kBAAgB;AAAA,MAChB,OAAO;AAAA,MAEN;AAAA;AAAA,EACH;AAEJ;;;AD+KU,gBAAAA,YAAA;AAzJV,SAAS,YAAY,OAAgB,QAAyC;AAC5E,MAAI,MAAO,QAAO,EAAE,eAAe,UAAU,KAAK,GAAG;AACrD,MAAI,OAAQ,QAAO,EAAE,eAAe,UAAU,MAAM,IAAI,iBAAiB,OAAO;AAChF,SAAO,CAAC;AACV;AAUA,SAAS,mBACP,SACA,MAQU;AACV,QAAM,EAAE,YAAY,OAAO,QAAQ,QAAQ,QAAQ,KAAK,IAAI;AAC5D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAmB;AAAA,IAC3C,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO;AAAA,IACP,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,MAAM,KAAK,UAAU,CAAC,QAAQ,QAAQ,MAAM,SAAS,MAAM,OAAO,MAAM,WAAW,MAAM,OAAO,CAAC;AAEvG,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,OAAQ;AACzB,UAAM,OAAO,IAAI,gBAAgB;AACjC,aAAS,EAAE,WAAW,MAAM,SAAS,MAAM,OAAO,MAAM,UAAU,MAAM,CAAC;AACzE,UAAM,IAAI,IAAI,gBAAgB,EAAE,OAAO,CAAC;AACxC,QAAI,OAAQ,GAAE,IAAI,UAAU,MAAM;AAClC,QAAI,MAAM,WAAW,QAAQ,MAAM,SAAS,MAAM;AAChD,QAAE,IAAI,WAAW,OAAO,KAAK,OAAO,CAAC;AACrC,QAAE,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC;AAAA,IACnC,WAAW,MAAM,WAAW;AAC1B,QAAE,IAAI,aAAa,KAAK,SAAS;AACjC,UAAI,KAAK,QAAS,GAAE,IAAI,WAAW,KAAK,OAAO;AAAA,IACjD;AACA,UAAM,OAAO,WAAW,QAAQ,OAAO,EAAE;AACzC,UAAM,GAAG,IAAI,uBAAuB,EAAE,SAAS,CAAC,IAAI;AAAA,MAClD,SAAS,YAAY,OAAO,MAAM;AAAA,MAClC,QAAQ,KAAK;AAAA,IACf,CAAC,EACE,KAAK,OAAO,MAAM;AACjB,UAAI,CAAC,EAAE,IAAI;AACT,cAAM,WAAW,EAAE,WAAW;AAC9B,cAAM,OAAO;AAAA,UACX,IAAI,MAAM,WAAW,yCAAyC,kBAAkB,EAAE,MAAM,IAAI;AAAA,UAC5F,EAAE,SAAS;AAAA,QACb;AAAA,MACF;AACA,aAAO,EAAE,KAAK;AAAA,IAChB,CAAC,EACA,KAAK,CAAC,MAAM;AACX,UAAI,CAAC,KAAK,OAAO,QAAS,UAAS,EAAE,WAAW,EAAE,WAAW,SAAS,OAAO,OAAO,MAAM,UAAU,MAAM,CAAC;AAAA,IAC7G,CAAC,EACA,MAAM,CAAC,MAAe;AACrB,UAAI,KAAK,OAAO,QAAS;AACzB,YAAM,WAAW,CAAC,CAAE,GAA8B;AAClD,eAAS;AAAA,QACP,WAAW;AAAA,QACX,SAAS;AAAA,QACT,OAAO,aAAa,QAAQ,EAAE,UAAU;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACH,WAAO,MAAM,KAAK,MAAM;AAAA,EAE1B,GAAG,CAAC,SAAS,KAAK,UAAU,CAAC;AAE7B,SAAO;AACT;AAEA,IAAM,WAAW;AAAA,EACf,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW;AAAA,EACX,OAAO;AAAA,EACP,UAAU;AACZ;AAGO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AACX,GAAuB;AACrB,QAAM,cAAc,CAAC,aAAa,CAAC,CAAC;AACpC,QAAM,WAAW,mBAAmB,aAAa,EAAE,YAAY,OAAO,QAAQ,QAAQ,QAAQ,KAAK,CAAC;AACpG,QAAM,CAAC,aAAa,cAAc,IAAI,SAAoE,IAAI;AAC9G,QAAM,cAAc,aAAa,SAAS;AAG1C,YAAU,MAAM,eAAe,IAAI,GAAG,CAAC,WAAW,CAAC;AAGnD,QAAM,cAAc,OAAsB,IAAI;AAC9C,YAAU,MAAM;AACd,QAAI,OAAkE;AACtE,QAAI,CAAC,aAAa,CAAC,OAAQ,QAAO,EAAE,QAAQ,SAAS,SAAS,mCAAmC;AAAA,aACxF,SAAS,MAAO,QAAO,EAAE,QAAQ,SAAS,WAAW,cAAc,SAAS,SAAS,SAAS,MAAM;AAAA,aACpG,YAAa,QAAO;AAC7B,QAAI,MAAM;AACR,UAAI,YAAY,YAAY,KAAK,SAAS;AACxC,oBAAY,UAAU,KAAK;AAC3B,kBAAU,IAAI;AAAA,MAChB;AAAA,IACF,OAAO;AACL,kBAAY,UAAU;AAAA,IACxB;AAAA,EAEF,GAAG,CAAC,WAAW,QAAQ,SAAS,OAAO,SAAS,UAAU,WAAW,CAAC;AAGtE,MAAI,CAAC,aAAa;AAChB,QAAI,aAAa,OAAQ,QAAO;AAChC,UAAM,MACJ,CAAC,aAAa,CAAC,SACX,yDACA,eAAe,SAAS,UACtB,gCACC,SAAS,SAAS;AAC3B,WACE,gBAAAA,KAAC,cAAW,OAAc,WAAU,sBAClC,0BAAAA,KAAC,SAAI,OAAO,EAAE,OAAO,GACnB,0BAAAA,KAAC,SAAI,OAAO,UAAW,eAAI,GAC7B,GACF;AAAA,EAEJ;AAIA,MAAI,eAAe,aAAa,OAAQ,QAAO;AAE/C,SACE,gBAAAA,KAAC,cAAW,OAAc,WAAU,sBAClC,0BAAAA,KAAC,SAAI,OAAO,EAAE,OAAO,GACnB,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,CAAC,SAAS,eAAe,IAAI;AAAA,MACtC,UAAQ;AAAA;AAAA,EACV,GACF,GACF;AAEJ;;;AE5OA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAEpC,SAAS,OAAO,QAAQ,YAAY,YAAY,UAAU,eAAe,gBAAgB;;;ACOlF,SAAS,QAAQ,KAA2C;AACjE,QAAM,MAAM,IAAI,SAAS,IAAI;AAC7B,SAAO,MAAM,EAAE,eAAe,UAAU,GAAG,GAAG,IAAI,CAAC;AACrD;AAEA,eAAsB,OAAU,KAAmB,MAA0B;AAC3E,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,WAAW,QAAQ,OAAO,EAAE,CAAC,GAAG,IAAI,IAAI,EAAE,SAAS,QAAQ,GAAG,EAAE,CAAC;AAChG,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAC9D,SAAQ,MAAM,IAAI,KAAK;AACzB;AAEA,eAAsB,QAAW,KAAmB,MAAc,MAA4B;AAC5F,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,WAAW,QAAQ,OAAO,EAAE,CAAC,GAAG,IAAI,IAAI;AAAA,IACrE,QAAQ;AAAA,IACR,SAAS,EAAE,GAAG,QAAQ,GAAG,GAAG,gBAAgB,mBAAmB;AAAA,IAC/D,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,EACtC,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAC9D,SAAQ,MAAM,IAAI,KAAK;AACzB;AAGA,gBAAuB,cACrB,KACA,QACA,UAC8B;AAC9B,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,WAAW,QAAQ,OAAO,EAAE,CAAC,mBAAmB;AAAA,IAC7E,QAAQ;AAAA,IACR,SAAS,EAAE,GAAG,QAAQ,GAAG,GAAG,gBAAgB,mBAAmB;AAAA,IAC/D,MAAM,KAAK,UAAU,EAAE,QAAQ,SAAS,CAAC;AAAA,EAC3C,CAAC;AACD,MAAI,CAAC,IAAI,MAAM,CAAC,IAAI,KAAM,OAAM,IAAI,MAAM,WAAW,IAAI,MAAM,EAAE;AACjE,QAAM,SAAS,IAAI,KAAK,UAAU;AAClC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AACb,aAAS;AACP,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,UAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,aAAS,MAAM,IAAI,KAAK;AACxB,eAAW,QAAQ,OAAO;AACxB,YAAM,IAAI,KAAK,KAAK;AACpB,UAAI,CAAC,EAAE,WAAW,OAAO,EAAG;AAC5B,YAAM,OAAO,EAAE,MAAM,CAAC,EAAE,KAAK;AAC7B,UAAI,SAAS,SAAU;AACvB,UAAI;AACF,cAAM,KAAK,MAAM,IAAI;AAAA,MACvB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;;;ADvCQ,SA4EM,UA5EN,OAAAC,MAwCE,YAxCF;AAXR,IAAM,gBAA4E;AAAA,EAChF,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AACR;AAEO,SAAS,gBAAgB,OAA6B;AAC3D,SACE,gBAAAA,KAAC,cAAW,OAAO,MAAM,OAAO,WAAU,wBACxC,0BAAAA,KAAC,iBACC,0BAAAA,KAAC,iBAAe,GAAG,OAAO,GAC5B,GACF;AAEJ;AAEA,SAAS,cAAc,EAAE,QAAQ,YAAY,QAAQ,OAAO,MAAM,GAAG,SAAS,UAAU,GAAyB;AAC/G,QAAM,MAAM,EAAE,YAAY,QAAQ,MAAM;AACxC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAA+B,IAAI;AAC7D,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,QAAQ,SAAS;AAEvB,EAAAC,WAAU,MAAM;AACd,QAAI,QAAQ;AACZ,WAAiC,KAAK,uBAAuB,MAAM,EAAE,EAClE,KAAK,CAAC,MAAM,SAAS,SAAS,EAAE,KAAK,CAAC,EACtC,MAAM,CAAC,MAAM,SAAS,SAAS,EAAE,OAAO,CAAC;AAC5C,WAAO,MAAM;AACX,cAAQ;AAAA,IACV;AAAA,EAEF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,MAAM,OAAO,MAAmB,SAA8B;AAClE,aAAS,CAAC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,MAAO,EAAE,OAAO,KAAK,KAAK,EAAE,GAAG,GAAG,QAAQ,SAAS,UAAU,YAAY,YAAY,IAAI,CAAE,CAAC;AAC7H,QAAI;AACF,YAAM,QAAQ,KAAK,gBAAgB,KAAK,EAAE,IAAI,IAAI,EAAE;AACpD,YAAM,SAAS,UAAU,YAAY,aAAa,SAAS,UAAU,OAAO,SAAS;AACrF,OAAC,SAAS,UAAU,UAAU,aAAa,IAAI;AAAA,IACjD,QAAQ;AACN,YAAM,qCAAgC,OAAO;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI;AACF,WAAO,gBAAAF,KAAC,cAAW,OAAM,8BAA8B,iBAAM;AAC/D,MAAI,CAAC;AACH,WACE,gBAAAA,KAAC,SAAI,WAAU,eACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,qBAAC,SAAI,WAAU,cACb;AAAA,sBAAAA,KAAC,YAAS,OAAM,OAAM,QAAQ,IAAI;AAAA,MAClC,gBAAAA,KAAC,YAAS,OAAM,QAAO,QAAQ,IAAI;AAAA,SAFJ,CAGjC,CACD,GACH;AAGJ,QAAM,UAAU,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE,MAAM,GAAG,GAAG;AAC1E,MAAI,QAAQ,WAAW;AACrB,WAAO,gBAAAA,KAAC,cAAW,OAAM,mBAAkB,2EAA6D;AAE1G,SACE,gBAAAA,KAAC,SAAI,WAAU,eACZ,kBAAQ,IAAI,CAAC,MACZ,qBAAC,aAAQ,WAAU,cACjB;AAAA,yBAAC,YAAO,WAAU,oBAChB;AAAA,sBAAAA,KAAC,SAAM,MAAM,cAAc,EAAE,QAAQ,GAAI,YAAE,UAAS;AAAA,MACpD,gBAAAA,KAAC,YAAQ,YAAE,OAAM;AAAA,OACnB;AAAA,IACA,gBAAAA,KAAC,OAAE,WAAU,oBAAoB,YAAE,MAAK;AAAA,IACxC,gBAAAA,KAAC,OAAE,WAAU,6BAA6B,YAAE,KAAI;AAAA,IAChD,gBAAAA,KAAC,OAAE,WAAU,mBAAmB,YAAE,gBAAe;AAAA,IACjD,qBAAC,SAAI,WAAU,oBACZ;AAAA,QAAE,kBACD,qBAAC,SAAM,MAAK,MACT;AAAA,UAAE,eAAe;AAAA,QAAO;AAAA,QAAE,EAAE,eAAe;AAAA,SAC9C;AAAA,MAEF,qBAAC,SAAM;AAAA;AAAA,QAAS,EAAE;AAAA,SAAO;AAAA,MACxB,EAAE,SAAS,SAAS,KAAK,qBAAC,UAAK,WAAU,aAAa;AAAA,UAAE,SAAS;AAAA,QAAO;AAAA,SAAS;AAAA,OACpF;AAAA,IACA,gBAAAA,KAAC,YAAO,WAAU,uBACf,YAAE,WAAW,YACZ,gBAAAA,KAAC,SAAM,MAAK,MAAK,qBAAO,IAExB,iCACE;AAAA,sBAAAA,KAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,SAAS,MAAM,IAAI,GAAG,OAAO,GAAG,mBAEpE;AAAA,MACA,gBAAAA,KAAC,UAAO,SAAQ,SAAQ,MAAK,MAAK,SAAS,MAAM,IAAI,GAAG,SAAS,GAAG,qBAEpE;AAAA,OACF,GAEJ;AAAA,OA9BmC,EAAE,EA+BvC,CACD,GACH;AAEJ;;;AElHA,SAAS,aAAAG,YAAW,YAAAC,iBAAgB;AAEpC,SAAS,SAAAC,QAAO,UAAAC,SAAQ,cAAAC,aAAY,cAAAC,aAAY,YAAAC,iBAAgB;AAuCxD,gBAAAC,MAqBY,QAAAC,aArBZ;AA7BD,SAAS,uBAAuB,EAAE,QAAQ,YAAY,QAAQ,OAAO,OAAO,SAAS,GAAgC;AAC1H,QAAM,MAAM,EAAE,YAAY,QAAQ,MAAM;AACxC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAA+B,IAAI;AAC7D,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAEtD,EAAAC,WAAU,MAAM;AACd,QAAI,QAAQ;AACZ,WAAiC,KAAK,uBAAuB,MAAM,EAAE,EAClE,KAAK,CAAC,MAAM,SAAS,SAAS,EAAE,KAAK,CAAC,EACtC,MAAM,CAAC,MAAM,SAAS,SAAS,EAAE,OAAO,CAAC;AAC5C,WAAO,MAAM;AACX,cAAQ;AAAA,IACV;AAAA,EAEF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,MAAM,OAAO,QAAqB;AACtC,aAAS,CAAC,QAAQ,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;AAC1D,QAAI;AACF,YAAM,QAAQ,KAAK,gBAAgB,IAAI,EAAE,QAAQ;AAAA,IACnD,QAAQ;AAAA,IAER;AACA,eAAW,GAAG;AAAA,EAChB;AAEA,SACE,gBAAAH,KAAC,cAAW,OAAc,WAAU,oBACjC,kBACC,gBAAAA,KAACI,aAAA,EAAW,OAAM,qCAAqC,iBAAM,IAC3D,CAAC,QACH,gBAAAJ,KAAC,SAAI,WAAU,eACZ,gBAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,MACjC,gBAAAA,KAACK,WAAA,EAAiB,QAAQ,MAAX,CAAe,CAC/B,GACH,IACE,MAAM,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE,WAAW,QAAQ,EAAE,WAAW,IAC9E,gBAAAL,KAACM,aAAA,EAAW,OAAM,wBAAuB,gDAAkC,IAE3E,gBAAAN,KAAC,QAAG,WAAU,eACX,gBACE,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE,WAAW,QAAQ,EACzD,IAAI,CAAC,KAAK,MACT,gBAAAC,MAAC,QAAG,WAAU,qBACZ;AAAA,oBAAAD,KAAC,UAAK,WAAU,8BAA8B,cAAI,GAAE;AAAA,IACpD,gBAAAC,MAAC,SAAI,WAAU,qBACb;AAAA,sBAAAD,KAAC,SAAI,WAAU,sBAAsB,cAAI,OAAM;AAAA,MAC/C,gBAAAC,MAAC,SAAI,WAAU,qBACb;AAAA,wBAAAD,KAACO,QAAA,EAAM,MAAM,IAAI,aAAa,SAAS,UAAU,IAAI,aAAa,WAAW,SAAS,QAAS,cAAI,UAAS;AAAA,QAC3G,IAAI,kBAAkB,gBAAAP,KAACO,QAAA,EAAM,MAAK,MAAM,cAAI,eAAe,MAAK;AAAA,QACjE,gBAAAN,MAACM,QAAA,EAAM;AAAA;AAAA,UAAS,IAAI;AAAA,WAAO;AAAA,SAC7B;AAAA,OACF;AAAA,IACA,gBAAAP,KAACQ,SAAA,EAAO,MAAK,MAAK,SAAQ,WAAU,SAAS,MAAM,IAAI,GAAG,GACvD,cAAI,OAAO,SAAS,oBAAoB,UAAU,IAAI,OAAO,SAAS,oBAAoB,eAAe,UAC5G;AAAA,OAZqC,IAAI,EAa3C,CACD,GACL,GAEJ;AAEJ;;;AC1EA,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAEpC,SAAS,YAAAC,iBAAgB;AA6Cf,gBAAAC,MAEA,QAAAC,aAFA;AAnCV,IAAM,QAAmC;AAAA,EACvC,eAAe;AAAA,EACf,aAAa;AAAA,EACb,iBAAiB;AACnB;AACA,IAAM,eAAgD;AAAA,EACpD,MAAM;AAAA,EACN,qBAAqB;AAAA,EACrB,MAAM;AACR;AAEO,SAAS,aAAa,EAAE,QAAQ,MAAM,YAAY,QAAQ,OAAO,OAAO,OAAO,IAAI,GAAsB;AAC9G,QAAM,MAAM,EAAE,YAAY,QAAQ,MAAM;AACxC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAuB,IAAI;AAErD,EAAAC,WAAU,MAAM;AACd,QAAI,QAAQ;AACZ,WAAc,KAAK,qBAAqB,MAAM,SAAS,IAAI,EAAE,EAC1D,KAAK,CAAC,MAAM,SAAS,SAAS,CAAC,CAAC,EAChC,MAAM,MAAM,SAAS,SAAS,IAAI,CAAC;AACtC,WAAO,MAAM;AACX,cAAQ;AAAA,IACV;AAAA,EAEF,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,QAAM,IAAI,OAAO,IAAI;AACrB,QAAM,IAAI,IAAI,KAAK,KAAK;AACxB,QAAM,QAAQ,OAAO,SAAS;AAC9B,QAAM,QAAQ,QAAQ,aAAa,MAAM,MAAM,IAAI;AAEnD,SACE,gBAAAH,KAAC,cAAW,OAAc,WAAU,qBAClC,0BAAAC,MAAC,SAAI,WAAU,eAAc,OAAO,EAAE,OAAO,KAAK,GAC/C;AAAA,KAAC,QACA,gBAAAD,KAACI,WAAA,EAAS,OAAO,MAAM,QAAQ,MAAM,QAAQ,OAAO,GAAG,IAEvD,gBAAAH,MAAC,SAAI,OAAO,MAAM,QAAQ,MAAM,SAAS,OAAO,IAAI,IAAI,IAAI,IAAI,MAAK,OAAM,cAAY,GAAG,MAAM,IAAI,CAAC,UAAU,KAAK,IAClH;AAAA,sBAAAD,KAAC,YAAO,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG,GAAM,MAAK,QAAO,QAAO,uBAAsB,aAAa,GAAG;AAAA,MACnG,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,IAAI,OAAO;AAAA,UACX,IAAI,OAAO;AAAA,UACX;AAAA,UACA,MAAK;AAAA,UACL,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,eAAc;AAAA,UACd,iBAAiB;AAAA,UACjB,kBAAkB,IAAK,QAAQ,MAAO;AAAA,UACtC,WAAW,cAAc,OAAO,CAAC,IAAI,OAAO,CAAC;AAAA,UAC7C,OAAO,EAAE,CAAC,aAAuB,GAAG,EAAE;AAAA;AAAA,MACxC;AAAA,MACA,gBAAAA,KAAC,UAAK,GAAE,OAAM,GAAE,OAAM,YAAW,UAAS,kBAAiB,UAAS,UAAU,OAAO,MAAM,MAAK,mBAAkB,YAAW,OAAM,YAAW,2BAA0B,eAAc,WACnL,iBACH;AAAA,MACA,gBAAAA,KAAC,UAAK,GAAE,OAAM,GAAE,OAAM,YAAW,UAAS,MAAK,oBAAmB,UAAU,OAAO,KAAK,mBAExF;AAAA,OACF;AAAA,IAEF,gBAAAA,KAAC,SAAI,WAAU,sBAAsB,gBAAM,IAAI,GAAE;AAAA,KACnD,GACF;AAEJ;;;AC7EA,SAAS,UAAAK,SAAQ,YAAAC,iBAAgB;AACjC,SAAS,YAAY;AAuDT,gBAAAC,MAWM,QAAAC,aAXN;AAtCL,SAAS,eAAe,EAAE,QAAQ,YAAY,QAAQ,OAAO,OAAO,cAAc,gCAA2B,GAAwB;AAC1I,QAAM,MAAM,EAAE,YAAY,QAAQ,MAAM;AACxC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,EAAE;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAiB,CAAC,CAAC;AAC7C,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAS,KAAK;AACtC,QAAM,YAAYC,QAAuB,IAAI;AAE7C,QAAM,MAAM,YAAY;AACtB,UAAM,IAAI,MAAM,KAAK;AACrB,QAAI,CAAC,KAAK,KAAM;AAChB,aAAS,EAAE;AACX,YAAQ,IAAI;AACZ,UAAM,MAAM,MAAM;AAClB,aAAS,CAAC,MAAM,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,IAAI,UAAU,CAAC,GAAG,WAAW,KAAK,CAAC,CAAC;AACnE,QAAI;AACF,uBAAiB,SAAS,cAAc,KAAK,QAAQ,CAAC,GAAG;AACvD,YAAI,MAAM,SAAS,SAAS;AAC1B,mBAAS,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,MAAO,MAAM,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI,MAAM,KAAK,IAAI,CAAE,CAAC;AAAA,QAClF,WAAW,MAAM,SAAS,YAAY;AACpC,mBAAS,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,MAAO,MAAM,MAAM,EAAE,GAAG,GAAG,UAAU,MAAM,SAAS,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAE,CAAC;AAAA,QACzG,WAAW,MAAM,SAAS,SAAS;AACjC,mBAAS,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,MAAO,MAAM,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AAAA,UAAa,MAAM,OAAO,IAAI,IAAI,CAAE,CAAC;AAAA,QACrG;AACA,kBAAU,SAAS,SAAS,EAAE,KAAK,UAAU,QAAQ,aAAa,CAAC;AAAA,MACrE;AAAA,IACF,SAAS,GAAG;AACV,eAAS,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,MAAO,MAAM,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,IAAI;AAAA,oBAAuB,IAAI,CAAE,CAAC;AAAA,IAC9F,UAAE;AACA,eAAS,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,MAAO,MAAM,MAAM,EAAE,GAAG,GAAG,WAAW,MAAM,IAAI,CAAE,CAAC;AAC7E,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,gBAAAH,KAAC,cAAW,OAAc,WAAU,uBAClC,0BAAAC,MAAC,SAAI,WAAU,iBACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,sBAAqB,KAAK,WACtC;AAAA,YAAM,WAAW,KAChB,gBAAAD,KAAC,SAAI,WAAU,iCAAgC,+FAE/C;AAAA,MAED,MAAM,IAAI,CAAC,GAAG,MACb,gBAAAC,MAAC,SAAY,WAAU,uBACrB;AAAA,wBAAAD,KAAC,SAAI,WAAU,oBAAoB,YAAE,GAAE;AAAA,QACvC,gBAAAC,MAAC,SAAI,WAAU,oBACZ;AAAA,YAAE;AAAA,UACF,EAAE,aAAa,gBAAAD,KAAC,UAAK,WAAU,wBAAuB;AAAA,UACtD,EAAE,SAAS,SAAS,KACnB,gBAAAC,MAAC,SAAI,WAAU,+BAA8B;AAAA;AAAA,YAAW,EAAE,SAAS;AAAA,YAAO;AAAA,aAAW;AAAA,WAEzF;AAAA,WARQ,CASV,CACD;AAAA,OACH;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,YAAE,eAAe;AACjB,eAAK,IAAI;AAAA,QACX;AAAA,QAEA;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC;AAAA,cACA,cAAW;AAAA;AAAA,UACb;AAAA,UACA,gBAAAA,KAAC,YAAO,WAAU,wCAAuC,MAAK,UAAS,UAAU,MAAM,cAAW,QAChG,0BAAAA,KAAC,QAAK,MAAM,IAAI,GAClB;AAAA;AAAA;AAAA,IACF;AAAA,KACF,GACF;AAEJ;","names":["jsx","useEffect","useState","jsx","useState","useEffect","useEffect","useState","Badge","Button","EmptyState","ErrorState","Skeleton","jsx","jsxs","useState","useEffect","ErrorState","Skeleton","EmptyState","Badge","Button","useEffect","useState","Skeleton","jsx","jsxs","useState","useEffect","Skeleton","useRef","useState","jsx","jsxs","useState","useRef"]}
|