@sightspool/sdk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/index.cjs +159 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +40 -13
- package/dist/index.js.map +1 -1
- package/dist/probe-BNGMQQ5C.js +113 -0
- package/dist/probe-BNGMQQ5C.js.map +1 -0
- package/dist/sdk.global.js +25 -4
- package/dist/sdk.global.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/capture.ts","../src/harvest.ts","../src/egress.ts","../src/triggers.ts","../src/intervention.ts","../src/env.ts","../src/index.ts"],"names":["_a","RAGE_WINDOW_MS"],"mappings":"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","file":"index.js","sourcesContent":["// 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\";\n\nexport type ServeContext = { route?: string; account?: string; plan?: string };\n\nexport type ServedIntervention = {\n id: string;\n type: string; // 'survey' renders today; others ignored until their widget ships\n config: SurveyConfig;\n};\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\"]);\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 / no\n * question). */\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 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, 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://app.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 c.surveyOnScreen = true;\n c.interventionsShown += 1;\n c.fatigue.lastPromptAt = Date.now(); // share the cooldown with the passive prompt\n try {\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 } 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/capture.ts","../src/harvest.ts","../src/egress.ts","../src/triggers.ts","../src/intervention.ts","../src/env.ts","../src/index.ts"],"names":["_a","RAGE_WINDOW_MS"],"mappings":"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","file":"index.js","sourcesContent":["// 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"]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// src/probe.ts
|
|
2
|
+
var FLOATING_STYLE = `
|
|
3
|
+
:host { all: initial; }
|
|
4
|
+
.wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;
|
|
5
|
+
width: 340px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }
|
|
6
|
+
.card { position: relative; background: #fff; color: #18181b; border: 1px solid #e4e4e7;
|
|
7
|
+
border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }
|
|
8
|
+
.probe { font: inherit; font-size: 13px; cursor: pointer; display: block; width: 100%;
|
|
9
|
+
text-align: left; border: 1px dashed #a1a1aa; border-radius: 8px; padding: 10px 12px;
|
|
10
|
+
background: #fafafa; color: #3f3f46; }
|
|
11
|
+
.probe:hover { border-color: #18181b; color: #18181b; }
|
|
12
|
+
.x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;
|
|
13
|
+
color: #a1a1aa; padding: 2px 6px; cursor: pointer; }
|
|
14
|
+
.done { font-size: 13px; color: #18181b; margin: 0; line-height: 1.4; }
|
|
15
|
+
`;
|
|
16
|
+
var INLINE_STYLE = `
|
|
17
|
+
:host { all: initial; display: inline-block; max-width: 100%; }
|
|
18
|
+
.probe { font: inherit; font-family: system-ui, -apple-system, sans-serif; font-size: 13px;
|
|
19
|
+
cursor: pointer; display: inline-block; text-align: left; border: 1px dashed #a1a1aa;
|
|
20
|
+
border-radius: 8px; padding: 8px 12px; background: transparent; color: #52525b; }
|
|
21
|
+
.probe:hover { border-color: #18181b; color: #18181b; }
|
|
22
|
+
.done { font-family: system-ui, -apple-system, sans-serif; font-size: 13px; color: #52525b;
|
|
23
|
+
margin: 0; line-height: 1.4; border: 1px dashed #d4d4d8; border-radius: 8px; padding: 8px 12px; }
|
|
24
|
+
`;
|
|
25
|
+
var DISCLOSURE_MS = 3200;
|
|
26
|
+
function findSlot(slot) {
|
|
27
|
+
try {
|
|
28
|
+
return document.querySelector(`[data-sightspool-slot="${slot}"]`);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function showProbe(config) {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
if (typeof document === "undefined") {
|
|
36
|
+
resolve({ dismissed: true, mounted: false });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const anchor = config.slot ? findSlot(config.slot) : null;
|
|
40
|
+
if (config.slot && !anchor) {
|
|
41
|
+
resolve({ mounted: false });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let settled = false;
|
|
45
|
+
const inline = !!anchor;
|
|
46
|
+
const host = document.createElement(inline ? "span" : "div");
|
|
47
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
48
|
+
function teardown() {
|
|
49
|
+
try {
|
|
50
|
+
host.remove();
|
|
51
|
+
} catch (e) {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function finish(result, disclose) {
|
|
55
|
+
if (settled) return;
|
|
56
|
+
settled = true;
|
|
57
|
+
resolve(result);
|
|
58
|
+
if (disclose) {
|
|
59
|
+
disclosure();
|
|
60
|
+
setTimeout(teardown, DISCLOSURE_MS);
|
|
61
|
+
} else {
|
|
62
|
+
teardown();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const style = document.createElement("style");
|
|
66
|
+
style.textContent = inline ? INLINE_STYLE : FLOATING_STYLE;
|
|
67
|
+
shadow.appendChild(style);
|
|
68
|
+
const wrap = document.createElement(inline ? "span" : "div");
|
|
69
|
+
if (!inline) wrap.className = "wrap";
|
|
70
|
+
shadow.appendChild(wrap);
|
|
71
|
+
function container() {
|
|
72
|
+
wrap.innerHTML = "";
|
|
73
|
+
if (inline) return wrap;
|
|
74
|
+
const c = document.createElement("div");
|
|
75
|
+
c.className = "card";
|
|
76
|
+
wrap.appendChild(c);
|
|
77
|
+
return c;
|
|
78
|
+
}
|
|
79
|
+
function probe() {
|
|
80
|
+
const c = container();
|
|
81
|
+
if (!inline) {
|
|
82
|
+
const x = document.createElement("button");
|
|
83
|
+
x.className = "x";
|
|
84
|
+
x.textContent = "\xD7";
|
|
85
|
+
x.setAttribute("aria-label", "Dismiss");
|
|
86
|
+
x.onclick = () => finish({ dismissed: true, mounted: true }, false);
|
|
87
|
+
c.appendChild(x);
|
|
88
|
+
}
|
|
89
|
+
const b = document.createElement("button");
|
|
90
|
+
b.className = "probe";
|
|
91
|
+
b.textContent = config.label;
|
|
92
|
+
b.onclick = () => finish({ voted: true, mounted: true }, true);
|
|
93
|
+
c.appendChild(b);
|
|
94
|
+
}
|
|
95
|
+
function disclosure() {
|
|
96
|
+
const c = container();
|
|
97
|
+
const p = document.createElement("p");
|
|
98
|
+
p.className = "done";
|
|
99
|
+
p.textContent = config.disclosure;
|
|
100
|
+
c.appendChild(p);
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
(anchor != null ? anchor : document.body).appendChild(host);
|
|
104
|
+
probe();
|
|
105
|
+
} catch (e) {
|
|
106
|
+
finish({ dismissed: true, mounted: false }, false);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { showProbe };
|
|
112
|
+
//# sourceMappingURL=probe-BNGMQQ5C.js.map
|
|
113
|
+
//# sourceMappingURL=probe-BNGMQQ5C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/probe.ts"],"names":[],"mappings":"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","file":"probe-BNGMQQ5C.js","sourcesContent":["// 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"]}
|