@sightspool/sdk 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +111 -333
- package/SECURITY.md +16 -0
- package/dist/index.cjs +159 -1226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -41
- package/dist/index.d.ts +20 -41
- package/dist/index.js +160 -761
- package/dist/index.js.map +1 -1
- package/dist/release.json +21 -0
- package/dist/sdk.global.js +2 -59
- package/dist/sdk.global.js.map +1 -1
- package/dist/source.json +11 -0
- package/package.json +14 -12
- package/site/CNAME +1 -0
- package/site/demo.html +6 -0
- package/site/demo.js +27 -0
- package/site/index.html +74 -0
- package/site/release.js +20 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/release.json +21 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js +3 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js.map +1 -0
- package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/source.json +11 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/release.json +21 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js +3 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js.map +1 -0
- package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/source.json +11 -0
- package/site/styles.css +69 -0
- package/site/trust.html +36 -0
- package/dist/chunk-4PADVIIO.js +0 -41
- package/dist/chunk-4PADVIIO.js.map +0 -1
- package/dist/probe-BNGMQQ5C.js +0 -113
- package/dist/probe-BNGMQQ5C.js.map +0 -1
- package/dist/prompt-GDFYC75D.js +0 -139
- package/dist/prompt-GDFYC75D.js.map +0 -1
- package/dist/survey-CICJQ5VI.js +0 -145
- package/dist/survey-CICJQ5VI.js.map +0 -1
package/dist/sdk.global.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/privacy.ts","../src/prompt.ts","../src/probe.ts","../src/survey.ts","../src/capture.ts","../src/harvest.ts","../src/egress.ts","../src/triggers.ts","../src/intervention.ts","../src/env.ts","../src/index.ts"],"names":["redactText","input","EMAIL_RE","LONG_DIGITS_RE","e","safeClosest","el","selector","isIgnoredElement","blockSelectors","IGNORE_ATTR","sel","matchesRedactSelector","redactSelectors","ATTACH_DISCLOSURE","REDACTED","init_privacy","__esmMin","prompt_exports","__export","showPrompt","opts","resolve","settled","host","shadow","finish","result","style","STYLE","wrap","render","node","card","x","disc","stateA","q","row","yes","no","stateB","c","b","se","stateText","submit","init_prompt","probe_exports","showProbe","findSlot","slot","config","anchor","inline","teardown","disclose","disclosure","INLINE_STYLE","FLOATING_STYLE","container","probe","p","init_probe","survey_exports","showSurvey","thank","thankYou","withClose","question","_a","_b","_c","opt","freeText","send","text","init_survey","TRAIL_MAX","DEAD_CLICK_MS","RAGE_WINDOW_MS","RAGE_COUNT","hasDom","createCapture","buf","lastError","started","subs","cleanups","recentClicks","notify","cb","push","type","label","currentRoute","currentLabel","onClick","ev","target","t","ts","isRage","routeBefore","mutated","observer","onError","onRejection","reason","installRouteTracking","fire","origPush","origReplace","args","r","installFetchTracking","orig","res","err","query","zeroResult","SEARCH_HINT_RE","DEBOUNCE_MS","looksLikeSearch","role","hay","createHarvest","capture","hint","timer","onInput","value","createEgress","queue","identity","interval","url","signals","body","json","blob","onVisibility","flush","batch","signal","next","detectFriction","trail","now","windowMs","recent","clicks","i","byLabel","n","DEFAULT_CAPS","canPrompt","state","caps","RENDERABLE","str","v","max","buildServeContext","route","ctx","account","plan","normalizeServed","raw","id","cfg","rawSlot","options","o","pickRespondentKey","userId","persisted","sessionRef","uid","RK_STORAGE_KEY","getRespondentKey","serveUrl","endpoint","path","fetchIntervention","data","served","submitResponse","LOCAL_HOSTS","isLocalhost","hostname","h","DEFAULT_ENDPOINT","FRICTION_EMIT_COOLDOWN_MS","EVENT_DEBOUNCE_MS","SERVE_SETTLE_MS","MAX_INTERVENTIONS_PER_SESSION","currentHostname","ctrl","uuid","deriveCandidates","out","buildSignal","trigger","extra","maybePrompt","maybeServeIntervention","respondentKey","prevShown","prevPromptAt","onCaptureEvent","onExitIntent","startRuntime","init","privacyOpts","harvest","egress","identify","traits","start","consent","granted","stop","api","src_default","key","list","attr"],"mappings":"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","file":"sdk.global.js","sourcesContent":["// Redaction — mask sensitive text before it ever leaves the page (GOV-3). The\n// pure string helpers are unit-tested; the DOM-querying part (selector masking)\n// lives in capture.ts and calls in here.\n\nconst EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g;\nconst LONG_DIGITS_RE = /\\d{6,}/g; // card / account-number-ish runs\n\nexport const MAX_LABEL_LEN = 280;\n\n/**\n * Mask PII-ish substrings in a captured label/verbatim and clamp length.\n * Conservative: emails and long digit runs become placeholders. Never throws.\n */\nexport function redactText(input: string | null | undefined): string {\n if (!input) return \"\";\n try {\n return String(input)\n .replace(EMAIL_RE, \"‹email›\")\n .replace(LONG_DIGITS_RE, \"‹num›\")\n .replace(/\\s+/g, \" \")\n .trim()\n .slice(0, MAX_LABEL_LEN);\n } catch {\n return \"\";\n }\n}\n\n/** Should a captured element's value be dropped entirely (not just masked)? */\nexport function isSensitiveInput(type: string | null | undefined): boolean {\n const t = (type ?? \"\").toLowerCase();\n return t === \"password\" || t === \"email\" || t === \"tel\" || t === \"creditcard\";\n}\n\nexport const ATTACH_DISCLOSURE = \"Session and account attached automatically.\";\n\n/** Placeholder substituted for the text of a `redact`-matched element (GOV-3). */\nexport const REDACTED = \"‹redacted›\";\n\n/** The per-element opt-out attribute: a click/input inside `[data-sightspool-ignore]` is dropped entirely. */\nexport const IGNORE_ATTR = \"data-sightspool-ignore\";\n\n/** Anything with a `.closest(selector)` — the bit of Element we depend on (kept DOM-free for unit tests). */\ntype Closeable = { closest?: (selectors: string) => unknown };\n\nfunction safeClosest(el: Closeable, selector: string): boolean {\n try {\n return typeof el.closest === \"function\" && el.closest(selector) != null;\n } catch {\n // An invalid selector (host misconfig) must never throw into capture — and must\n // never *accidentally capture* what was meant to be excluded: treat as no-match\n // for that one selector and let the others decide.\n return false;\n }\n}\n\n/**\n * Should this element's events be dropped entirely (not just masked)? True when the\n * element — or any ancestor — carries `data-sightspool-ignore` or matches one of the\n * configured `block` selectors. The host's hard privacy opt-out (GOV-3).\n */\nexport function isIgnoredElement(\n el: Closeable | null | undefined,\n blockSelectors: readonly string[] = [],\n): boolean {\n if (!el || typeof el.closest !== \"function\") return false;\n if (safeClosest(el, `[${IGNORE_ATTR}]`)) return true;\n for (const sel of blockSelectors) {\n if (sel && safeClosest(el, sel)) return true;\n }\n return false;\n}\n\n/**\n * Should this element's captured text be masked wholesale? True when the element —\n * or any ancestor — matches one of the configured `redact` selectors. (The event is\n * still recorded; only its label becomes {@link REDACTED}.)\n */\nexport function matchesRedactSelector(\n el: Closeable | null | undefined,\n redactSelectors: readonly string[] = [],\n): boolean {\n if (!el || typeof el.closest !== \"function\") return false;\n for (const sel of redactSelectors) {\n if (sel && safeClosest(el, sel)) return true;\n }\n return false;\n}\n","// The prompt UI (FR-5/6, the §16.2 blend) — rendered in a shadow root so the host\n// app's CSS can't style-break it and it leaks zero styles back. This module is\n// dynamically imported by index.ts only when a trigger fires, so it splits into a\n// lazily-loaded chunk and adds nothing to the host bundle until needed.\n//\n// State A — \"Were you able to do what you came here to do today?\" [Yes][Not really]\n// State B — (after \"Not really\") top candidate goals + an always-present\n// \"Something else\" → optional free text only after that.\n\nimport type { SignalAnswer } from \"./types\";\nimport { ATTACH_DISCLOSURE } from \"./privacy\";\n\nexport type PromptResult = {\n answer: SignalAnswer;\n intent?: string; // a tapped candidate\n verbatim?: string; // free text from \"Something else\"\n};\n\nexport type PromptOptions = {\n /** Locally-derived candidate goals (FR-5 State B). May be empty → generic ask. */\n candidates: string[];\n};\n\nconst STYLE = `\n:host { all: initial; }\n.wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;\n width: 320px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }\n.card { background: #fff; color: #18181b; border: 1px solid #e4e4e7; border-radius: 12px;\n box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }\n.q { font-size: 14px; font-weight: 600; margin: 0 0 12px; line-height: 1.35; }\n.row { display: flex; gap: 8px; flex-wrap: wrap; }\nbutton { font: inherit; font-size: 13px; cursor: pointer; border-radius: 8px; padding: 8px 12px;\n border: 1px solid #e4e4e7; background: #fafafa; color: #18181b; }\nbutton:hover { background: #f4f4f5; }\nbutton.primary { background: #18181b; color: #fff; border-color: #18181b; }\n.cand { display: block; width: 100%; text-align: left; margin-bottom: 6px; }\n.disc { font-size: 11px; color: #71717a; margin: 12px 0 0; }\n.x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;\n color: #a1a1aa; padding: 2px 6px; }\ninput { font: inherit; font-size: 13px; width: 100%; box-sizing: border-box; padding: 8px 10px;\n border: 1px solid #e4e4e7; border-radius: 8px; margin-bottom: 8px; }\n`;\n\nexport function showPrompt(opts: PromptOptions): Promise<PromptResult> {\n return new Promise((resolve) => {\n if (typeof document === \"undefined\") {\n resolve({ answer: \"dismissed\" });\n return;\n }\n\n let settled = false;\n const host = document.createElement(\"div\");\n const shadow = host.attachShadow({ mode: \"open\" });\n\n function finish(result: PromptResult) {\n if (settled) return;\n settled = true;\n try {\n host.remove();\n } catch {\n /* swallow */\n }\n resolve(result);\n }\n\n const style = document.createElement(\"style\");\n style.textContent = STYLE;\n shadow.appendChild(style);\n\n const wrap = document.createElement(\"div\");\n wrap.className = \"wrap\";\n shadow.appendChild(wrap);\n\n function render(node: HTMLElement) {\n wrap.innerHTML = \"\";\n const card = document.createElement(\"div\");\n card.className = \"card\";\n card.style.position = \"relative\";\n const x = document.createElement(\"button\");\n x.className = \"x\";\n x.textContent = \"×\";\n x.setAttribute(\"aria-label\", \"Dismiss\");\n x.onclick = () => finish({ answer: \"dismissed\" });\n card.appendChild(x);\n card.appendChild(node);\n const disc = document.createElement(\"p\");\n disc.className = \"disc\";\n disc.textContent = ATTACH_DISCLOSURE;\n card.appendChild(disc);\n wrap.appendChild(card);\n }\n\n // --- State A ---\n function stateA() {\n const node = document.createElement(\"div\");\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = \"Were you able to do what you came here to do today?\";\n node.appendChild(q);\n const row = document.createElement(\"div\");\n row.className = \"row\";\n const yes = document.createElement(\"button\");\n yes.className = \"primary\";\n yes.textContent = \"Yes\";\n yes.onclick = () => finish({ answer: \"yes\" });\n const no = document.createElement(\"button\");\n no.textContent = \"Not really\";\n no.onclick = () => stateB();\n row.append(yes, no);\n node.appendChild(row);\n render(node);\n }\n\n // --- State B ---\n function stateB() {\n const node = document.createElement(\"div\");\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = \"What were you trying to do?\";\n node.appendChild(q);\n for (const c of opts.candidates.slice(0, 4)) {\n const b = document.createElement(\"button\");\n b.className = \"cand\";\n b.textContent = c;\n b.onclick = () => finish({ answer: \"not_really\", intent: c });\n node.appendChild(b);\n }\n const se = document.createElement(\"button\");\n se.className = \"cand\";\n se.textContent = \"Something else…\";\n se.onclick = () => stateText();\n node.appendChild(se);\n render(node);\n }\n\n // --- \"Something else\" free text ---\n function stateText() {\n const node = document.createElement(\"div\");\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = \"What were you trying to do?\";\n node.appendChild(q);\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.placeholder = \"In your own words…\";\n node.appendChild(input);\n const row = document.createElement(\"div\");\n row.className = \"row\";\n const submit = document.createElement(\"button\");\n submit.className = \"primary\";\n submit.textContent = \"Send\";\n submit.onclick = () =>\n finish({ answer: \"not_really\", verbatim: input.value.trim() || undefined });\n row.appendChild(submit);\n node.appendChild(row);\n render(node);\n try {\n input.focus();\n } catch {\n /* swallow */\n }\n }\n\n try {\n document.body.appendChild(host);\n stateA();\n } catch {\n finish({ answer: \"dismissed\" });\n }\n });\n}\n","// The demand-probe widget — the honest painted door, client half. Renders a\n// human-approved probe served by /api/sdk/serve: a dashed-border button\n// standing in for a feature that DOESN'T exist yet. Clicking is a vote; the\n// widget then shows the server's fixed disclosure (\"this doesn't exist yet —\n// your click was counted as a vote\"), so the pattern is never a deceptive\n// fake door. Same shadow-root + lazy-import discipline as survey.ts.\n//\n// Two placements:\n// floating (default) — the survey-style card, bottom-right; zero integration.\n// slot — the button mounts INSIDE the client's own UI, but only where the\n// client explicitly invited it: an element carrying\n// data-sightspool-slot=\"<slot>\". We only ever append into that anchor\n// (own host node + shadow root — no sibling injection, no layout edits);\n// if the anchor isn't on the page, we mount NOTHING and report it, so the\n// caller can restore its fatigue counters.\n\nexport type ProbeConfig = {\n /** The feature as the user would want it — the dashed button's copy. */\n label: string;\n /** The fixed post-vote honesty line, injected server-side. Required: the\n * widget refuses to render without it (see normalizeServed). */\n disclosure: string;\n /** Optional inline anchor: mount inside [data-sightspool-slot=\"<slot>\"]. */\n slot?: string;\n};\n\nexport type ProbeResult = {\n voted?: boolean;\n dismissed?: boolean;\n /** false = the declared slot wasn't on this page, nothing rendered. */\n mounted: boolean;\n};\n\nconst FLOATING_STYLE = `\n:host { all: initial; }\n.wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;\n width: 340px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }\n.card { position: relative; background: #fff; color: #18181b; border: 1px solid #e4e4e7;\n border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }\n.probe { font: inherit; font-size: 13px; cursor: pointer; display: block; width: 100%;\n text-align: left; border: 1px dashed #a1a1aa; border-radius: 8px; padding: 10px 12px;\n background: #fafafa; color: #3f3f46; }\n.probe:hover { border-color: #18181b; color: #18181b; }\n.x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;\n color: #a1a1aa; padding: 2px 6px; cursor: pointer; }\n.done { font-size: 13px; color: #18181b; margin: 0; line-height: 1.4; }\n`;\n\n// Inline: no fixed positioning, no card chrome — just the dashed affordance,\n// sized by its content, so the host layout stays the host's.\nconst INLINE_STYLE = `\n:host { all: initial; display: inline-block; max-width: 100%; }\n.probe { font: inherit; font-family: system-ui, -apple-system, sans-serif; font-size: 13px;\n cursor: pointer; display: inline-block; text-align: left; border: 1px dashed #a1a1aa;\n border-radius: 8px; padding: 8px 12px; background: transparent; color: #52525b; }\n.probe:hover { border-color: #18181b; color: #18181b; }\n.done { font-family: system-ui, -apple-system, sans-serif; font-size: 13px; color: #52525b;\n margin: 0; line-height: 1.4; border: 1px dashed #d4d4d8; border-radius: 8px; padding: 8px 12px; }\n`;\n\nconst DISCLOSURE_MS = 3200; // long enough to read the honesty line, then close\n\nfunction findSlot(slot: string): Element | null {\n try {\n // The slot token is validated upstream ([a-z0-9_-]), so it's quote-safe.\n return document.querySelector(`[data-sightspool-slot=\"${slot}\"]`);\n } catch {\n return null;\n }\n}\n\nexport function showProbe(config: ProbeConfig): Promise<ProbeResult> {\n return new Promise((resolve) => {\n if (typeof document === \"undefined\") {\n resolve({ dismissed: true, mounted: false });\n return;\n }\n\n const anchor = config.slot ? findSlot(config.slot) : null;\n if (config.slot && !anchor) {\n // The client declared a placement and this page doesn't have it —\n // render nothing (never fall back to floating: the probe shows where\n // the client intended, or nowhere).\n resolve({ mounted: false });\n return;\n }\n\n let settled = false;\n const inline = !!anchor;\n const host = document.createElement(inline ? \"span\" : \"div\");\n const shadow = host.attachShadow({ mode: \"open\" });\n\n function teardown() {\n try {\n host.remove();\n } catch {\n /* swallow */\n }\n }\n\n function finish(result: ProbeResult, disclose: boolean) {\n if (settled) return;\n settled = true;\n resolve(result);\n if (disclose) {\n disclosure();\n setTimeout(teardown, DISCLOSURE_MS);\n } else {\n teardown();\n }\n }\n\n const style = document.createElement(\"style\");\n style.textContent = inline ? INLINE_STYLE : FLOATING_STYLE;\n shadow.appendChild(style);\n\n const wrap = document.createElement(inline ? \"span\" : \"div\");\n if (!inline) wrap.className = \"wrap\";\n shadow.appendChild(wrap);\n\n function container(): HTMLElement {\n wrap.innerHTML = \"\";\n if (inline) return wrap as HTMLElement;\n const c = document.createElement(\"div\");\n c.className = \"card\";\n wrap.appendChild(c);\n return c;\n }\n\n function probe() {\n const c = container();\n if (!inline) {\n const x = document.createElement(\"button\");\n x.className = \"x\";\n x.textContent = \"×\";\n x.setAttribute(\"aria-label\", \"Dismiss\");\n x.onclick = () => finish({ dismissed: true, mounted: true }, false);\n c.appendChild(x);\n }\n const b = document.createElement(\"button\");\n b.className = \"probe\";\n b.textContent = config.label;\n b.onclick = () => finish({ voted: true, mounted: true }, true);\n c.appendChild(b);\n }\n\n // The truth-telling moment — the only thing separating this from a fake\n // door. Always the server's fixed copy, shown after every vote.\n function disclosure() {\n const c = container();\n const p = document.createElement(\"p\");\n p.className = \"done\";\n p.textContent = config.disclosure;\n c.appendChild(p);\n }\n\n try {\n (anchor ?? document.body).appendChild(host);\n probe();\n } catch {\n finish({ dismissed: true, mounted: false }, false);\n }\n });\n}\n","// The intervention survey widget (Wave 0005 slice B — the client half). Renders a\n// human-approved one-tap survey served by /api/sdk/serve, in a shadow root so the\n// host app's CSS can't style-break it and it leaks zero styles back. Dynamically\n// imported by index.ts only when the serve endpoint actually returns something, so\n// it splits into its own lazily-loaded chunk and adds nothing to the host bundle\n// until a survey is shown. Mirrors prompt.ts (the passive ask) deliberately.\n//\n// question + [option] [option] … (tap an option → choice)\n// + \"Something else…\" → free text (only when allow_text)\n\nexport type SurveyConfig = {\n question: string;\n options?: string[];\n allow_text?: boolean;\n};\n\nexport type SurveyResult = {\n choice?: string;\n text?: string;\n dismissed?: boolean;\n};\n\nconst STYLE = `\n:host { all: initial; }\n.wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;\n width: 340px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }\n.card { position: relative; background: #fff; color: #18181b; border: 1px solid #e4e4e7;\n border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }\n.q { font-size: 14px; font-weight: 600; margin: 0 0 12px; line-height: 1.35; padding-right: 16px; }\n.row { display: flex; gap: 8px; flex-wrap: wrap; }\nbutton { font: inherit; font-size: 13px; cursor: pointer; border-radius: 8px; padding: 8px 12px;\n border: 1px solid #e4e4e7; background: #fafafa; color: #18181b; }\nbutton:hover { background: #f4f4f5; }\nbutton.primary { background: #18181b; color: #fff; border-color: #18181b; }\n.opt { display: block; width: 100%; text-align: left; margin-bottom: 6px; }\n.x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;\n color: #a1a1aa; padding: 2px 6px; cursor: pointer; }\n.done { font-size: 13px; color: #18181b; margin: 0; }\ninput { font: inherit; font-size: 13px; width: 100%; box-sizing: border-box; padding: 8px 10px;\n border: 1px solid #e4e4e7; border-radius: 8px; margin-bottom: 8px; }\n`;\n\nconst THANKS_MS = 1100; // brief acknowledgement, then auto-close\n\nexport function showSurvey(config: SurveyConfig): Promise<SurveyResult> {\n return new Promise((resolve) => {\n if (typeof document === \"undefined\") {\n resolve({ dismissed: true });\n return;\n }\n\n let settled = false;\n const host = document.createElement(\"div\");\n const shadow = host.attachShadow({ mode: \"open\" });\n\n function teardown() {\n try {\n host.remove();\n } catch {\n /* swallow */\n }\n }\n\n // Resolve immediately (so the answer is sent without delay) but leave a short\n // \"Thanks\" on screen before removing the node.\n function finish(result: SurveyResult, thank: boolean) {\n if (settled) return;\n settled = true;\n resolve(result);\n if (thank) {\n thankYou();\n setTimeout(teardown, THANKS_MS);\n } else {\n teardown();\n }\n }\n\n const style = document.createElement(\"style\");\n style.textContent = STYLE;\n shadow.appendChild(style);\n\n const wrap = document.createElement(\"div\");\n wrap.className = \"wrap\";\n shadow.appendChild(wrap);\n\n function card(): HTMLElement {\n wrap.innerHTML = \"\";\n const c = document.createElement(\"div\");\n c.className = \"card\";\n wrap.appendChild(c);\n return c;\n }\n\n function withClose(c: HTMLElement) {\n const x = document.createElement(\"button\");\n x.className = \"x\";\n x.textContent = \"×\";\n x.setAttribute(\"aria-label\", \"Dismiss\");\n x.onclick = () => finish({ dismissed: true }, false);\n c.appendChild(x);\n }\n\n function question() {\n const c = card();\n withClose(c);\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = config.question;\n c.appendChild(q);\n\n for (const opt of (config.options ?? []).slice(0, 6)) {\n const b = document.createElement(\"button\");\n b.className = \"opt\";\n b.textContent = opt;\n b.onclick = () => finish({ choice: opt }, true);\n c.appendChild(b);\n }\n\n if (config.allow_text) {\n const se = document.createElement(\"button\");\n se.className = \"opt\";\n // If there were no options, this is the only path — label it plainly.\n se.textContent = (config.options?.length ?? 0) > 0 ? \"Something else…\" : \"Answer…\";\n se.onclick = freeText;\n c.appendChild(se);\n }\n }\n\n function freeText() {\n const c = card();\n withClose(c);\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = config.question;\n c.appendChild(q);\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.placeholder = \"In your own words…\";\n c.appendChild(input);\n const row = document.createElement(\"div\");\n row.className = \"row\";\n const send = document.createElement(\"button\");\n send.className = \"primary\";\n send.textContent = \"Send\";\n const submit = () => {\n const text = input.value.trim();\n if (!text) {\n finish({ dismissed: true }, false);\n return;\n }\n finish({ text }, true);\n };\n send.onclick = submit;\n input.onkeydown = (e) => {\n if ((e as KeyboardEvent).key === \"Enter\") submit();\n };\n row.appendChild(send);\n c.appendChild(row);\n try {\n input.focus();\n } catch {\n /* swallow */\n }\n }\n\n function thankYou() {\n const c = card();\n const p = document.createElement(\"p\");\n p.className = \"done\";\n p.textContent = \"Thanks — that helps.\";\n c.appendChild(p);\n }\n\n try {\n document.body.appendChild(host);\n question();\n } catch {\n finish({ dismissed: true }, false);\n }\n });\n}\n","// Passive context capture (FR-2) — the buffer of route/click/error events the\n// rest of the runtime reads. All DOM access is guarded and wrapped: this module\n// must never throw into the host app (NFR-3).\n\nimport type { TrailEvent, TrailEventType } from \"./types\";\nimport { redactText, isIgnoredElement, matchesRedactSelector, REDACTED } from \"./privacy\";\n\nconst TRAIL_MAX = 30;\nconst DEAD_CLICK_MS = 700; // a click with no DOM/route change after this = dead-click\nconst RAGE_WINDOW_MS = 1_000;\nconst RAGE_COUNT = 3;\n\nexport type CaptureHandle = {\n start(): void;\n stop(): void;\n trail(): TrailEvent[];\n route(): string;\n label(): string;\n error(): string | undefined;\n /** Subscribe to \"a meaningful event happened\" (the trigger engine polls off this). */\n onEvent(cb: () => void): void;\n /** Called by harvest.ts when a search/filter query is typed. */\n recordSearch(query: string, zeroResult?: boolean): void;\n};\n\nfunction hasDom(): boolean {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\nexport function createCapture(opts: {\n debug: boolean;\n redact?: readonly string[];\n block?: readonly string[];\n}): CaptureHandle {\n const redactSelectors = opts.redact ?? [];\n const blockSelectors = opts.block ?? [];\n let buf: TrailEvent[] = [];\n let lastError: string | undefined;\n let started = false;\n const subs: Array<() => void> = [];\n const cleanups: Array<() => void> = [];\n let recentClicks: number[] = []; // timestamps, for rage detection\n\n function notify() {\n for (const cb of subs) {\n try {\n cb();\n } catch {\n /* a subscriber must never break capture */\n }\n }\n }\n\n function push(type: TrailEventType, label?: string) {\n try {\n buf.push({ t: Date.now(), type, label: label ? redactText(label) : undefined });\n if (buf.length > TRAIL_MAX) buf = buf.slice(-TRAIL_MAX);\n if (opts.debug) console.debug(\"[sightspool] event\", type, label);\n notify();\n } catch {\n /* swallow */\n }\n }\n\n function currentRoute(): string {\n try {\n return location.pathname + location.search;\n } catch {\n return \"\";\n }\n }\n\n function currentLabel(): string {\n try {\n return document.title || \"\";\n } catch {\n return \"\";\n }\n }\n\n function onClick(ev: MouseEvent) {\n try {\n const target = ev.target as Element | null;\n // Hard opt-out: a click inside [data-sightspool-ignore] or a `block` selector is\n // never recorded — not even as an unlabelled event (GOV-3).\n if (isIgnoredElement(target, blockSelectors)) return;\n const text =\n (target && (target.getAttribute?.(\"aria-label\") || target.textContent)) || \"\";\n // `redact` selectors mask the label wholesale; emails/digits in any label are\n // also masked by push() → redactText.\n const label = matchesRedactSelector(target, redactSelectors)\n ? REDACTED\n : text.trim().slice(0, 60);\n const t = Date.now();\n\n recentClicks = recentClicks.filter((ts) => t - ts <= RAGE_WINDOW_MS);\n recentClicks.push(t);\n const isRage = recentClicks.length >= RAGE_COUNT;\n push(isRage ? \"rage_click\" : \"click\", label);\n\n // dead-click: did anything change shortly after? watch for a DOM mutation or\n // a route change; if neither, record a dead_click.\n const routeBefore = currentRoute();\n let mutated = false;\n let observer: MutationObserver | null = null;\n try {\n observer = new MutationObserver(() => {\n mutated = true;\n });\n observer.observe(document.body, { childList: true, subtree: true, attributes: true });\n } catch {\n /* no MutationObserver — skip dead-click detection */\n }\n window.setTimeout(() => {\n try {\n observer?.disconnect();\n if (!mutated && currentRoute() === routeBefore && label) {\n push(\"dead_click\", label);\n }\n } catch {\n /* swallow */\n }\n }, DEAD_CLICK_MS);\n } catch {\n /* swallow */\n }\n }\n\n function onError(ev: ErrorEvent) {\n try {\n lastError = String(ev.message || \"error\");\n push(\"error\", lastError);\n } catch {\n /* swallow */\n }\n }\n\n function onRejection(ev: PromiseRejectionEvent) {\n try {\n const reason = ev.reason;\n lastError = reason instanceof Error ? reason.message : String(reason);\n push(\"error\", lastError);\n } catch {\n /* swallow */\n }\n }\n\n // Route changes: patch history.pushState/replaceState + listen for popstate.\n function installRouteTracking() {\n try {\n const fire = () => push(\"route\", currentRoute());\n const origPush = history.pushState;\n const origReplace = history.replaceState;\n history.pushState = function (this: History, ...args: Parameters<History[\"pushState\"]>) {\n const r = origPush.apply(this, args);\n fire();\n return r;\n };\n history.replaceState = function (\n this: History,\n ...args: Parameters<History[\"replaceState\"]>\n ) {\n const r = origReplace.apply(this, args);\n fire();\n return r;\n };\n window.addEventListener(\"popstate\", fire);\n cleanups.push(() => {\n history.pushState = origPush;\n history.replaceState = origReplace;\n window.removeEventListener(\"popstate\", fire);\n });\n push(\"route\", currentRoute()); // seed with the entry route\n } catch {\n /* swallow */\n }\n }\n\n // Light fetch wrapper to catch failed/4xx-5xx requests as request_error events.\n function installFetchTracking() {\n try {\n if (typeof window.fetch !== \"function\") return;\n const orig = window.fetch.bind(window);\n window.fetch = async (...args: Parameters<typeof fetch>) => {\n try {\n const res = await orig(...args);\n if (!res.ok) push(\"request_error\", `HTTP ${res.status}`);\n return res;\n } catch (err) {\n push(\"request_error\", err instanceof Error ? err.message : \"network error\");\n throw err;\n }\n };\n cleanups.push(() => {\n window.fetch = orig;\n });\n } catch {\n /* swallow */\n }\n }\n\n return {\n start() {\n if (started || !hasDom()) return;\n started = true;\n try {\n document.addEventListener(\"click\", onClick, true);\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n cleanups.push(() => {\n document.removeEventListener(\"click\", onClick, true);\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n });\n installRouteTracking();\n installFetchTracking();\n } catch {\n /* swallow */\n }\n },\n stop() {\n started = false;\n for (const c of cleanups.splice(0)) {\n try {\n c();\n } catch {\n /* swallow */\n }\n }\n },\n trail() {\n return buf.slice();\n },\n route: currentRoute,\n label: currentLabel,\n error() {\n return lastError;\n },\n onEvent(cb) {\n subs.push(cb);\n },\n recordSearch(query, zeroResult) {\n const q = query.trim();\n if (!q) return;\n push(zeroResult ? \"zero_result\" : \"search\", q);\n },\n };\n}\n","// Intent harvest (FR-3) — treat typed queries in search / filter / command-palette\n// / empty-state inputs as STATED intent (the highest-signal intent, no question\n// needed). Harvesting precedes any inference. Defensive throughout (NFR-3).\n//\n// Zero-result detection is genuinely cross-app-specific and best-effort in v1: we\n// capture the query as a search event; flagging it as zero-result reliably is a\n// follow-up (it needs per-app empty-state hints). The query itself is the value.\n\nimport type { CaptureHandle } from \"./capture\";\nimport { isIgnoredElement, matchesRedactSelector } from \"./privacy\";\n\nconst SEARCH_HINT_RE = /search|filter|find|query|command|lookup/i;\nconst DEBOUNCE_MS = 800;\n\nexport type HarvestHandle = {\n start(): void;\n stop(): void;\n /** The most recent stated intent (last search/filter query), for State-B candidates. */\n lastIntentHint(): string | undefined;\n};\n\nfunction looksLikeSearch(el: Element): boolean {\n try {\n const input = el as HTMLInputElement;\n if (input.type === \"search\") return true;\n const role = el.getAttribute(\"role\") || \"\";\n if (role === \"searchbox\" || role === \"combobox\") return true;\n const hay = [\n input.name,\n input.placeholder,\n el.getAttribute(\"aria-label\"),\n el.id,\n el.className,\n ]\n .filter(Boolean)\n .join(\" \");\n return SEARCH_HINT_RE.test(hay);\n } catch {\n return false;\n }\n}\n\nexport function createHarvest(\n capture: CaptureHandle,\n opts: { debug: boolean; redact?: readonly string[]; block?: readonly string[] },\n): HarvestHandle {\n let hint: string | undefined;\n let timer: number | null = null;\n let started = false;\n const redactSelectors = opts.redact ?? [];\n const blockSelectors = opts.block ?? [];\n\n function onInput(ev: Event) {\n try {\n const target = ev.target as HTMLInputElement | null;\n if (!target || (target.tagName !== \"INPUT\" && target.tagName !== \"TEXTAREA\")) return;\n if (!looksLikeSearch(target)) return;\n // A masked query is useless intent, so a `redact`-matched search box is treated\n // as a hard opt-out here (same as `block`/ignore): don't harvest the value at all.\n if (isIgnoredElement(target, blockSelectors) || matchesRedactSelector(target, redactSelectors))\n return;\n const value = (target.value || \"\").trim();\n if (value.length < 2) return;\n\n if (timer !== null) window.clearTimeout(timer);\n timer = window.setTimeout(() => {\n hint = value;\n capture.recordSearch(value);\n if (opts.debug) console.debug(\"[sightspool] harvested intent\", value);\n }, DEBOUNCE_MS);\n } catch {\n /* swallow */\n }\n }\n\n return {\n start() {\n if (started || typeof document === \"undefined\") return;\n started = true;\n try {\n document.addEventListener(\"input\", onInput, true);\n } catch {\n /* swallow */\n }\n },\n stop() {\n started = false;\n try {\n document.removeEventListener(\"input\", onInput, true);\n if (timer !== null) window.clearTimeout(timer);\n } catch {\n /* swallow */\n }\n },\n lastIntentHint() {\n return hint;\n },\n };\n}\n","// Egress — batch captured Signals and ship them to /api/sdk/ingest, preferring\n// navigator.sendBeacon (survives page unload) with a fetch+keepalive fallback.\n// Every path is wrapped: a failed send must never surface in the host app (NFR-3),\n// and a Signal already records its why/cost passively, so a dropped beacon just\n// loses enrichment, not the capture's value (FR-7).\n\nimport type { CapturedSignal, Identity, IngestBody } from \"./types\";\n\nconst FLUSH_BATCH = 10; // flush when this many Signals are queued\nconst FLUSH_INTERVAL_MS = 15_000;\n\nexport type EgressHandle = {\n start(): void;\n stop(): void;\n enqueue(signal: CapturedSignal): void;\n flush(): void;\n setIdentity(identity: Identity): void;\n};\n\nexport function createEgress(opts: {\n key: string;\n endpoint: string;\n debug: boolean;\n}): EgressHandle {\n let queue: CapturedSignal[] = [];\n let identity: Identity | undefined;\n let interval: number | null = null;\n let started = false;\n\n const url = `${opts.endpoint.replace(/\\/+$/, \"\")}/api/sdk/ingest`;\n\n function send(signals: CapturedSignal[]) {\n if (signals.length === 0) return;\n const body: IngestBody = { key: opts.key, identity, signals };\n const json = JSON.stringify(body);\n try {\n // text/plain is a CORS-safelisted content type, so a cross-origin beacon\n // skips the preflight entirely (the host app's domain ≠ ours). The server\n // parses the text as JSON regardless.\n if (typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\") {\n const blob = new Blob([json], { type: \"text/plain\" });\n const ok = navigator.sendBeacon(url, blob);\n if (ok) {\n if (opts.debug) console.debug(\"[sightspool] beacon\", signals.length);\n return;\n }\n }\n // Fallback: fetch with keepalive so it can outlive the page.\n void fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"text/plain\" },\n body: json,\n keepalive: true,\n mode: \"cors\",\n credentials: \"omit\",\n }).catch(() => {\n /* swallow — drop on failure */\n });\n } catch {\n /* swallow */\n }\n }\n\n function onVisibility() {\n try {\n if (document.visibilityState === \"hidden\") flush();\n } catch {\n /* swallow */\n }\n }\n\n function flush() {\n if (queue.length === 0) return;\n const batch = queue;\n queue = [];\n send(batch);\n }\n\n return {\n start() {\n if (started || typeof window === \"undefined\") return;\n started = true;\n try {\n document.addEventListener(\"visibilitychange\", onVisibility);\n window.addEventListener(\"pagehide\", flush);\n interval = window.setInterval(flush, FLUSH_INTERVAL_MS);\n } catch {\n /* swallow */\n }\n },\n stop() {\n started = false;\n try {\n document.removeEventListener(\"visibilitychange\", onVisibility);\n window.removeEventListener(\"pagehide\", flush);\n if (interval !== null) window.clearInterval(interval);\n } catch {\n /* swallow */\n }\n flush();\n },\n enqueue(signal) {\n queue.push(signal);\n if (queue.length >= FLUSH_BATCH) flush();\n },\n flush,\n setIdentity(next) {\n identity = next;\n },\n };\n}\n","// Trigger + fatigue logic (FR-4, NFR-2) — the make-or-break craft surface.\n//\n// Kept PURE (no DOM) so it unit-tests cleanly under `node --test` and so the\n// heuristics can be tuned against real traffic later without touching the capture\n// wiring. Detection quality is the primary failure mode (false positives that\n// pester users), so the defaults are deliberately conservative.\n\nimport type { TrailEvent } from \"./types\";\n\nexport const RAGE_CLICK_COUNT = 3; // clicks…\nexport const RAGE_WINDOW_MS = 1_000; // …within this window form a rage cluster\nexport const FRICTION_RETRY_COUNT = 3; // repeated identical actions = retry frustration\nexport const FRICTION_WINDOW_MS = 8_000; // how far back a friction scan looks\n\nexport type FrictionKind = \"error\" | \"rage\" | \"dead_end\" | \"retry\";\n\n/**\n * Scan the recent trail for a friction moment. Returns the strongest kind found,\n * or null. Order = severity: a real error beats a rage cluster beats a dead-end\n * beats repeated retries.\n */\nexport function detectFriction(\n trail: TrailEvent[],\n now: number,\n windowMs = FRICTION_WINDOW_MS,\n): FrictionKind | null {\n const recent = trail.filter((e) => now - e.t <= windowMs);\n\n if (recent.some((e) => e.type === \"error\" || e.type === \"request_error\")) return \"error\";\n\n const clicks = recent.filter((e) => e.type === \"click\" || e.type === \"rage_click\");\n for (let i = 0; i < clicks.length; i++) {\n const burst = clicks.filter(\n (e) => e.t >= clicks[i].t && e.t - clicks[i].t <= RAGE_WINDOW_MS,\n );\n if (burst.length >= RAGE_CLICK_COUNT) return \"rage\";\n }\n\n if (recent.some((e) => e.type === \"dead_click\")) return \"dead_end\";\n\n const byLabel = new Map<string, number>();\n for (const e of clicks) {\n if (!e.label) continue;\n const n = (byLabel.get(e.label) ?? 0) + 1;\n byLabel.set(e.label, n);\n if (n >= FRICTION_RETRY_COUNT) return \"retry\";\n }\n\n return null;\n}\n\n// --- Fatigue caps (NFR-2): never pester. Conservative by default. ------------\n\nexport type FatigueCaps = {\n maxPromptsPerSession: number;\n cooldownMs: number; // min gap between prompts\n};\n\nexport const DEFAULT_CAPS: FatigueCaps = {\n maxPromptsPerSession: 1,\n cooldownMs: 5 * 60_000,\n};\n\nexport type FatigueState = {\n promptsShown: number;\n lastPromptAt: number | null;\n};\n\n/** May we show a prompt right now, given how many we've shown and when? */\nexport function canPrompt(\n state: FatigueState,\n now: number,\n caps: FatigueCaps = DEFAULT_CAPS,\n): boolean {\n if (state.promptsShown >= caps.maxPromptsPerSession) return false;\n if (state.lastPromptAt !== null && now - state.lastPromptAt < caps.cooldownMs) return false;\n return true;\n}\n","// Intervention serve/respond (Wave 0005 slice B — the client half). The two-way\n// SDK: besides emitting Signals, the SDK asks \"is there anything to show this user\n// here?\" (/api/sdk/serve) and posts the answer (/api/sdk/respond). Both halves are\n// wrapped — a serve/respond failure must never surface in the host app (NFR-3); the\n// worst case is simply no survey shown.\n//\n// Pure helpers (buildServeContext / normalizeServed / pickRespondentKey) are split\n// out so the contract is unit-testable without a DOM, like triggers.ts.\n\nimport type { Identity } from \"./types\";\nimport type { SurveyConfig } from \"./survey\";\nimport type { ProbeConfig } from \"./probe\";\n\nexport type ServeContext = { route?: string; account?: string; plan?: string };\n\nexport type ServedIntervention =\n | { id: string; type: \"survey\"; config: SurveyConfig }\n | { id: string; type: \"demand_probe\"; config: ProbeConfig };\n\nexport type InterventionAnswer = { choice?: string; text?: string };\n\n// Types the SDK can actually render. Mirrors the server's RENDERABLE_TYPES; if the\n// server ever serves an un-renderable type we drop it rather than show a blank.\nconst RENDERABLE = new Set([\"survey\", \"demand_probe\"]);\n\nfunction str(v: unknown, max: number): string | undefined {\n if (typeof v !== \"string\") return undefined;\n const t = v.trim();\n return t ? t.slice(0, max) : undefined;\n}\n\n/** The serve context from the current route + the identified account/plan. Only\n * defined fields are included (an absent field = unconstrained on the server). */\nexport function buildServeContext(\n route: string | undefined,\n identity: Identity | undefined,\n): ServeContext {\n const ctx: ServeContext = {};\n const r = str(route, 500);\n if (r) ctx.route = r;\n const account = str(identity?.account, 200);\n if (account) ctx.account = account;\n const plan = str(identity?.plan, 80);\n if (plan) ctx.plan = plan;\n return ctx;\n}\n\n/** Validate + normalise what /serve returned — never trust the wire blindly. Returns\n * a clean ServedIntervention or null (unknown shape / un-renderable type /\n * incomplete config). */\nexport function normalizeServed(raw: unknown): ServedIntervention | null {\n if (!raw || typeof raw !== \"object\") return null;\n const r = raw as Record<string, unknown>;\n const id = str(r.id, 64);\n const type = str(r.type, 40);\n if (!id || !type || !RENDERABLE.has(type)) return null;\n\n const cfg =\n r.config && typeof r.config === \"object\" ? (r.config as Record<string, unknown>) : {};\n\n if (type === \"demand_probe\") {\n // The honest painted door: label = the feature as the user would want it;\n // disclosure = the fixed \"this doesn't exist yet\" copy the server always\n // injects. If the disclosure is missing we DROP the probe rather than\n // render an undisclosed fake door — the client-side belt to the server's\n // braces. `slot` (optional inline placement) is re-validated as a bare\n // token so it can never smuggle a selector.\n const label = str(cfg.label, 200);\n const disclosure = str(cfg.disclosure, 300);\n if (!label || !disclosure) return null;\n const rawSlot = str(cfg.slot, 64);\n const slot = rawSlot && /^[a-z0-9][a-z0-9_-]*$/i.test(rawSlot) ? rawSlot : undefined;\n return { id, type, config: { label, disclosure, ...(slot ? { slot } : {}) } };\n }\n\n const question = str(cfg.question, 500);\n if (!question) return null;\n\n const options = Array.isArray(cfg.options)\n ? (cfg.options as unknown[])\n .map((o) => str(o, 200))\n .filter((o): o is string => !!o)\n .slice(0, 6)\n : undefined;\n\n const config: SurveyConfig = {\n question,\n ...(options && options.length ? { options } : {}),\n allow_text: cfg.allow_text === true,\n };\n return { id, type: \"survey\", config };\n}\n\n/** Stable id for serve-time de-dup (so a tapped survey doesn't reappear). The\n * identified user wins; else a persisted anon id; else the per-session ref. Pure\n * so it's testable — the localStorage read lives in getRespondentKey. */\nexport function pickRespondentKey(\n userId: string | undefined,\n persisted: string | null,\n sessionRef: string,\n): string {\n const uid = str(userId, 200);\n if (uid) return uid;\n const p = str(persisted, 200);\n if (p) return p;\n return sessionRef;\n}\n\nconst RK_STORAGE_KEY = \"sightspool_rk\";\n\n/** Resolve the respondent key, persisting an anonymous one in localStorage so\n * de-dup survives reloads. Falls back to the session ref if storage is blocked. */\nexport function getRespondentKey(\n identity: Identity | undefined,\n sessionRef: string,\n): string {\n const uid = str(identity?.userId, 200);\n if (uid) return uid;\n try {\n let v = localStorage.getItem(RK_STORAGE_KEY);\n if (!v) {\n v = \"anon-\" + Math.random().toString(36).slice(2) + Date.now().toString(36);\n localStorage.setItem(RK_STORAGE_KEY, v);\n }\n return pickRespondentKey(undefined, v, sessionRef);\n } catch {\n return sessionRef;\n }\n}\n\nfunction serveUrl(endpoint: string, path: string): string {\n return `${endpoint.replace(/\\/+$/, \"\")}/api/sdk/${path}`;\n}\n\n/** Ask the serve endpoint for an intervention to show, or null. Uses a text/plain\n * POST (CORS-safelisted → no preflight) and reads the JSON response (the serve\n * route sets Access-Control-Allow-Origin). */\nexport async function fetchIntervention(opts: {\n endpoint: string;\n key: string;\n ctx: ServeContext;\n respondentKey: string;\n debug?: boolean;\n}): Promise<ServedIntervention | null> {\n try {\n if (typeof fetch !== \"function\") return null;\n const res = await fetch(serveUrl(opts.endpoint, \"serve\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"text/plain\" },\n body: JSON.stringify({\n key: opts.key,\n context: opts.ctx,\n respondent_key: opts.respondentKey,\n }),\n mode: \"cors\",\n credentials: \"omit\",\n });\n if (!res.ok) return null;\n const data = (await res.json()) as { intervention?: unknown };\n const served = normalizeServed(data?.intervention);\n if (opts.debug) console.debug(\"[sightspool] serve\", served?.id ?? \"(none)\");\n return served;\n } catch {\n return null;\n }\n}\n\n/** Post a user's answer. Fire-and-forget (sendBeacon, fetch+keepalive fallback) —\n * the response is a 204 we don't need to read. */\nexport function submitResponse(opts: {\n endpoint: string;\n key: string;\n interventionId: string;\n response: InterventionAnswer;\n respondentKey: string;\n}): void {\n try {\n const url = serveUrl(opts.endpoint, \"respond\");\n const json = JSON.stringify({\n key: opts.key,\n intervention_id: opts.interventionId,\n response: opts.response,\n respondent_key: opts.respondentKey,\n });\n if (typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\") {\n const blob = new Blob([json], { type: \"text/plain\" });\n if (navigator.sendBeacon(url, blob)) return;\n }\n if (typeof fetch === \"function\") {\n void fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"text/plain\" },\n body: json,\n keepalive: true,\n mode: \"cors\",\n credentials: \"omit\",\n }).catch(() => {\n /* swallow */\n });\n }\n } catch {\n /* swallow */\n }\n}\n","// Environment guards. Kept pure (a hostname string in, a boolean out) so the\n// no-op-on-localhost decision is unit-testable without a DOM.\n\nconst LOCAL_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"0.0.0.0\", \"::1\", \"\"]);\n\n/**\n * Is this a local-development hostname? Capture is suppressed on these by default so\n * a client's `npm run dev` traffic never pollutes their Sightspool workspace (override\n * with `captureOnLocalhost: true`). Covers the common dev hosts + the `.local` /\n * `.localhost` TLDs (e.g. `myapp.local`, `app.localhost`).\n */\nexport function isLocalhost(hostname: string | null | undefined): boolean {\n const h = (hostname ?? \"\").trim().toLowerCase();\n if (LOCAL_HOSTS.has(h)) return true;\n return h.endsWith(\".local\") || h.endsWith(\".localhost\");\n}\n","// @sightspool/sdk — the in-product capture runtime (public surface).\n//\n// Ties the pieces together: passive capture + intent harvest feed a conservative\n// trigger engine; on a friction moment or a session boundary we (fatigue\n// permitting) show the one-tap prompt, then emit one Signal via batched sendBeacon.\n// Every public method is wrapped — the SDK must never throw into the host (NFR-3).\n\nimport type { SightspoolConfig, Identity, CapturedSignal } from \"./types\";\nimport { createCapture, type CaptureHandle } from \"./capture\";\nimport { createHarvest, type HarvestHandle } from \"./harvest\";\nimport { createEgress, type EgressHandle } from \"./egress\";\nimport {\n detectFriction,\n canPrompt,\n DEFAULT_CAPS,\n type FatigueState,\n} from \"./triggers\";\nimport {\n buildServeContext,\n fetchIntervention,\n submitResponse,\n getRespondentKey,\n} from \"./intervention\";\nimport { isLocalhost } from \"./env\";\n\nexport type { SightspoolConfig, Identity } from \"./types\";\n\nconst DEFAULT_ENDPOINT = \"https://www.sightspool.com\";\nconst FRICTION_EMIT_COOLDOWN_MS = 30_000;\nconst EVENT_DEBOUNCE_MS = 600;\n// Let the page settle before the first serve check (don't race the initial render).\nconst SERVE_SETTLE_MS = 2_500;\n// Conservative client cap; the server also de-dups (answered) + targets + bounds by\n// response_target, so this just stops a dismissed survey re-nagging within a session.\nconst MAX_INTERVENTIONS_PER_SESSION = 1;\n\ntype Controller = {\n config: Required<Pick<SightspoolConfig, \"key\" | \"endpoint\" | \"boundaryAsk\" | \"debug\">> &\n SightspoolConfig;\n capture: CaptureHandle;\n harvest: HarvestHandle;\n egress: EgressHandle;\n identity: Identity;\n sessionRef: string;\n fatigue: FatigueState;\n lastFrictionEmitAt: number;\n eventTimer: number | null;\n running: boolean;\n /** Environmental kill-switch: on localhost without `captureOnLocalhost`, never start. */\n suppressed: boolean;\n // --- interventions (slice B serve loop) ---\n interventionsEnabled: boolean;\n lastServeRoute: string | null; // re-check serve when the route changes\n surveyOnScreen: boolean;\n interventionsShown: number;\n};\n\nfunction currentHostname(): string {\n try {\n return typeof location !== \"undefined\" ? location.hostname : \"\";\n } catch {\n return \"\";\n }\n}\n\nlet ctrl: Controller | null = null;\n\nfunction uuid(): string {\n try {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n } catch {\n /* fall through */\n }\n return \"s-\" + Math.random().toString(36).slice(2) + Date.now().toString(36);\n}\n\n// Locally-derived candidate goals for State B (FR-5). v1 leans on harvested intent\n// (a recent search) + the page label; server-LLM enrichment is a follow-up.\nfunction deriveCandidates(c: Controller): string[] {\n const out: string[] = [];\n const hint = c.harvest.lastIntentHint();\n if (hint) out.push(`Searching for “${hint}”`);\n const label = c.capture.label();\n if (label) out.push(`Something on “${label.slice(0, 40)}”`);\n return out;\n}\n\nfunction buildSignal(\n c: Controller,\n trigger: \"boundary\" | \"friction\",\n extra: Partial<CapturedSignal> = {},\n): CapturedSignal {\n const err = c.capture.error();\n return {\n captured_at: new Date().toISOString(),\n route: c.capture.route(),\n client_label: c.capture.label(),\n trail: c.capture.trail(),\n session_ref: c.sessionRef,\n trigger,\n intent_hint: c.harvest.lastIntentHint(),\n error: err,\n outcome: err || trigger === \"friction\" ? \"failed\" : \"unknown\",\n ...extra,\n };\n}\n\nasync function maybePrompt(c: Controller, trigger: \"boundary\" | \"friction\") {\n const now = Date.now();\n if (canPrompt(c.fatigue, now, DEFAULT_CAPS)) {\n c.fatigue.promptsShown += 1;\n c.fatigue.lastPromptAt = now;\n try {\n const { showPrompt } = await import(\"./prompt\");\n const result = await showPrompt({ candidates: deriveCandidates(c) });\n c.egress.enqueue(\n buildSignal(c, trigger, {\n answer: result.answer,\n verbatim: result.verbatim,\n intent_hint: result.intent ?? c.harvest.lastIntentHint(),\n outcome: result.answer === \"yes\" ? \"achieved\" : \"failed\",\n }),\n );\n } catch {\n // Prompt failed to load/show — still emit the passive Signal (FR-7).\n c.egress.enqueue(buildSignal(c, trigger));\n }\n } else {\n // Fatigued: keep the silent-capture property — emit without asking (FR-7).\n c.egress.enqueue(buildSignal(c, trigger));\n }\n}\n\n// Ask the serve endpoint whether there's a human-approved survey to show this user\n// here, and if so render it + post the answer. Server-gated (targeting, approval,\n// de-dup, response_target); the client guards are just \"don't pester\": one on\n// screen at a time, a per-session cap, and the shared prompt cooldown so a survey\n// and the passive ask never stack back-to-back.\nasync function maybeServeIntervention(c: Controller) {\n if (!c.running || !c.interventionsEnabled || c.suppressed) return;\n if (c.surveyOnScreen) return;\n if (c.interventionsShown >= MAX_INTERVENTIONS_PER_SESSION) return;\n const now = Date.now();\n if (c.fatigue.lastPromptAt !== null && now - c.fatigue.lastPromptAt < DEFAULT_CAPS.cooldownMs)\n return;\n\n const respondentKey = getRespondentKey(c.identity, c.sessionRef);\n const served = await fetchIntervention({\n endpoint: c.config.endpoint,\n key: c.config.key,\n ctx: buildServeContext(c.capture.route(), c.identity),\n respondentKey,\n debug: c.config.debug,\n });\n if (!served || !c.running) return;\n\n const prevShown = c.interventionsShown;\n const prevPromptAt = c.fatigue.lastPromptAt;\n c.surveyOnScreen = true;\n c.interventionsShown += 1;\n c.fatigue.lastPromptAt = Date.now(); // share the cooldown with the passive prompt\n try {\n if (served.type === \"demand_probe\") {\n // The honest painted door: a vote is recorded as choice \"vote\"; the\n // widget always shows the server's fixed disclosure after the click.\n const { showProbe } = await import(\"./probe\");\n const result = await showProbe(served.config);\n if (!result.mounted) {\n // A slot probe whose anchor isn't on this page rendered NOTHING —\n // give the session its fatigue budget back so a real prompt can\n // still show later (and the probe can retry on another route).\n c.interventionsShown = prevShown;\n c.fatigue.lastPromptAt = prevPromptAt;\n } else if (result.voted) {\n submitResponse({\n endpoint: c.config.endpoint,\n key: c.config.key,\n interventionId: served.id,\n response: { choice: \"vote\" },\n respondentKey,\n });\n }\n } else {\n const { showSurvey } = await import(\"./survey\");\n const result = await showSurvey(served.config);\n if (!result.dismissed && (result.choice || result.text)) {\n submitResponse({\n endpoint: c.config.endpoint,\n key: c.config.key,\n interventionId: served.id,\n response: { choice: result.choice, text: result.text },\n respondentKey,\n });\n }\n }\n } catch {\n /* swallow — a render/import failure must not surface in the host */\n } finally {\n c.surveyOnScreen = false;\n }\n}\n\nfunction onCaptureEvent() {\n const c = ctrl;\n if (!c || !c.running) return;\n\n // Re-check for a servable intervention when the route changes (SPA navigation).\n try {\n const route = c.capture.route();\n if (route && route !== c.lastServeRoute) {\n c.lastServeRoute = route;\n void maybeServeIntervention(c);\n }\n } catch {\n /* swallow */\n }\n\n if (c.eventTimer !== null) return; // debounce a burst of events into one check\n c.eventTimer = (typeof window !== \"undefined\" ? window.setTimeout : setTimeout)(() => {\n c.eventTimer = null;\n try {\n const now = Date.now();\n if (now - c.lastFrictionEmitAt < FRICTION_EMIT_COOLDOWN_MS) return;\n const kind = detectFriction(c.capture.trail(), now);\n if (!kind) return;\n c.lastFrictionEmitAt = now;\n void maybePrompt(c, \"friction\");\n } catch {\n /* swallow */\n }\n }, EVENT_DEBOUNCE_MS) as unknown as number;\n}\n\nfunction onExitIntent(ev: MouseEvent) {\n const c = ctrl;\n if (!c || !c.running || !c.config.boundaryAsk) return;\n try {\n if (ev.clientY <= 0) void maybePrompt(c, \"boundary\");\n } catch {\n /* swallow */\n }\n}\n\nfunction startRuntime(c: Controller) {\n if (c.running) return;\n if (c.suppressed) {\n if (c.config.debug)\n console.debug(\n \"[sightspool] capture suppressed on localhost (set captureOnLocalhost:true to override)\",\n );\n return;\n }\n c.running = true;\n c.capture.start();\n c.harvest.start();\n c.egress.start();\n c.capture.onEvent(onCaptureEvent);\n try {\n document.addEventListener(\"mouseout\", onExitIntent);\n } catch {\n /* swallow */\n }\n // First serve check once the page has settled (route-change checks happen in\n // onCaptureEvent thereafter).\n if (c.interventionsEnabled) {\n c.lastServeRoute = (() => {\n try {\n return c.capture.route();\n } catch {\n return null;\n }\n })();\n (typeof window !== \"undefined\" ? window.setTimeout : setTimeout)(() => {\n void maybeServeIntervention(c);\n }, SERVE_SETTLE_MS);\n }\n if (c.config.debug) console.debug(\"[sightspool] started\", c.sessionRef);\n}\n\n// --- public API --------------------------------------------------------------\n\nexport function init(config: SightspoolConfig): void {\n try {\n if (!config || !config.key) {\n console.warn(\"[sightspool] init: a `key` is required\");\n return;\n }\n if (ctrl) return; // already initialised\n const endpoint = config.endpoint || DEFAULT_ENDPOINT;\n const privacyOpts = { redact: config.redact, block: config.block };\n const capture = createCapture({ debug: !!config.debug, ...privacyOpts });\n const harvest = createHarvest(capture, { debug: !!config.debug, ...privacyOpts });\n const egress = createEgress({ key: config.key, endpoint, debug: !!config.debug });\n ctrl = {\n config: {\n ...config,\n key: config.key,\n endpoint,\n boundaryAsk: config.boundaryAsk !== false,\n debug: !!config.debug,\n },\n capture,\n harvest,\n egress,\n identity: {},\n sessionRef: uuid(),\n fatigue: { promptsShown: 0, lastPromptAt: null },\n lastFrictionEmitAt: 0,\n eventTimer: null,\n running: false,\n suppressed: isLocalhost(currentHostname()) && config.captureOnLocalhost !== true,\n interventionsEnabled: config.interventions !== false,\n lastServeRoute: null,\n surveyOnScreen: false,\n interventionsShown: 0,\n };\n if (config.consent !== false) startRuntime(ctrl);\n } catch (err) {\n // init itself must never throw into the host.\n try {\n console.warn(\"[sightspool] init failed\", err);\n } catch {\n /* swallow */\n }\n }\n}\n\nexport function identify(userId: string, traits?: { account?: string; plan?: string }): void {\n try {\n if (!ctrl) return;\n ctrl.identity = { userId, account: traits?.account, plan: traits?.plan };\n ctrl.egress.setIdentity(ctrl.identity);\n } catch {\n /* swallow */\n }\n}\n\n/** Begin capture if init was called with { consent: false }. */\nexport function start(): void {\n try {\n if (ctrl) startRuntime(ctrl);\n } catch {\n /* swallow */\n }\n}\n\n/**\n * Runtime consent gate (a clean toggle over start()/stop()) — wire it to your cookie\n * banner: `Sightspool.consent(true)` resumes capture, `Sightspool.consent(false)`\n * pauses and flushes. Pairs with init `{ consent: false }` to stay dark until granted.\n */\nexport function consent(granted: boolean): void {\n try {\n if (!ctrl) return;\n if (granted) startRuntime(ctrl);\n else stop();\n } catch {\n /* swallow */\n }\n}\n\n/** Pause capture and flush whatever's queued. */\nexport function stop(): void {\n try {\n if (!ctrl) return;\n ctrl.running = false;\n ctrl.capture.stop();\n ctrl.harvest.stop();\n ctrl.egress.stop();\n try {\n document.removeEventListener(\"mouseout\", onExitIntent);\n } catch {\n /* swallow */\n }\n } catch {\n /* swallow */\n }\n}\n\nconst api = { init, identify, start, stop, consent };\nexport default api;\n\n// --- script-tag auto-init ----------------------------------------------------\n// The standalone <script data-sightspool-key=\"pk_…\"> install auto-boots from its\n// own tag's data attributes. (No-op for the ESM build: module scripts have no\n// document.currentScript, so bundler consumers always call init() themselves.)\ntry {\n if (typeof document !== \"undefined\") {\n // currentScript is null for async/defer/dynamically-injected scripts (e.g.\n // Next's <Script> component), so fall back to finding our tag by attribute.\n const el =\n (document.currentScript as HTMLScriptElement | null) ??\n document.querySelector<HTMLScriptElement>(\"script[data-sightspool-key]\");\n const key = el?.getAttribute(\"data-sightspool-key\");\n if (key) {\n // Default the ingest endpoint to where the bundle was served from — the app\n // serves /sdk.global.js, so a same-origin script install needs only the key.\n // An explicit data-sightspool-endpoint still wins (e.g. a CDN-hosted bundle).\n let endpoint = el?.getAttribute(\"data-sightspool-endpoint\") || undefined;\n if (!endpoint && el?.src) {\n try {\n endpoint = new URL(el.src).origin;\n } catch {\n /* keep the built-in default */\n }\n }\n // Comma-separated CSS selectors → string[] (the script-tag equivalent of the\n // init() arrays; bundler users pass arrays directly).\n const list = (attr: string): string[] | undefined => {\n const raw = el?.getAttribute(attr);\n if (!raw) return undefined;\n const out = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n return out.length ? out : undefined;\n };\n init({\n key,\n endpoint,\n redact: list(\"data-sightspool-redact\"),\n block: list(\"data-sightspool-block\"),\n captureOnLocalhost: el?.hasAttribute(\"data-sightspool-capture-localhost\") || undefined,\n interventions: el?.hasAttribute(\"data-sightspool-no-interventions\") ? false : undefined,\n debug: el?.hasAttribute(\"data-sightspool-debug\") || undefined,\n });\n }\n }\n} catch {\n /* swallow */\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/research.ts","../src/index.ts","../src/browser.ts"],"names":["slot","host","current","_a","eligible","r","remove","invalidate","status","value","check","generation","request","timeout","response","result","button","hash","e","init","config","browser","url","previous","destroy","device","bytes","identify","userId","identified","pause","resume","getStatus","_b","src_default","browser_default","script","key","audience"],"mappings":"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","file":"sdk.global.js","sourcesContent":["export type SightspoolConfig = {\n /** Public workspace widget key from Go live (UUID, not an old pk_live key). */\n key: string;\n /** Match the approved research audience. No default that widens recruitment. */\n audience: \"all_visitors\" | \"signed_in\";\n /** Sightspool origin. Defaults to the hosted application. */\n endpoint?: string;\n};\nexport type ResearchStatus =\n | \"not_initialized\" | \"signed_out\" | \"paused\" | \"checking\"\n | \"unavailable\" | \"available\" | \"error\";\n\ntype Runtime = {\n key: string; endpoint: string; audience: SightspoolConfig[\"audience\"]; identified: boolean; paused: boolean;\n disposed: boolean; generation: number; device: string; offer: string | null;\n button: HTMLButtonElement | null; popup: Window | null;\n pending: AbortController | null; timer: number; visibility: () => void;\n status: ResearchStatus;\n};\nconst slot = Symbol.for(\"sightspool.research.runtime.v1\");\ntype Host = Window & { [slot]?: Runtime };\nconst host = (): Host | null => typeof window === \"undefined\" ? null : window as Host;\nconst current = () => host()?.[slot];\nconst eligible = (r: Runtime) => r.audience === \"all_visitors\" || r.identified;\n\nfunction remove(r: Runtime) {\n r.button?.remove(); r.button = null; r.offer = null;\n}\nfunction invalidate(r: Runtime) {\n r.generation += 1; r.pending?.abort(); r.pending = null; remove(r);\n}\nfunction status(r: Runtime, value: ResearchStatus) { r.status = value; }\n\nasync function check(r: Runtime) {\n if (r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== \"visible\") return;\n const generation = r.generation;\n const request = new AbortController();\n r.pending = request;\n const timeout = window.setTimeout(() => request.abort(), 10_000);\n if (!r.button) status(r, \"checking\");\n try {\n const response = await fetch(r.endpoint + \"/widget-offer\", {\n method: \"POST\", credentials: \"omit\", cache: \"no-store\", referrerPolicy: \"no-referrer\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ operation: \"offer\", key: r.key, device: r.device }),\n signal: request.signal,\n });\n if (!response.ok) throw Error(\"offer unavailable\");\n const result = await response.json();\n if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;\n if (result.available !== true || typeof result.offer !== \"string\" || !result.offer) {\n remove(r); status(r, \"unavailable\"); return;\n }\n r.offer = result.offer;\n status(r, \"available\");\n if (r.button) return;\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Talk to the founder · 5 min\";\n button.setAttribute(\"aria-label\", \"Sightspool: join a five-minute user interview\");\n button.style.cssText = \"position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)\";\n button.onclick = () => {\n try {\n if (r.disposed || r.paused || !eligible(r) || !r.offer) return;\n if (r.popup && !r.popup.closed) { r.popup.focus(); return; }\n const hash = new URLSearchParams({ offer: r.offer, device: r.device });\n r.popup = window.open(r.endpoint + \"/interview-widget#\" + hash, \"sightspool-interview\", \"popup,width=520,height=760\");\n } catch { /* Host pages remain usable if popups are blocked. */ }\n };\n r.button = button;\n document.body.appendChild(button);\n } catch {\n if (!r.disposed && generation === r.generation) { remove(r); status(r, \"error\"); }\n } finally {\n window.clearTimeout(timeout);\n if (r.pending === request) r.pending = null;\n }\n}\n\n/** Start research for the chosen audience. Signed-in-only waits for identify(). */\nexport function init(config: SightspoolConfig): void {\n try {\n const browser = host();\n if (!browser || !config || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(config.key)) return;\n if (config.audience !== \"all_visitors\" && config.audience !== \"signed_in\") return;\n const url = new URL(config.endpoint || \"https://www.sightspool.com\");\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname))) return;\n if (url.username || url.password) return;\n const previous = current();\n if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;\n if (previous) destroy();\n let device = \"\";\n try { device = sessionStorage.getItem(\"sightspool-widget-device:\" + config.key) || \"\"; } catch {}\n if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n device = \"ss_fcd_\" + btoa(String.fromCharCode(...bytes)).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n try { sessionStorage.setItem(\"sightspool-widget-device:\" + config.key, device); } catch {}\n }\n const r: Runtime = {\n key: config.key, endpoint: url.origin, audience: config.audience, identified: false, paused: false,\n disposed: false, generation: 0, device, offer: null, button: null,\n popup: null, pending: null, timer: 0, visibility: () => {}, status: \"signed_out\",\n };\n browser[slot] = r;\n r.visibility = () => {\n try {\n if (document.visibilityState === \"visible\") void check(r);\n else { invalidate(r); status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\"); }\n } catch {}\n };\n document.addEventListener(\"visibilitychange\", r.visibility);\n r.timer = window.setInterval(() => { void check(r); }, 15_000);\n if (eligible(r)) void check(r);\n } catch { /* Never throw into the host application. */ }\n}\n\n/** Only the presence of an ID is retained. The ID itself is never stored or sent. */\nexport function identify(userId: string | null | undefined): void {\n try {\n const r = current();\n if (!r) return;\n const identified = typeof userId === \"string\" && userId.trim().length > 0;\n if (!identified && !r.identified) { if (!r.paused && eligible(r)) void check(r); return; }\n invalidate(r);\n r.identified = identified;\n status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\");\n if (eligible(r) && !r.paused) void check(r);\n } catch {}\n}\nexport function pause(): void {\n try { const r = current(); if (r) { r.paused = true; invalidate(r); status(r, \"paused\"); } } catch {}\n}\nexport function resume(): void {\n try { const r = current(); if (r) { r.paused = false; if (!eligible(r)) status(r, \"signed_out\"); void check(r); } } catch {}\n}\n/** Stop recruitment and remove listeners/UI. Does not end an already opened interview. */\nexport function destroy(): void {\n try {\n const r = current();\n if (!r) return;\n r.disposed = true; invalidate(r);\n window.clearInterval(r.timer);\n document.removeEventListener(\"visibilitychange\", r.visibility);\n delete host()![slot];\n } catch {}\n}\nexport function getStatus(): ResearchStatus {\n try { return current()?.status ?? \"not_initialized\"; } catch { return \"error\"; }\n}\n","// Research is the public SDK. The former capture engine is parked.\nexport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport type { SightspoolConfig, ResearchStatus } from \"./research\";\nimport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport default { init, identify, pause, resume, destroy, getStatus };\n","import api from \"./index\";\nexport * from \"./index\";\nexport default api;\n\ntry {\n const script = document.currentScript as HTMLScriptElement | null;\n const key = script?.dataset.sightspoolKey || script?.dataset.key;\n const audience = script?.dataset.sightspoolAudience;\n if (key && (audience === \"all_visitors\" || audience === \"signed_in\")) {\n api.init({ key, audience, endpoint: script?.dataset.sightspoolEndpoint || new URL(script!.src).origin });\n if (script?.dataset.userId) api.identify(script.dataset.userId);\n }\n // The old research-widget URL is an alias of this bundle, not another runtime.\n (window as Window & { SightspoolResearch?: typeof api }).SightspoolResearch = api;\n Promise.resolve().then(() => window.dispatchEvent(new Event(\"sightspool:ready\")));\n} catch { /* Browser auto-init must not interrupt the client app. */ }\n"]}
|
package/dist/source.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": {
|
|
3
|
+
"src/index.ts": "// Research is the public SDK. The former capture engine is parked.\nexport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport type { SightspoolConfig, ResearchStatus } from \"./research\";\nimport { init, identify, pause, resume, destroy, getStatus } from \"./research\";\nexport default { init, identify, pause, resume, destroy, getStatus };\n",
|
|
4
|
+
"src/browser.ts": "import api from \"./index\";\nexport * from \"./index\";\nexport default api;\n\ntry {\n const script = document.currentScript as HTMLScriptElement | null;\n const key = script?.dataset.sightspoolKey || script?.dataset.key;\n const audience = script?.dataset.sightspoolAudience;\n if (key && (audience === \"all_visitors\" || audience === \"signed_in\")) {\n api.init({ key, audience, endpoint: script?.dataset.sightspoolEndpoint || new URL(script!.src).origin });\n if (script?.dataset.userId) api.identify(script.dataset.userId);\n }\n // The old research-widget URL is an alias of this bundle, not another runtime.\n (window as Window & { SightspoolResearch?: typeof api }).SightspoolResearch = api;\n Promise.resolve().then(() => window.dispatchEvent(new Event(\"sightspool:ready\")));\n} catch { /* Browser auto-init must not interrupt the client app. */ }\n",
|
|
5
|
+
"src/research.ts": "export type SightspoolConfig = {\n /** Public workspace widget key from Go live (UUID, not an old pk_live key). */\n key: string;\n /** Match the approved research audience. No default that widens recruitment. */\n audience: \"all_visitors\" | \"signed_in\";\n /** Sightspool origin. Defaults to the hosted application. */\n endpoint?: string;\n};\nexport type ResearchStatus =\n | \"not_initialized\" | \"signed_out\" | \"paused\" | \"checking\"\n | \"unavailable\" | \"available\" | \"error\";\n\ntype Runtime = {\n key: string; endpoint: string; audience: SightspoolConfig[\"audience\"]; identified: boolean; paused: boolean;\n disposed: boolean; generation: number; device: string; offer: string | null;\n button: HTMLButtonElement | null; popup: Window | null;\n pending: AbortController | null; timer: number; visibility: () => void;\n status: ResearchStatus;\n};\nconst slot = Symbol.for(\"sightspool.research.runtime.v1\");\ntype Host = Window & { [slot]?: Runtime };\nconst host = (): Host | null => typeof window === \"undefined\" ? null : window as Host;\nconst current = () => host()?.[slot];\nconst eligible = (r: Runtime) => r.audience === \"all_visitors\" || r.identified;\n\nfunction remove(r: Runtime) {\n r.button?.remove(); r.button = null; r.offer = null;\n}\nfunction invalidate(r: Runtime) {\n r.generation += 1; r.pending?.abort(); r.pending = null; remove(r);\n}\nfunction status(r: Runtime, value: ResearchStatus) { r.status = value; }\n\nasync function check(r: Runtime) {\n if (r.disposed || r.paused || !eligible(r) || r.pending || document.visibilityState !== \"visible\") return;\n const generation = r.generation;\n const request = new AbortController();\n r.pending = request;\n const timeout = window.setTimeout(() => request.abort(), 10_000);\n if (!r.button) status(r, \"checking\");\n try {\n const response = await fetch(r.endpoint + \"/widget-offer\", {\n method: \"POST\", credentials: \"omit\", cache: \"no-store\", referrerPolicy: \"no-referrer\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ operation: \"offer\", key: r.key, device: r.device }),\n signal: request.signal,\n });\n if (!response.ok) throw Error(\"offer unavailable\");\n const result = await response.json();\n if (r.disposed || generation !== r.generation || r.paused || !eligible(r)) return;\n if (result.available !== true || typeof result.offer !== \"string\" || !result.offer) {\n remove(r); status(r, \"unavailable\"); return;\n }\n r.offer = result.offer;\n status(r, \"available\");\n if (r.button) return;\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Talk to the founder · 5 min\";\n button.setAttribute(\"aria-label\", \"Sightspool: join a five-minute user interview\");\n button.style.cssText = \"position:fixed;bottom:20px;right:20px;z-index:2147483000;padding:14px 18px;border:0;border-radius:16px;background:#171717;color:white;font:500 14px system-ui;box-shadow:0 8px 30px #0003;cursor:pointer;max-width:calc(100vw - 40px)\";\n button.onclick = () => {\n try {\n if (r.disposed || r.paused || !eligible(r) || !r.offer) return;\n if (r.popup && !r.popup.closed) { r.popup.focus(); return; }\n const hash = new URLSearchParams({ offer: r.offer, device: r.device });\n r.popup = window.open(r.endpoint + \"/interview-widget#\" + hash, \"sightspool-interview\", \"popup,width=520,height=760\");\n } catch { /* Host pages remain usable if popups are blocked. */ }\n };\n r.button = button;\n document.body.appendChild(button);\n } catch {\n if (!r.disposed && generation === r.generation) { remove(r); status(r, \"error\"); }\n } finally {\n window.clearTimeout(timeout);\n if (r.pending === request) r.pending = null;\n }\n}\n\n/** Start research for the chosen audience. Signed-in-only waits for identify(). */\nexport function init(config: SightspoolConfig): void {\n try {\n const browser = host();\n if (!browser || !config || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(config.key)) return;\n if (config.audience !== \"all_visitors\" && config.audience !== \"signed_in\") return;\n const url = new URL(config.endpoint || \"https://www.sightspool.com\");\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname))) return;\n if (url.username || url.password) return;\n const previous = current();\n if (previous && previous.key === config.key && previous.endpoint === url.origin && previous.audience === config.audience) return;\n if (previous) destroy();\n let device = \"\";\n try { device = sessionStorage.getItem(\"sightspool-widget-device:\" + config.key) || \"\"; } catch {}\n if (!/^ss_fcd_[A-Za-z0-9_-]{43}$/.test(device)) {\n const bytes = crypto.getRandomValues(new Uint8Array(32));\n device = \"ss_fcd_\" + btoa(String.fromCharCode(...bytes)).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n try { sessionStorage.setItem(\"sightspool-widget-device:\" + config.key, device); } catch {}\n }\n const r: Runtime = {\n key: config.key, endpoint: url.origin, audience: config.audience, identified: false, paused: false,\n disposed: false, generation: 0, device, offer: null, button: null,\n popup: null, pending: null, timer: 0, visibility: () => {}, status: \"signed_out\",\n };\n browser[slot] = r;\n r.visibility = () => {\n try {\n if (document.visibilityState === \"visible\") void check(r);\n else { invalidate(r); status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\"); }\n } catch {}\n };\n document.addEventListener(\"visibilitychange\", r.visibility);\n r.timer = window.setInterval(() => { void check(r); }, 15_000);\n if (eligible(r)) void check(r);\n } catch { /* Never throw into the host application. */ }\n}\n\n/** Only the presence of an ID is retained. The ID itself is never stored or sent. */\nexport function identify(userId: string | null | undefined): void {\n try {\n const r = current();\n if (!r) return;\n const identified = typeof userId === \"string\" && userId.trim().length > 0;\n if (!identified && !r.identified) { if (!r.paused && eligible(r)) void check(r); return; }\n invalidate(r);\n r.identified = identified;\n status(r, r.paused ? \"paused\" : eligible(r) ? \"unavailable\" : \"signed_out\");\n if (eligible(r) && !r.paused) void check(r);\n } catch {}\n}\nexport function pause(): void {\n try { const r = current(); if (r) { r.paused = true; invalidate(r); status(r, \"paused\"); } } catch {}\n}\nexport function resume(): void {\n try { const r = current(); if (r) { r.paused = false; if (!eligible(r)) status(r, \"signed_out\"); void check(r); } } catch {}\n}\n/** Stop recruitment and remove listeners/UI. Does not end an already opened interview. */\nexport function destroy(): void {\n try {\n const r = current();\n if (!r) return;\n r.disposed = true; invalidate(r);\n window.clearInterval(r.timer);\n document.removeEventListener(\"visibilitychange\", r.visibility);\n delete host()![slot];\n } catch {}\n}\nexport function getStatus(): ResearchStatus {\n try { return current()?.status ?? \"not_initialized\"; } catch { return \"error\"; }\n}\n",
|
|
6
|
+
"tsup.config.ts": "import { defineConfig } from \"tsup\";\n\n// npm (ESM/CJS/types) and the script-tag bundle share the research runtime.\n// Parked capture modules are intentionally absent from both dependency graphs.\nexport default defineConfig([\n {\n entry: { index: \"src/index.ts\" },\n format: [\"esm\", \"cjs\"],\n dts: true,\n sourcemap: true,\n clean: true,\n treeshake: true,\n minify: false,\n target: \"es2018\",\n },\n {\n entry: { sdk: \"src/browser.ts\" },\n format: [\"iife\"],\n globalName: \"Sightspool\",\n sourcemap: true,\n minify: true,\n treeshake: true,\n target: \"es2018\",\n },\n]);\n",
|
|
7
|
+
"package.json": "{\n \"name\": \"@sightspool/sdk\",\n \"version\": \"0.4.0\",\n \"description\": \"Sightspool research SDK \\u2014 invite website visitors and signed-in users into approved user research.\",\n \"type\": \"module\",\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"LICENSE\",\n \"NOTICE\",\n \"site\",\n \"SECURITY.md\",\n \"CHANGELOG.md\"\n ],\n \"sideEffects\": false,\n \"license\": \"Apache-2.0\",\n \"author\": \"Sightspool\",\n \"homepage\": \"https://www.sightspool.com/sdk\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/sightspool/sdk.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/sightspool/sdk/issues\"\n },\n \"keywords\": [\n \"sightspool\",\n \"user-research\",\n \"research\",\n \"interviews\",\n \"sdk\"\n ],\n \"engines\": {\n \"node\": \">=18\"\n },\n \"packageManager\": \"pnpm@9.15.0\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"build\": \"tsup && node scripts/build-release.mjs\",\n \"type-check\": \"tsc --noEmit\",\n \"test\": \"tsc --noEmit && node --test __tests__/*.test.ts\",\n \"prepublishOnly\": \"pnpm run build\",\n \"test:release\": \"node scripts/verify-release.mjs && node --test scripts/release.test.mjs\",\n \"build:site\": \"node scripts/stage-site.mjs\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.10.4\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.3\"\n }\n}\n",
|
|
8
|
+
"pnpm-lock.yaml": "lockfileVersion: '9.0'\n\nsettings:\n autoInstallPeers: true\n excludeLinksFromLockfile: false\n\nimporters:\n\n .:\n devDependencies:\n '@types/node':\n specifier: ^24.10.4\n version: 24.13.1\n tsup:\n specifier: ^8.5.0\n version: 8.5.1(typescript@5.9.3)\n typescript:\n specifier: ^5.9.3\n version: 5.9.3\n\n packages/react:\n devDependencies:\n '@sightspool/sdk':\n specifier: workspace:^\n version: link:../..\n '@types/react':\n specifier: ^19.0.0\n version: 19.2.17\n react:\n specifier: ^19.0.0\n version: 19.2.7\n tsup:\n specifier: ^8.5.0\n version: 8.5.1(typescript@5.9.3)\n typescript:\n specifier: ^5.9.3\n version: 5.9.3\n\npackages:\n\n '@esbuild/aix-ppc64@0.27.7':\n resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}\n engines: {node: '>=18'}\n cpu: [ppc64]\n os: [aix]\n\n '@esbuild/android-arm64@0.27.7':\n resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [android]\n\n '@esbuild/android-arm@0.27.7':\n resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}\n engines: {node: '>=18'}\n cpu: [arm]\n os: [android]\n\n '@esbuild/android-x64@0.27.7':\n resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [android]\n\n '@esbuild/darwin-arm64@0.27.7':\n resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [darwin]\n\n '@esbuild/darwin-x64@0.27.7':\n resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [darwin]\n\n '@esbuild/freebsd-arm64@0.27.7':\n resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [freebsd]\n\n '@esbuild/freebsd-x64@0.27.7':\n resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [freebsd]\n\n '@esbuild/linux-arm64@0.27.7':\n resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [linux]\n\n '@esbuild/linux-arm@0.27.7':\n resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}\n engines: {node: '>=18'}\n cpu: [arm]\n os: [linux]\n\n '@esbuild/linux-ia32@0.27.7':\n resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}\n engines: {node: '>=18'}\n cpu: [ia32]\n os: [linux]\n\n '@esbuild/linux-loong64@0.27.7':\n resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}\n engines: {node: '>=18'}\n cpu: [loong64]\n os: [linux]\n\n '@esbuild/linux-mips64el@0.27.7':\n resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}\n engines: {node: '>=18'}\n cpu: [mips64el]\n os: [linux]\n\n '@esbuild/linux-ppc64@0.27.7':\n resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}\n engines: {node: '>=18'}\n cpu: [ppc64]\n os: [linux]\n\n '@esbuild/linux-riscv64@0.27.7':\n resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}\n engines: {node: '>=18'}\n cpu: [riscv64]\n os: [linux]\n\n '@esbuild/linux-s390x@0.27.7':\n resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}\n engines: {node: '>=18'}\n cpu: [s390x]\n os: [linux]\n\n '@esbuild/linux-x64@0.27.7':\n resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [linux]\n\n '@esbuild/netbsd-arm64@0.27.7':\n resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [netbsd]\n\n '@esbuild/netbsd-x64@0.27.7':\n resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [netbsd]\n\n '@esbuild/openbsd-arm64@0.27.7':\n resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [openbsd]\n\n '@esbuild/openbsd-x64@0.27.7':\n resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [openbsd]\n\n '@esbuild/openharmony-arm64@0.27.7':\n resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [openharmony]\n\n '@esbuild/sunos-x64@0.27.7':\n resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [sunos]\n\n '@esbuild/win32-arm64@0.27.7':\n resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}\n engines: {node: '>=18'}\n cpu: [arm64]\n os: [win32]\n\n '@esbuild/win32-ia32@0.27.7':\n resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}\n engines: {node: '>=18'}\n cpu: [ia32]\n os: [win32]\n\n '@esbuild/win32-x64@0.27.7':\n resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}\n engines: {node: '>=18'}\n cpu: [x64]\n os: [win32]\n\n '@jridgewell/gen-mapping@0.3.13':\n resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}\n\n '@jridgewell/resolve-uri@3.1.2':\n resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}\n engines: {node: '>=6.0.0'}\n\n '@jridgewell/sourcemap-codec@1.5.5':\n resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}\n\n '@jridgewell/trace-mapping@0.3.31':\n resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}\n\n '@rollup/rollup-android-arm-eabi@4.61.1':\n resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==}\n cpu: [arm]\n os: [android]\n\n '@rollup/rollup-android-arm64@4.61.1':\n resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==}\n cpu: [arm64]\n os: [android]\n\n '@rollup/rollup-darwin-arm64@4.61.1':\n resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==}\n cpu: [arm64]\n os: [darwin]\n\n '@rollup/rollup-darwin-x64@4.61.1':\n resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==}\n cpu: [x64]\n os: [darwin]\n\n '@rollup/rollup-freebsd-arm64@4.61.1':\n resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==}\n cpu: [arm64]\n os: [freebsd]\n\n '@rollup/rollup-freebsd-x64@4.61.1':\n resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==}\n cpu: [x64]\n os: [freebsd]\n\n '@rollup/rollup-linux-arm-gnueabihf@4.61.1':\n resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==}\n cpu: [arm]\n os: [linux]\n\n '@rollup/rollup-linux-arm-musleabihf@4.61.1':\n resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==}\n cpu: [arm]\n os: [linux]\n\n '@rollup/rollup-linux-arm64-gnu@4.61.1':\n resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==}\n cpu: [arm64]\n os: [linux]\n\n '@rollup/rollup-linux-arm64-musl@4.61.1':\n resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==}\n cpu: [arm64]\n os: [linux]\n\n '@rollup/rollup-linux-loong64-gnu@4.61.1':\n resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==}\n cpu: [loong64]\n os: [linux]\n\n '@rollup/rollup-linux-loong64-musl@4.61.1':\n resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==}\n cpu: [loong64]\n os: [linux]\n\n '@rollup/rollup-linux-ppc64-gnu@4.61.1':\n resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==}\n cpu: [ppc64]\n os: [linux]\n\n '@rollup/rollup-linux-ppc64-musl@4.61.1':\n resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==}\n cpu: [ppc64]\n os: [linux]\n\n '@rollup/rollup-linux-riscv64-gnu@4.61.1':\n resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==}\n cpu: [riscv64]\n os: [linux]\n\n '@rollup/rollup-linux-riscv64-musl@4.61.1':\n resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==}\n cpu: [riscv64]\n os: [linux]\n\n '@rollup/rollup-linux-s390x-gnu@4.61.1':\n resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==}\n cpu: [s390x]\n os: [linux]\n\n '@rollup/rollup-linux-x64-gnu@4.61.1':\n resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==}\n cpu: [x64]\n os: [linux]\n\n '@rollup/rollup-linux-x64-musl@4.61.1':\n resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==}\n cpu: [x64]\n os: [linux]\n\n '@rollup/rollup-openbsd-x64@4.61.1':\n resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==}\n cpu: [x64]\n os: [openbsd]\n\n '@rollup/rollup-openharmony-arm64@4.61.1':\n resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==}\n cpu: [arm64]\n os: [openharmony]\n\n '@rollup/rollup-win32-arm64-msvc@4.61.1':\n resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==}\n cpu: [arm64]\n os: [win32]\n\n '@rollup/rollup-win32-ia32-msvc@4.61.1':\n resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==}\n cpu: [ia32]\n os: [win32]\n\n '@rollup/rollup-win32-x64-gnu@4.61.1':\n resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==}\n cpu: [x64]\n os: [win32]\n\n '@rollup/rollup-win32-x64-msvc@4.61.1':\n resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==}\n cpu: [x64]\n os: [win32]\n\n '@types/estree@1.0.9':\n resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}\n\n '@types/node@24.13.1':\n resolution: {integrity: sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==}\n\n '@types/react@19.2.17':\n resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==}\n\n acorn@8.16.0:\n resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}\n engines: {node: '>=0.4.0'}\n hasBin: true\n\n any-promise@1.3.0:\n resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}\n\n bundle-require@5.1.0:\n resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}\n engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}\n peerDependencies:\n esbuild: '>=0.18'\n\n cac@6.7.14:\n resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}\n engines: {node: '>=8'}\n\n chokidar@4.0.3:\n resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}\n engines: {node: '>= 14.16.0'}\n\n commander@4.1.1:\n resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}\n engines: {node: '>= 6'}\n\n confbox@0.1.8:\n resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}\n\n consola@3.4.2:\n resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}\n engines: {node: ^14.18.0 || >=16.10.0}\n\n csstype@3.2.3:\n resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}\n\n debug@4.4.3:\n resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}\n engines: {node: '>=6.0'}\n peerDependencies:\n supports-color: '*'\n peerDependenciesMeta:\n supports-color:\n optional: true\n\n esbuild@0.27.7:\n resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}\n engines: {node: '>=18'}\n hasBin: true\n\n fdir@6.5.0:\n resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}\n engines: {node: '>=12.0.0'}\n peerDependencies:\n picomatch: ^3 || ^4\n peerDependenciesMeta:\n picomatch:\n optional: true\n\n fix-dts-default-cjs-exports@1.0.1:\n resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}\n\n fsevents@2.3.3:\n resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}\n engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}\n os: [darwin]\n\n joycon@3.1.1:\n resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}\n engines: {node: '>=10'}\n\n lilconfig@3.1.3:\n resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}\n engines: {node: '>=14'}\n\n lines-and-columns@1.2.4:\n resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}\n\n load-tsconfig@0.2.5:\n resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}\n engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}\n\n magic-string@0.30.21:\n resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}\n\n mlly@1.8.2:\n resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==}\n\n ms@2.1.3:\n resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}\n\n mz@2.7.0:\n resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}\n\n object-assign@4.1.1:\n resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}\n engines: {node: '>=0.10.0'}\n\n pathe@2.0.3:\n resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}\n\n picocolors@1.1.1:\n resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}\n\n picomatch@4.0.4:\n resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}\n engines: {node: '>=12'}\n\n pirates@4.0.7:\n resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}\n engines: {node: '>= 6'}\n\n pkg-types@1.3.1:\n resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}\n\n postcss-load-config@6.0.1:\n resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}\n engines: {node: '>= 18'}\n peerDependencies:\n jiti: '>=1.21.0'\n postcss: '>=8.0.9'\n tsx: ^4.8.1\n yaml: ^2.4.2\n peerDependenciesMeta:\n jiti:\n optional: true\n postcss:\n optional: true\n tsx:\n optional: true\n yaml:\n optional: true\n\n react@19.2.7:\n resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==}\n engines: {node: '>=0.10.0'}\n\n readdirp@4.1.2:\n resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}\n engines: {node: '>= 14.18.0'}\n\n resolve-from@5.0.0:\n resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}\n engines: {node: '>=8'}\n\n rollup@4.61.1:\n resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==}\n engines: {node: '>=18.0.0', npm: '>=8.0.0'}\n hasBin: true\n\n source-map@0.7.6:\n resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}\n engines: {node: '>= 12'}\n\n sucrase@3.35.1:\n resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==}\n engines: {node: '>=16 || 14 >=14.17'}\n hasBin: true\n\n thenify-all@1.6.0:\n resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}\n engines: {node: '>=0.8'}\n\n thenify@3.3.1:\n resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}\n\n tinyexec@0.3.2:\n resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}\n\n tinyglobby@0.2.17:\n resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}\n engines: {node: '>=12.0.0'}\n\n tree-kill@1.2.2:\n resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}\n hasBin: true\n\n ts-interface-checker@0.1.13:\n resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}\n\n tsup@8.5.1:\n resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==}\n engines: {node: '>=18'}\n hasBin: true\n peerDependencies:\n '@microsoft/api-extractor': ^7.36.0\n '@swc/core': ^1\n postcss: ^8.4.12\n typescript: '>=4.5.0'\n peerDependenciesMeta:\n '@microsoft/api-extractor':\n optional: true\n '@swc/core':\n optional: true\n postcss:\n optional: true\n typescript:\n optional: true\n\n typescript@5.9.3:\n resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}\n engines: {node: '>=14.17'}\n hasBin: true\n\n ufo@1.6.4:\n resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}\n\n undici-types@7.18.2:\n resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}\n\nsnapshots:\n\n '@esbuild/aix-ppc64@0.27.7':\n optional: true\n\n '@esbuild/android-arm64@0.27.7':\n optional: true\n\n '@esbuild/android-arm@0.27.7':\n optional: true\n\n '@esbuild/android-x64@0.27.7':\n optional: true\n\n '@esbuild/darwin-arm64@0.27.7':\n optional: true\n\n '@esbuild/darwin-x64@0.27.7':\n optional: true\n\n '@esbuild/freebsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/freebsd-x64@0.27.7':\n optional: true\n\n '@esbuild/linux-arm64@0.27.7':\n optional: true\n\n '@esbuild/linux-arm@0.27.7':\n optional: true\n\n '@esbuild/linux-ia32@0.27.7':\n optional: true\n\n '@esbuild/linux-loong64@0.27.7':\n optional: true\n\n '@esbuild/linux-mips64el@0.27.7':\n optional: true\n\n '@esbuild/linux-ppc64@0.27.7':\n optional: true\n\n '@esbuild/linux-riscv64@0.27.7':\n optional: true\n\n '@esbuild/linux-s390x@0.27.7':\n optional: true\n\n '@esbuild/linux-x64@0.27.7':\n optional: true\n\n '@esbuild/netbsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/netbsd-x64@0.27.7':\n optional: true\n\n '@esbuild/openbsd-arm64@0.27.7':\n optional: true\n\n '@esbuild/openbsd-x64@0.27.7':\n optional: true\n\n '@esbuild/openharmony-arm64@0.27.7':\n optional: true\n\n '@esbuild/sunos-x64@0.27.7':\n optional: true\n\n '@esbuild/win32-arm64@0.27.7':\n optional: true\n\n '@esbuild/win32-ia32@0.27.7':\n optional: true\n\n '@esbuild/win32-x64@0.27.7':\n optional: true\n\n '@jridgewell/gen-mapping@0.3.13':\n dependencies:\n '@jridgewell/sourcemap-codec': 1.5.5\n '@jridgewell/trace-mapping': 0.3.31\n\n '@jridgewell/resolve-uri@3.1.2': {}\n\n '@jridgewell/sourcemap-codec@1.5.5': {}\n\n '@jridgewell/trace-mapping@0.3.31':\n dependencies:\n '@jridgewell/resolve-uri': 3.1.2\n '@jridgewell/sourcemap-codec': 1.5.5\n\n '@rollup/rollup-android-arm-eabi@4.61.1':\n optional: true\n\n '@rollup/rollup-android-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-darwin-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-darwin-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-freebsd-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-freebsd-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm-gnueabihf@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm-musleabihf@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-arm64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-loong64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-loong64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-ppc64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-ppc64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-riscv64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-riscv64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-s390x-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-x64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-linux-x64-musl@4.61.1':\n optional: true\n\n '@rollup/rollup-openbsd-x64@4.61.1':\n optional: true\n\n '@rollup/rollup-openharmony-arm64@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-arm64-msvc@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-ia32-msvc@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-x64-gnu@4.61.1':\n optional: true\n\n '@rollup/rollup-win32-x64-msvc@4.61.1':\n optional: true\n\n '@types/estree@1.0.9': {}\n\n '@types/node@24.13.1':\n dependencies:\n undici-types: 7.18.2\n\n '@types/react@19.2.17':\n dependencies:\n csstype: 3.2.3\n\n acorn@8.16.0: {}\n\n any-promise@1.3.0: {}\n\n bundle-require@5.1.0(esbuild@0.27.7):\n dependencies:\n esbuild: 0.27.7\n load-tsconfig: 0.2.5\n\n cac@6.7.14: {}\n\n chokidar@4.0.3:\n dependencies:\n readdirp: 4.1.2\n\n commander@4.1.1: {}\n\n confbox@0.1.8: {}\n\n consola@3.4.2: {}\n\n csstype@3.2.3: {}\n\n debug@4.4.3:\n dependencies:\n ms: 2.1.3\n\n esbuild@0.27.7:\n optionalDependencies:\n '@esbuild/aix-ppc64': 0.27.7\n '@esbuild/android-arm': 0.27.7\n '@esbuild/android-arm64': 0.27.7\n '@esbuild/android-x64': 0.27.7\n '@esbuild/darwin-arm64': 0.27.7\n '@esbuild/darwin-x64': 0.27.7\n '@esbuild/freebsd-arm64': 0.27.7\n '@esbuild/freebsd-x64': 0.27.7\n '@esbuild/linux-arm': 0.27.7\n '@esbuild/linux-arm64': 0.27.7\n '@esbuild/linux-ia32': 0.27.7\n '@esbuild/linux-loong64': 0.27.7\n '@esbuild/linux-mips64el': 0.27.7\n '@esbuild/linux-ppc64': 0.27.7\n '@esbuild/linux-riscv64': 0.27.7\n '@esbuild/linux-s390x': 0.27.7\n '@esbuild/linux-x64': 0.27.7\n '@esbuild/netbsd-arm64': 0.27.7\n '@esbuild/netbsd-x64': 0.27.7\n '@esbuild/openbsd-arm64': 0.27.7\n '@esbuild/openbsd-x64': 0.27.7\n '@esbuild/openharmony-arm64': 0.27.7\n '@esbuild/sunos-x64': 0.27.7\n '@esbuild/win32-arm64': 0.27.7\n '@esbuild/win32-ia32': 0.27.7\n '@esbuild/win32-x64': 0.27.7\n\n fdir@6.5.0(picomatch@4.0.4):\n optionalDependencies:\n picomatch: 4.0.4\n\n fix-dts-default-cjs-exports@1.0.1:\n dependencies:\n magic-string: 0.30.21\n mlly: 1.8.2\n rollup: 4.61.1\n\n fsevents@2.3.3:\n optional: true\n\n joycon@3.1.1: {}\n\n lilconfig@3.1.3: {}\n\n lines-and-columns@1.2.4: {}\n\n load-tsconfig@0.2.5: {}\n\n magic-string@0.30.21:\n dependencies:\n '@jridgewell/sourcemap-codec': 1.5.5\n\n mlly@1.8.2:\n dependencies:\n acorn: 8.16.0\n pathe: 2.0.3\n pkg-types: 1.3.1\n ufo: 1.6.4\n\n ms@2.1.3: {}\n\n mz@2.7.0:\n dependencies:\n any-promise: 1.3.0\n object-assign: 4.1.1\n thenify-all: 1.6.0\n\n object-assign@4.1.1: {}\n\n pathe@2.0.3: {}\n\n picocolors@1.1.1: {}\n\n picomatch@4.0.4: {}\n\n pirates@4.0.7: {}\n\n pkg-types@1.3.1:\n dependencies:\n confbox: 0.1.8\n mlly: 1.8.2\n pathe: 2.0.3\n\n postcss-load-config@6.0.1:\n dependencies:\n lilconfig: 3.1.3\n\n react@19.2.7: {}\n\n readdirp@4.1.2: {}\n\n resolve-from@5.0.0: {}\n\n rollup@4.61.1:\n dependencies:\n '@types/estree': 1.0.9\n optionalDependencies:\n '@rollup/rollup-android-arm-eabi': 4.61.1\n '@rollup/rollup-android-arm64': 4.61.1\n '@rollup/rollup-darwin-arm64': 4.61.1\n '@rollup/rollup-darwin-x64': 4.61.1\n '@rollup/rollup-freebsd-arm64': 4.61.1\n '@rollup/rollup-freebsd-x64': 4.61.1\n '@rollup/rollup-linux-arm-gnueabihf': 4.61.1\n '@rollup/rollup-linux-arm-musleabihf': 4.61.1\n '@rollup/rollup-linux-arm64-gnu': 4.61.1\n '@rollup/rollup-linux-arm64-musl': 4.61.1\n '@rollup/rollup-linux-loong64-gnu': 4.61.1\n '@rollup/rollup-linux-loong64-musl': 4.61.1\n '@rollup/rollup-linux-ppc64-gnu': 4.61.1\n '@rollup/rollup-linux-ppc64-musl': 4.61.1\n '@rollup/rollup-linux-riscv64-gnu': 4.61.1\n '@rollup/rollup-linux-riscv64-musl': 4.61.1\n '@rollup/rollup-linux-s390x-gnu': 4.61.1\n '@rollup/rollup-linux-x64-gnu': 4.61.1\n '@rollup/rollup-linux-x64-musl': 4.61.1\n '@rollup/rollup-openbsd-x64': 4.61.1\n '@rollup/rollup-openharmony-arm64': 4.61.1\n '@rollup/rollup-win32-arm64-msvc': 4.61.1\n '@rollup/rollup-win32-ia32-msvc': 4.61.1\n '@rollup/rollup-win32-x64-gnu': 4.61.1\n '@rollup/rollup-win32-x64-msvc': 4.61.1\n fsevents: 2.3.3\n\n source-map@0.7.6: {}\n\n sucrase@3.35.1:\n dependencies:\n '@jridgewell/gen-mapping': 0.3.13\n commander: 4.1.1\n lines-and-columns: 1.2.4\n mz: 2.7.0\n pirates: 4.0.7\n tinyglobby: 0.2.17\n ts-interface-checker: 0.1.13\n\n thenify-all@1.6.0:\n dependencies:\n thenify: 3.3.1\n\n thenify@3.3.1:\n dependencies:\n any-promise: 1.3.0\n\n tinyexec@0.3.2: {}\n\n tinyglobby@0.2.17:\n dependencies:\n fdir: 6.5.0(picomatch@4.0.4)\n picomatch: 4.0.4\n\n tree-kill@1.2.2: {}\n\n ts-interface-checker@0.1.13: {}\n\n tsup@8.5.1(typescript@5.9.3):\n dependencies:\n bundle-require: 5.1.0(esbuild@0.27.7)\n cac: 6.7.14\n chokidar: 4.0.3\n consola: 3.4.2\n debug: 4.4.3\n esbuild: 0.27.7\n fix-dts-default-cjs-exports: 1.0.1\n joycon: 3.1.1\n picocolors: 1.1.1\n postcss-load-config: 6.0.1\n resolve-from: 5.0.0\n rollup: 4.61.1\n source-map: 0.7.6\n sucrase: 3.35.1\n tinyexec: 0.3.2\n tinyglobby: 0.2.17\n tree-kill: 1.2.2\n optionalDependencies:\n typescript: 5.9.3\n transitivePeerDependencies:\n - jiti\n - supports-color\n - tsx\n - yaml\n\n typescript@5.9.3: {}\n\n ufo@1.6.4: {}\n\n undici-types@7.18.2: {}\n",
|
|
9
|
+
"scripts/build-release.mjs": "import { readFileSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { gzipSync } from 'node:zlib';\nimport { execFileSync } from 'node:child_process';\nconst digest = (bytes, algorithm = 'sha256', encoding = 'hex') => createHash(algorithm).update(bytes).digest(encoding);\nconst pkg = JSON.parse(readFileSync('package.json', 'utf8'));\nconst bundle = readFileSync('dist/sdk.global.js');\nconst sourceFiles = ['src/index.ts', 'src/browser.ts', 'src/research.ts', 'tsup.config.ts', 'package.json', 'pnpm-lock.yaml', 'scripts/build-release.mjs'];\nconst files = Object.fromEntries(sourceFiles.map(path => [path, readFileSync(path, 'utf8')]));\nconst source = JSON.stringify({ files }, null, 2) + '\\n';\nconst sha256 = digest(bundle);\nconst sourceCommit = execFileSync('git', ['rev-parse', 'HEAD'], {encoding:'utf8'}).trim();\nconst sourceDirty = Boolean(execFileSync('git', ['status', '--porcelain', '--untracked-files=normal'], {encoding:'utf8'}).trim());\nconst artifactId = digest(JSON.stringify([pkg.version, sha256, digest(source), sourceCommit, sourceDirty]));\nconst manifest = {\n schemaVersion: 1, package: pkg.name, version: pkg.version,\n sourceCommit, sourceDirty, artifactId,\n bundle: { file: 'sdk.global.js', path: `releases/${pkg.version}/${artifactId}/sdk.global.js`, sha256,\n integrity: 'sha384-' + digest(bundle, 'sha384', 'base64'), bytes: bundle.length, gzipBytes: gzipSync(bundle).length },\n source: { file: 'source.json', sha256: digest(source) },\n runtimeDependencies: Object.keys(pkg.dependencies || {}),\n};\nwriteFileSync('dist/source.json', source);\nwriteFileSync('dist/release.json', JSON.stringify(manifest, null, 2) + '\\n');\nconsole.log(`Prepared ${pkg.name} ${pkg.version}: ${bundle.length} bytes, ${manifest.bundle.gzipBytes} gzip bytes. No publication performed.`);\n"
|
|
10
|
+
}
|
|
11
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sightspool/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Sightspool
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Sightspool research SDK \u2014 invite website visitors and signed-in users into approved user research.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -17,12 +17,15 @@
|
|
|
17
17
|
"dist",
|
|
18
18
|
"README.md",
|
|
19
19
|
"LICENSE",
|
|
20
|
-
"NOTICE"
|
|
20
|
+
"NOTICE",
|
|
21
|
+
"site",
|
|
22
|
+
"SECURITY.md",
|
|
23
|
+
"CHANGELOG.md"
|
|
21
24
|
],
|
|
22
25
|
"sideEffects": false,
|
|
23
26
|
"license": "Apache-2.0",
|
|
24
27
|
"author": "Sightspool",
|
|
25
|
-
"homepage": "https://
|
|
28
|
+
"homepage": "https://www.sightspool.com/sdk",
|
|
26
29
|
"repository": {
|
|
27
30
|
"type": "git",
|
|
28
31
|
"url": "git+https://github.com/sightspool/sdk.git"
|
|
@@ -32,12 +35,9 @@
|
|
|
32
35
|
},
|
|
33
36
|
"keywords": [
|
|
34
37
|
"sightspool",
|
|
35
|
-
"analytics",
|
|
36
|
-
"product-analytics",
|
|
37
38
|
"user-research",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"telemetry",
|
|
39
|
+
"research",
|
|
40
|
+
"interviews",
|
|
41
41
|
"sdk"
|
|
42
42
|
],
|
|
43
43
|
"engines": {
|
|
@@ -48,10 +48,12 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
|
-
"build": "tsup",
|
|
51
|
+
"build": "tsup && node scripts/build-release.mjs",
|
|
52
52
|
"type-check": "tsc --noEmit",
|
|
53
|
-
"test": "node --test __tests__/*.test.ts",
|
|
54
|
-
"prepublishOnly": "pnpm run build"
|
|
53
|
+
"test": "tsc --noEmit && node --test __tests__/*.test.ts",
|
|
54
|
+
"prepublishOnly": "pnpm run build",
|
|
55
|
+
"test:release": "node scripts/verify-release.mjs && node --test scripts/release.test.mjs",
|
|
56
|
+
"build:site": "node scripts/stage-site.mjs"
|
|
55
57
|
},
|
|
56
58
|
"devDependencies": {
|
|
57
59
|
"@types/node": "^24.10.4",
|
package/site/CNAME
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sdk.sightspool.com
|
package/site/demo.html
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Try the research SDK — Sightspool</title><link rel="stylesheet" href="styles.css"><script src="demo.js" defer></script></head><body><main class="wrap">
|
|
2
|
+
<nav aria-label="SDK documentation"><a href="index.html">SDK guide</a><a href="trust.html">Data & security</a><a href="demo.html" aria-current="page">Try the SDK</a></nav>
|
|
3
|
+
<h1>See what the SDK does.</h1><p class="lede">Run the actual built SDK with a simulated invitation response. Switch audience, sign in or out, and inspect the request fields.</p><p class="note">This standalone demo replaces offer requests with local simulated responses. Only documentation and bundle files are fetched. No real workspace, participant, interview, microphone or recording is used. Request bodies below redact the random session identifier.</p>
|
|
4
|
+
<div class="controls" id="controls"><button disabled data-action="visitors">Start for all visitors</button><button disabled data-action="members">Start for signed-in users</button><button disabled data-action="login" class="secondary">Simulate sign-in</button><button disabled data-action="logout" class="secondary">Sign out</button><button disabled data-action="pause" class="secondary">Pause</button><button disabled data-action="resume" class="secondary">Resume</button><button disabled data-action="destroy" class="secondary">Remove widget</button></div>
|
|
5
|
+
<p id="status" role="status">Loading the reviewed SDK bundle…</p><p id="summary">No simulated offer requests yet.</p><h2>Simulated request log</h2><pre id="events">Choose an audience to start.</pre><p class="muted">The launcher is the current runtime’s simple interview button. Clicking it logs the handoff rather than opening an interview.</p>
|
|
6
|
+
<footer><a href="trust.html">Read the full data inventory and limitations</a></footer></main></body></html>
|
package/site/demo.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
(async () => {
|
|
2
|
+
const status=document.getElementById('status'), events=document.getElementById('events');
|
|
3
|
+
const realFetch=window.fetch.bind(window);let count=0, log=[], identityLeaked=false, timer;
|
|
4
|
+
const show=(entry)=>{log.unshift(entry);log=log.slice(0,10);events.textContent=log.join('\n\n');};
|
|
5
|
+
try {
|
|
6
|
+
const response=await realFetch('release.json',{credentials:'omit',cache:'no-store'});
|
|
7
|
+
if(!response.ok) throw Error('Release manifest unavailable');
|
|
8
|
+
const manifest=await response.json();
|
|
9
|
+
if(!/^[a-f0-9]{64}$/.test(manifest.artifactId)||!/^\d+\.\d+\.\d+$/.test(manifest.version)||!/^[a-f0-9]{64}$/.test(manifest.bundle.sha256)||manifest.bundle.path!==`releases/${manifest.version}/${manifest.artifactId}/sdk.global.js`||!/^sha384-[A-Za-z0-9+/]{64}$/.test(manifest.bundle.integrity)) throw Error('Invalid release manifest');
|
|
10
|
+
window.fetch=async (url,input)=>{
|
|
11
|
+
if(String(url)!=='https://demo.sightspool.invalid/widget-offer') return realFetch(url,input);
|
|
12
|
+
const body=JSON.parse(input.body);count++;identityLeaked ||= input.body.includes('demo-private-user');
|
|
13
|
+
show('SIMULATED POST /widget-offer\n'+JSON.stringify({...body,device:'[random session identifier redacted]'},null,2));
|
|
14
|
+
document.getElementById('summary').textContent=`${count} simulated offer requests · test user ID in payload: ${identityLeaked?'YES':'no'}`;
|
|
15
|
+
return new Response(JSON.stringify({available:true,offer:'synthetic-demo-not-a-valid-offer'}),{headers:{'Content-Type':'application/json'}});
|
|
16
|
+
};
|
|
17
|
+
window.open=()=>{show('SIMULATED HANDOFF: the real flow opens consent and eligibility review. No interview opened.');return null;};
|
|
18
|
+
const script=document.createElement('script');script.src=manifest.bundle.path;script.integrity=manifest.bundle.integrity;script.crossOrigin='anonymous';script.referrerPolicy='no-referrer';
|
|
19
|
+
await new Promise((resolve,reject)=>{script.onload=resolve;script.onerror=()=>reject(Error('Bundle failed to load or integrity did not match'));document.body.appendChild(script);});
|
|
20
|
+
const sdk=window.Sightspool;
|
|
21
|
+
const start=(audience)=>sdk.init({key:'11111111-1111-4111-8111-111111111111',endpoint:'https://demo.sightspool.invalid',audience});
|
|
22
|
+
const actions={visitors:()=>start('all_visitors'),members:()=>start('signed_in'),login:()=>sdk.identify('demo-private-user'),logout:()=>sdk.identify(null),pause:()=>sdk.pause(),resume:()=>sdk.resume(),destroy:()=>sdk.destroy()};
|
|
23
|
+
document.querySelectorAll('[data-action]').forEach(button=>{button.disabled=false;button.onclick=actions[button.dataset.action];});
|
|
24
|
+
const update=()=>{const text=`SDK status: ${sdk.getStatus()}`;if(status.textContent!==text)status.textContent=text;};update();timer=setInterval(update,250);
|
|
25
|
+
window.addEventListener('pagehide',()=>{clearInterval(timer);sdk.destroy();},{once:true});
|
|
26
|
+
} catch(error) { status.textContent=`Demo unavailable: ${error.message}. No invitation was started.`; }
|
|
27
|
+
})();
|