@loupfeed/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +114 -0
- package/dist/index.cjs +942 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +351 -0
- package/dist/index.d.ts +351 -0
- package/dist/index.js +910 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dsn.ts","../src/transport.ts","../src/selector.ts","../src/env.ts","../src/version.ts","../src/event.ts","../src/scope.ts","../src/replay.ts","../src/client.ts","../src/sdk.ts","../src/overlay/styles.ts","../src/overlay/index.ts"],"names":["buffer","close"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * DSN parsing + ingest endpoint derivation.\n *\n * Format (Sentry-inspired):\n * https://<PUBLIC_KEY>@<INGEST_HOST>/o/<ORG_ID>/p/<PROJECT_ID>\n *\n * Self-host vs SaaS is purely the host — same protocol, same packages.\n */\n\nexport type Dsn = {\n raw: string;\n protocol: string;\n publicKey: string;\n /** hostname only (no port). */\n host: string;\n port: string;\n orgId: string;\n projectId: string;\n /** `${protocol}://${host[:port]}` — no trailing slash. */\n baseUrl: string;\n};\n\nconst PATH_RE = /^\\/o\\/([^/]+)\\/p\\/([^/]+)\\/?$/;\n\nexport function parseDsn(dsn: string): Dsn {\n let url: URL;\n try {\n url = new URL(dsn);\n } catch {\n throw new Error(`[loupfeed] Invalid DSN: ${JSON.stringify(dsn)}`);\n }\n const publicKey = url.username;\n if (!publicKey) {\n throw new Error('[loupfeed] DSN is missing its public key: https://<PUBLIC_KEY>@host/o/<org>/p/<project>');\n }\n const match = PATH_RE.exec(url.pathname);\n const orgId = match?.[1];\n const projectId = match?.[2];\n if (!orgId || !projectId) {\n throw new Error(`[loupfeed] DSN path must be /o/<org>/p/<project>, got ${JSON.stringify(url.pathname)}`);\n }\n const protocol = url.protocol.replace(/:$/, '');\n return {\n raw: dsn,\n protocol,\n publicKey,\n host: url.hostname,\n port: url.port,\n orgId,\n projectId,\n baseUrl: `${protocol}://${url.host}`,\n };\n}\n\nfunction apiBase(dsn: Dsn): string {\n return `${dsn.baseUrl}/api/${encodeURIComponent(dsn.orgId)}/${encodeURIComponent(dsn.projectId)}`;\n}\n\nexport function eventsUrl(dsn: Dsn): string {\n return `${apiBase(dsn)}/events`;\n}\nexport function replaysUrl(dsn: Dsn): string {\n return `${apiBase(dsn)}/replays`;\n}\nexport function manifestsUrl(dsn: Dsn): string {\n return `${apiBase(dsn)}/manifests`;\n}\nexport function resolveUrl(dsn: Dsn): string {\n return `${apiBase(dsn)}/resolve`;\n}\n","/**\n * Fetch transport — POSTs the FeedbackEvent envelope (and, when present, the\n * replay blob) to the DSN-derived ingest endpoints. Retries on network / 5xx,\n * tracks in-flight sends for flush(), and uses `keepalive` so a submit can\n * outlive an unload.\n */\n\nimport type { Dsn } from './dsn';\nimport { eventsUrl, replaysUrl } from './dsn';\nimport type { FeedbackEvent, ReplayBuffer, Transport } from './types';\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function makeFetchTransport(dsn: Dsn, opts: { debug?: boolean } = {}): Transport {\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n // Non-secret, project-scoped ingest key (doc 06 §Auth on ingest).\n 'x-loupfeed-key': dsn.publicKey,\n };\n const pending = new Set<Promise<unknown>>();\n\n async function post(url: string, body: string, attempt = 0): Promise<Response> {\n try {\n const res = await fetch(url, { method: 'POST', headers, body, keepalive: true });\n if (res.status >= 500 && attempt < 2) {\n await delay(200 * (attempt + 1));\n return post(url, body, attempt + 1);\n }\n return res;\n } catch (err) {\n if (attempt < 2) {\n await delay(200 * (attempt + 1));\n return post(url, body, attempt + 1);\n }\n throw err;\n }\n }\n\n function track<T>(p: Promise<T>): Promise<T> {\n pending.add(p);\n void p.catch(() => undefined).finally(() => pending.delete(p));\n return p;\n }\n\n async function send(event: FeedbackEvent): Promise<string> {\n return track(\n post(eventsUrl(dsn), JSON.stringify(event)).then(async (res) => {\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`[loupfeed] ingest responded ${res.status} ${text}`.trim());\n }\n const data = (await res.json().catch(() => ({}))) as { eventId?: string };\n if (opts.debug) console.debug('[loupfeed] sent event', data.eventId ?? event.eventId);\n return data.eventId ?? event.eventId;\n }),\n );\n }\n\n async function sendReplay(buffer: ReplayBuffer): Promise<{ replayId: string; durationMs: number }> {\n const body = JSON.stringify({\n replayId: buffer.replayId,\n durationMs: buffer.durationMs,\n kind: buffer.kind ?? 'rrweb',\n events: buffer.events,\n frames: buffer.frames,\n viewport: buffer.viewport,\n video: buffer.video,\n mimeType: buffer.mimeType,\n });\n const res = await post(replaysUrl(dsn), body);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`[loupfeed] replay upload ${res.status} ${text}`.trim());\n }\n const data = (await res.json().catch(() => ({}))) as { replayId?: string; durationMs?: number };\n return {\n replayId: data.replayId ?? buffer.replayId,\n durationMs: data.durationMs ?? buffer.durationMs,\n };\n }\n\n async function flush(timeout?: number): Promise<boolean> {\n const all = Promise.allSettled([...pending]).then(() => true);\n if (!timeout) return all;\n return Promise.race([all, delay(timeout).then(() => false)]);\n }\n\n return { send, sendReplay, flush };\n}\n","/**\n * Element-identification engine (lifted + generalized from the Trivision\n * `app/src/feedback/selector.ts`). Produces an identifier per element that:\n * 1. Survives re-renders within a session\n * 2. Survives a page refresh (comments persist across reloads)\n * 3. Tolerates minor markup changes between deploys (best-effort)\n *\n * Three-tier resolution, in priority order:\n * 1. el.closest('[data-fb-id]') → hand-authored stable id\n * 2. el.closest('[data-fb]') → opaque build-injected id → manifest (src:line)\n * 3. structural CSS path → tag + :nth-of-type(n), relative to the root\n *\n * The opaque `data-fb` id never carries a source path; it resolves to\n * `<rel-path>:<line>` server-side via the manifest. The client never sees paths.\n */\n\nimport type { ElementInfo } from './types';\n\n/** The root selectors are generated relative to. Set once by the overlay. */\nlet rootEl: Element | null = null;\n\nexport function setSelectorRoot(el: Element | null): void {\n rootEl = el;\n}\n\nexport function getSelectorRoot(): Element | null {\n return rootEl;\n}\n\nfunction defaultRoot(): Element | null {\n if (rootEl) return rootEl;\n return typeof document !== 'undefined' ? document.body : null;\n}\n\n/** Generate a stable selector for an element, relative to the root. */\nexport function selectorFor(el: Element): string {\n // 1. Closest data-fb-id wins.\n const tagged = el.closest('[data-fb-id]');\n if (tagged) {\n return `[data-fb-id=\"${tagged.getAttribute('data-fb-id')}\"]`;\n }\n // 2. Build a structural CSS path back up to the root. tag + :nth-of-type so\n // swapping unrelated siblings doesn't break the selector.\n const root = defaultRoot();\n const parts: string[] = [];\n let cur: Element | null = el;\n while (cur && cur !== root) {\n const node: Element = cur;\n const parent: Element | null = node.parentElement;\n if (!parent) break;\n const tag = node.tagName.toLowerCase();\n const sameTag = Array.from(parent.children).filter((c) => c.tagName === node.tagName);\n let segment = tag;\n if (sameTag.length > 1) {\n segment += `:nth-of-type(${sameTag.indexOf(node) + 1})`;\n }\n parts.unshift(segment);\n cur = parent;\n }\n return parts.join(' > ');\n}\n\n/** Try to resolve a stored selector back to a live element. */\nexport function resolveSelector(selector: string): Element | null {\n const root = defaultRoot();\n if (!root || !selector) return null;\n try {\n return root.querySelector(selector);\n } catch {\n return null;\n }\n}\n\n/** Snapshot an element's identity + display metadata at click time. */\nexport function snapshotElement(el: Element): ElementInfo {\n const r = el.getBoundingClientRect();\n // Walk up to the nearest ancestor carrying the opaque build-injected id. The\n // element itself usually qualifies (every JSX node is tagged), but leaf icons\n // are not, so closest() climbs to the rendering component's outer element.\n const idEl = el.closest('[data-fb]');\n const elementId = idEl?.getAttribute('data-fb') ?? undefined;\n const text = (el.textContent ?? '').trim().slice(0, 80);\n return {\n selector: selectorFor(el),\n elementId,\n tagName: el.tagName.toLowerCase(),\n text: text || undefined,\n rect: { x: r.x, y: r.y, w: r.width, h: r.height },\n };\n}\n","/** SSR-safe environment guards + small primitives. No DOM work runs at import. */\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nexport function nowIso(): string {\n return new Date().toISOString();\n}\n\nexport function uuid(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n // RFC4122-ish fallback for older runtimes.\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n","/** SDK version, surfaced on every event's `sdk` field. Bumped by Changesets. */\nexport const SDK_VERSION = '0.0.0';\n","/**\n * FeedbackEvent assembly. Merges global scope ⊕ active withScope child ⊕\n * auto-context ⊕ the element snapshot, then runs `beforeSend`.\n */\n\nimport type { Client } from './client';\nimport type { ScopeData } from './scope';\nimport type { ElementInfo, FeedbackEvent, FeedbackInput, Primitive } from './types';\nimport { snapshotElement } from './selector';\nimport { isBrowser, nowIso, uuid } from './env';\nimport { SDK_VERSION } from './version';\n\nfunction normalizeTags(tags: Record<string, Primitive>): Record<string, string | number | boolean> {\n const out: Record<string, string | number | boolean> = {};\n for (const [k, v] of Object.entries(tags)) {\n if (v === null || v === undefined) continue;\n out[k] = v;\n }\n return out;\n}\n\nexport function buildEvent(\n client: Client,\n input: FeedbackInput,\n scope: ScopeData,\n): FeedbackEvent | null {\n const options = client.getOptions();\n let element: ElementInfo;\n if (input.element) {\n // Web: snapshot the live DOM element.\n element = snapshotElement(input.element);\n } else if (input.elementId || input.elementInfo) {\n // Non-DOM (React Native): the adapter supplies the anchor directly.\n element = {\n selector: input.elementInfo?.selector ?? '',\n elementId: input.elementId ?? input.elementInfo?.elementId,\n tagName: input.elementInfo?.tagName,\n text: input.elementInfo?.text,\n rect: input.elementInfo?.rect,\n };\n } else {\n element = { selector: '' };\n }\n\n const event: FeedbackEvent = {\n eventId: uuid(),\n timestamp: nowIso(),\n release: options.release ?? '',\n environment: options.environment ?? 'production',\n text: input.text,\n element,\n sdk: { name: 'loupfeed', version: SDK_VERSION },\n };\n\n if (scope.user) event.user = scope.user;\n const tags = normalizeTags(scope.tags);\n if (Object.keys(tags).length) event.tags = tags;\n if (Object.keys(scope.contexts).length) event.contexts = { ...scope.contexts };\n if (scope.breadcrumbs.length) event.breadcrumbs = scope.breadcrumbs;\n\n if (options.autoContext !== false && isBrowser()) {\n event.request = { url: window.location.href };\n const device = {\n viewport: {\n width: window.innerWidth,\n height: window.innerHeight,\n dpr: window.devicePixelRatio,\n },\n };\n event.contexts = { ...(event.contexts ?? {}), device };\n }\n\n if (options.beforeSend) {\n return options.beforeSend(event);\n }\n return event;\n}\n","/**\n * Scope / context API — generalizes what Trivision's FeedbackProvider hard-codes\n * (tenant/rep/version) into a Sentry-style developer-driven API.\n *\n * - The global scope holds long-lived data (user, tags, persistent contexts).\n * - `withScope(cb)` forks a child for a single capture without polluting global.\n */\n\nimport type { Breadcrumb, Primitive, User } from './types';\nimport { nowIso } from './env';\n\nexport interface ScopeData {\n user?: User;\n tags: Record<string, Primitive>;\n contexts: Record<string, Record<string, unknown>>;\n breadcrumbs: Breadcrumb[];\n}\n\nconst DEFAULT_MAX_BREADCRUMBS = 50;\n\nexport class Scope {\n private _user?: User;\n private _tags: Record<string, Primitive> = {};\n private _contexts: Record<string, Record<string, unknown>> = {};\n private _breadcrumbs: Breadcrumb[] = [];\n private _maxBreadcrumbs = DEFAULT_MAX_BREADCRUMBS;\n\n setUser(user: User | null): this {\n this._user = user ?? undefined;\n return this;\n }\n\n getUser(): User | undefined {\n return this._user;\n }\n\n setTag(key: string, value: Primitive): this {\n this._tags[key] = value;\n return this;\n }\n\n setTags(tags: Record<string, Primitive>): this {\n Object.assign(this._tags, tags);\n return this;\n }\n\n setContext(key: string, data: Record<string, unknown> | null): this {\n if (data === null) {\n delete this._contexts[key];\n } else {\n this._contexts[key] = data;\n }\n return this;\n }\n\n addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): this {\n const crumb: Breadcrumb = { ...breadcrumb, timestamp: breadcrumb.timestamp ?? nowIso() };\n this._breadcrumbs.push(crumb);\n const limit = maxBreadcrumbs ?? this._maxBreadcrumbs;\n if (this._breadcrumbs.length > limit) {\n this._breadcrumbs.splice(0, this._breadcrumbs.length - limit);\n }\n return this;\n }\n\n setMaxBreadcrumbs(n: number): this {\n this._maxBreadcrumbs = n;\n return this;\n }\n\n clearBreadcrumbs(): this {\n this._breadcrumbs = [];\n return this;\n }\n\n clone(): Scope {\n const c = new Scope();\n c._user = this._user;\n c._tags = { ...this._tags };\n c._contexts = Object.fromEntries(\n Object.entries(this._contexts).map(([k, v]) => [k, { ...v }]),\n );\n c._breadcrumbs = [...this._breadcrumbs];\n c._maxBreadcrumbs = this._maxBreadcrumbs;\n return c;\n }\n\n getScopeData(): ScopeData {\n return {\n user: this._user,\n tags: { ...this._tags },\n contexts: Object.fromEntries(\n Object.entries(this._contexts).map(([k, v]) => [k, { ...v }]),\n ),\n breadcrumbs: [...this._breadcrumbs],\n };\n }\n}\n\nlet globalScope: Scope | undefined;\nconst scopeStack: Scope[] = [];\n\nexport function getGlobalScope(): Scope {\n if (!globalScope) globalScope = new Scope();\n return globalScope;\n}\n\n/** The active scope: the top of the withScope stack, else the global scope. */\nexport function getCurrentScope(): Scope {\n return scopeStack[scopeStack.length - 1] ?? getGlobalScope();\n}\n\n/** Fork a child scope for a single capture; auto-popped when `cb` returns. */\nexport function withScope<T>(cb: (scope: Scope) => T): T {\n const child = getCurrentScope().clone();\n scopeStack.push(child);\n try {\n return cb(child);\n } finally {\n scopeStack.pop();\n }\n}\n\n// —— convenience top-level API (operate on the active scope) ——\n\nexport function setUser(user: User | null): void {\n getCurrentScope().setUser(user);\n}\nexport function setContext(key: string, data: Record<string, unknown> | null): void {\n getCurrentScope().setContext(key, data);\n}\nexport function setTag(key: string, value: Primitive): void {\n getCurrentScope().setTag(key, value);\n}\nexport function setTags(tags: Record<string, Primitive>): void {\n getCurrentScope().setTags(tags);\n}\nexport function addBreadcrumb(breadcrumb: Breadcrumb): void {\n getCurrentScope().addBreadcrumb(breadcrumb);\n}\n","/**\n * Session recorder — wraps rrweb behind loupfeed's own rolling-buffer + masking\n * lifecycle (docs/05). We own the masking *defaults* (mask-by-default), the ring\n * buffer, and the upload lifecycle; rrweb is just the DOM codec, swappable later.\n *\n * rrweb is loaded with a real dynamic import so it (a) stays out of apps that\n * don't enable replay (tree-shakeable / lazy) and (b) is bundler-resolved on web.\n * React Native uses a native recorder instead and stubs `rrweb` in Metro.\n */\n\nimport type { Recorder, ReplayBuffer, ReplayOptions } from './types';\nimport { isBrowser, uuid } from './env';\n\n/** Minimal shape of an rrweb event we rely on. */\ntype RREvent = { type: number; timestamp: number; [k: string]: unknown };\n\nconst FULL_SNAPSHOT = 2; // rrweb EventType.FullSnapshot\nconst META = 4; // rrweb EventType.Meta\n\nlet stopFn: (() => void) | null = null;\nlet starting = false;\nlet buffer: RREvent[] = [];\nlet checkpoints: number[] = []; // buffer indices that start a valid replay (Meta/FullSnapshot)\n\nlet replayOptions: ReplayOptions = {};\nlet bufferMs = 60_000;\nconst MAX_BYTES = 5_000_000;\n\nexport function configureRecorder(opts: { replay?: ReplayOptions; replayBufferSeconds?: number }): void {\n replayOptions = opts.replay ?? {};\n if (typeof opts.replayBufferSeconds === 'number') bufferMs = Math.max(5, opts.replayBufferSeconds) * 1000;\n}\n\nfunction rrwebOptions(emit: (e: RREvent, isCheckout?: boolean) => void): Record<string, unknown> {\n const o = replayOptions;\n return {\n emit,\n checkoutEveryNms: bufferMs, // periodic full snapshots bound the buffer\n // —— masking: privacy by DEFAULT (mask everything, opt out deliberately) ——\n maskAllInputs: o.maskAllInputs !== false,\n maskInputOptions: { password: true }, // passwords always, non-overridable\n maskTextSelector: o.maskAllText !== false ? '*' : o.maskTextSelector,\n blockSelector: o.blockSelector ?? '[data-fb-block],[data-private]',\n recordCanvas: false,\n collectFonts: false,\n };\n}\n\nfunction bytes(): number {\n // Cheap upper-bound estimate without serializing every event each push.\n let n = 0;\n for (const e of buffer) n += (e as { __sz?: number }).__sz ?? 0;\n return n;\n}\n\nfunction enforce(): void {\n // Keep at most the last 2 checkpoint segments (covers >= bufferMs).\n while (checkpoints.length > 2) {\n const dropBefore = checkpoints[1]!;\n buffer = buffer.slice(dropBefore);\n checkpoints = checkpoints.slice(1).map((i) => i - dropBefore);\n }\n // Byte cap: drop the oldest segment until under the cap (keep >= 1 checkpoint).\n while (checkpoints.length > 1 && bytes() > MAX_BYTES) {\n const dropBefore = checkpoints[1]!;\n buffer = buffer.slice(dropBefore);\n checkpoints = checkpoints.slice(1).map((i) => i - dropBefore);\n }\n}\n\n// A truly-dynamic import the bundler can't statically resolve would break Vite,\n// so we use a normal dynamic import (Vite resolves it; Metro stubs `rrweb`).\nasync function loadRrweb(): Promise<{ record?: (o: unknown) => (() => void) | undefined } | null> {\n try {\n return (await import('rrweb')) as unknown as { record?: (o: unknown) => (() => void) | undefined };\n } catch {\n return null;\n }\n}\n\nasync function startAsync(): Promise<void> {\n if (!isBrowser() || stopFn || starting) return;\n starting = true;\n // Defer until the DOM exists so rrweb can snapshot the body.\n if (document.readyState === 'loading') {\n await new Promise<void>((r) => document.addEventListener('DOMContentLoaded', () => r(), { once: true }));\n }\n const rr = await loadRrweb();\n const record = rr?.record;\n if (typeof record !== 'function') {\n starting = false;\n console.warn('[loupfeed] rrweb not available — session replay disabled. Install it: `npm i rrweb`.');\n return;\n }\n buffer = [];\n checkpoints = [];\n const emit = (event: RREvent, _isCheckout?: boolean) => {\n if (event.type === FULL_SNAPSHOT) {\n // Start the segment at the preceding Meta event if present, so the player\n // has the viewport dimensions.\n const prev = buffer.length - 1;\n const start = prev >= 0 && buffer[prev]?.type === META ? prev : buffer.length;\n checkpoints.push(start);\n }\n try {\n (event as { __sz?: number }).__sz = JSON.stringify(event).length;\n } catch {\n (event as { __sz?: number }).__sz = 256;\n }\n buffer.push(event);\n enforce();\n };\n stopFn = record(rrwebOptions(emit)) ?? null;\n starting = false;\n}\n\n/** The public `replay` API (re-exported from core's index). */\nexport const replay = {\n start(): void {\n void startAsync();\n },\n stop(): void {\n stopFn?.();\n stopFn = null;\n buffer = [];\n checkpoints = [];\n },\n isRecording(): boolean {\n return stopFn != null || starting;\n },\n /** Freeze the rolling buffer for the current event. */\n snapshot(): ReplayBuffer {\n if (buffer.length === 0 || checkpoints.length === 0) {\n return { replayId: '', durationMs: 0, kind: 'rrweb', events: [] };\n }\n const events = buffer.map((e) => {\n const { __sz, ...rest } = e as RREvent & { __sz?: number };\n return rest;\n });\n const first = events[0] as RREvent | undefined;\n const last = events[events.length - 1] as RREvent | undefined;\n const durationMs = Math.max(0, (last?.timestamp ?? 0) - (first?.timestamp ?? 0));\n return { replayId: uuid(), durationMs, kind: 'rrweb', events };\n },\n};\n\n// The active recorder used at capture time. Web defaults to the rrweb `replay`;\n// React Native swaps in a native screen recorder via setReplayRecorder().\nlet activeRecorder: Recorder = replay;\n\nexport function setReplayRecorder(recorder: Recorder | null): void {\n activeRecorder = recorder ?? replay;\n}\n\nexport function getActiveRecorder(): Recorder {\n return activeRecorder;\n}\n","/**\n * Client — holds the parsed DSN, normalized options, and the transport. Owns\n * `captureFeedback`: it builds the event from the active scope and sends it.\n */\n\nimport type { Dsn } from './dsn';\nimport { parseDsn } from './dsn';\nimport { makeFetchTransport } from './transport';\nimport { buildEvent } from './event';\nimport { getCurrentScope, getGlobalScope } from './scope';\nimport { getActiveRecorder } from './replay';\nimport type { FeedbackEvent, FeedbackInput, InitOptions, Transport } from './types';\n\nexport class Client {\n readonly dsn: Dsn;\n private readonly options: InitOptions;\n private readonly transport: Transport;\n\n constructor(options: InitOptions) {\n this.options = options;\n this.dsn = parseDsn(options.dsn);\n this.transport = options.transport ?? makeFetchTransport(this.dsn, { debug: options.debug });\n if (typeof options.maxBreadcrumbs === 'number') {\n getGlobalScope().setMaxBreadcrumbs(options.maxBreadcrumbs);\n }\n }\n\n getOptions(): InitOptions {\n return this.options;\n }\n\n getDsn(): Dsn {\n return this.dsn;\n }\n\n getTransport(): Transport {\n return this.transport;\n }\n\n async captureFeedback(input: FeedbackInput): Promise<string> {\n const event = buildEvent(this, input, getCurrentScope().getScopeData());\n if (!event) {\n if (this.options.debug) console.warn('[loupfeed] event dropped by beforeSend');\n return '';\n }\n // Attach a session replay (sampled) before sending the event (docs/05).\n await this.maybeAttachReplay(event);\n if (this.options.debug) console.debug('[loupfeed] capture', event);\n try {\n return await this.transport.send(event);\n } catch (err) {\n console.error('[loupfeed] failed to send feedback', err);\n // Return the locally-generated id so callers/optimistic UIs still have one.\n return event.eventId;\n }\n }\n\n private async maybeAttachReplay(event: FeedbackEvent): Promise<void> {\n const rate = this.options.replaysSampleRate ?? 0;\n const recorder = getActiveRecorder();\n if (rate <= 0 || !this.transport.sendReplay || !recorder.isRecording()) return;\n if (Math.random() > rate) return;\n try {\n const buffer = await recorder.snapshot();\n if (!buffer || (!buffer.events?.length && !buffer.frames?.length && !buffer.video)) return;\n const { replayId, durationMs } = await this.transport.sendReplay(buffer);\n if (replayId) event.replay = { replayId, durationMs };\n } catch (err) {\n if (this.options.debug) console.warn('[loupfeed] replay upload failed', err);\n }\n }\n\n async flush(timeout?: number): Promise<boolean> {\n return this.transport.flush(timeout);\n }\n\n async close(timeout?: number): Promise<boolean> {\n const res = await this.transport.flush(timeout);\n this.transport.close?.();\n return res;\n }\n}\n","/**\n * The init/singleton wiring. `init()` is idempotent and safe to import on the\n * server — no DOM work happens here (the overlay mounts separately, lazily).\n */\n\nimport { Client } from './client';\nimport { configureRecorder, replay } from './replay';\nimport type { FeedbackInput, InitOptions } from './types';\n\nlet currentClient: Client | undefined;\n\nexport function init(options: InitOptions): Client {\n const client = new Client(options);\n currentClient = client;\n // Arm the session recorder when replay is enabled (sampled per replaysSampleRate).\n const replayEnabled = (options.replaysSampleRate ?? 0) > 0 || options.replay != null;\n if (replayEnabled) {\n configureRecorder({ replay: options.replay, replayBufferSeconds: options.replayBufferSeconds });\n replay.start();\n }\n if (options.debug) {\n console.debug('[loupfeed] initialized', {\n org: client.dsn.orgId,\n project: client.dsn.projectId,\n host: client.dsn.host,\n release: options.release,\n environment: options.environment,\n });\n }\n return client;\n}\n\nexport function getClient(): Client | undefined {\n return currentClient;\n}\n\nexport async function captureFeedback(input: FeedbackInput): Promise<string> {\n const client = currentClient;\n if (!client) {\n console.warn('[loupfeed] captureFeedback() called before init(); ignoring.');\n return '';\n }\n return client.captureFeedback(input);\n}\n\n/** Flush + stop. */\nexport async function close(timeout?: number): Promise<boolean> {\n if (!currentClient) return true;\n const res = await currentClient.close(timeout);\n currentClient = undefined;\n return res;\n}\n","/** Shadow-DOM stylesheet for the inspector overlay. `accent` must be 6-digit hex. */\nexport function overlayCss(accent: string): string {\n return `\n:host { all: initial; }\n* { box-sizing: border-box; }\n\n.lf-highlight {\n position: fixed;\n pointer-events: none;\n border: 2px solid ${accent};\n border-radius: 3px;\n background: ${accent}1f;\n box-shadow: 0 0 0 1px rgba(255,255,255,.45);\n z-index: 1;\n transition: left .05s, top .05s, width .05s, height .05s;\n display: none;\n}\n.lf-label {\n position: absolute;\n top: -22px;\n left: -2px;\n font: 600 11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;\n color: #fff;\n background: ${accent};\n padding: 1px 6px;\n border-radius: 3px;\n white-space: nowrap;\n pointer-events: none;\n}\n\n.lf-launcher {\n position: fixed;\n right: 16px;\n bottom: 16px;\n pointer-events: auto;\n font: 600 13px/1 ui-sans-serif, system-ui, -apple-system, sans-serif;\n color: #fff;\n background: ${accent};\n border: none;\n border-radius: 999px;\n padding: 10px 16px;\n cursor: pointer;\n box-shadow: 0 4px 14px rgba(0,0,0,.25);\n}\n.lf-launcher[data-active=\"true\"] { background: #111; }\n.lf-launcher:hover { filter: brightness(1.06); }\n\n.lf-popup {\n position: fixed;\n pointer-events: auto;\n width: 280px;\n background: #fff;\n color: #111;\n border-radius: 10px;\n box-shadow: 0 10px 40px rgba(0,0,0,.3);\n padding: 12px;\n font: 400 13px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif;\n display: none;\n z-index: 2;\n}\n.lf-popup[data-open=\"true\"] { display: block; }\n.lf-target {\n font: 600 11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;\n color: ${accent};\n margin-bottom: 6px;\n word-break: break-all;\n}\n.lf-popup textarea {\n width: 100%;\n min-height: 64px;\n resize: vertical;\n border: 1px solid #dcdce3;\n border-radius: 6px;\n padding: 8px;\n font: inherit;\n outline: none;\n}\n.lf-popup textarea:focus { border-color: ${accent}; }\n.lf-row { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }\n.lf-btn {\n font: 600 12px/1 ui-sans-serif, system-ui, -apple-system, sans-serif;\n border-radius: 6px;\n padding: 7px 12px;\n cursor: pointer;\n border: 1px solid transparent;\n}\n.lf-btn-primary { background: ${accent}; color: #fff; }\n.lf-btn-primary:disabled { opacity: .6; cursor: default; }\n.lf-btn-ghost { background: transparent; color: #555; border-color: #dcdce3; }\n.lf-sent { color: #16a34a; font-weight: 600; padding: 6px 2px; }\n`;\n}\n","/**\n * Framework-agnostic inspector overlay, rendered into a shadow root so the host\n * app's CSS can neither style nor break it. Generalizes the hit-testing core of\n * Trivision's FeedbackOverlay (elementsFromPoint + pointer-events isolation +\n * portal) into vanilla DOM with zero runtime deps.\n *\n * Capture-only by design: the in-page widget collects element-anchored feedback;\n * triage/threads/replay live in the dashboard (doc 06), not the host page.\n *\n * State machine: idle → inspect (hover-highlight) → compose (comment popup).\n */\n\nimport { isBrowser } from '../env';\nimport { setSelectorRoot, snapshotElement } from '../selector';\nimport { captureFeedback } from '../sdk';\nimport type { FeedbackInput, OverlayOptions } from '../types';\nimport { overlayCss } from './styles';\n\nexport type OverlayController = {\n open(): void;\n close(): void;\n toggleInspect(): void;\n isInspecting(): boolean;\n destroy(): void;\n};\n\ntype State = 'idle' | 'inspect' | 'compose';\n\nfunction noopController(): OverlayController {\n return {\n open() {},\n close() {},\n toggleInspect() {},\n isInspecting() {\n return false;\n },\n destroy() {},\n };\n}\n\nfunction createOverlay(opts: OverlayOptions = {}): OverlayController {\n if (!isBrowser()) return noopController();\n\n const accent = opts.accentColor ?? '#6d28d9';\n const zIndex = opts.zIndex ?? 2147483600;\n const root = opts.root ?? document.body;\n const submit = opts.onSubmit ?? ((input: FeedbackInput) => void captureFeedback(input));\n const showLauncher = opts.launcher !== false;\n\n setSelectorRoot(root);\n\n // Host is pointer-events:none so it never blocks the page; only the launcher\n // and popup re-enable pointer events. elementFromPoint therefore returns the\n // page element directly (it sees through the transparent host).\n const host = document.createElement('div');\n host.setAttribute('data-loupfeed', 'overlay');\n host.style.cssText = `position:fixed;inset:0;pointer-events:none;z-index:${zIndex};`;\n const shadow = host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = overlayCss(accent);\n shadow.append(style);\n\n const highlight = document.createElement('div');\n highlight.className = 'lf-highlight';\n const label = document.createElement('div');\n label.className = 'lf-label';\n highlight.append(label);\n shadow.append(highlight);\n\n const popup = document.createElement('div');\n popup.className = 'lf-popup';\n shadow.append(popup);\n\n let launcher: HTMLButtonElement | null = null;\n if (showLauncher) {\n launcher = document.createElement('button');\n launcher.type = 'button';\n launcher.className = 'lf-launcher';\n launcher.textContent = 'Feedback';\n launcher.addEventListener('click', () => toggleInspect());\n shadow.append(launcher);\n }\n\n document.body.append(host);\n\n let state: State = 'idle';\n let current: Element | null = null;\n\n function describe(elm: Element): string {\n const tag = elm.tagName.toLowerCase();\n const id = elm.closest('[data-fb]')?.getAttribute('data-fb');\n return id ? `${tag} · ${id}` : tag;\n }\n\n function setHighlight(elm: Element | null): void {\n if (!elm) {\n highlight.style.display = 'none';\n return;\n }\n const r = elm.getBoundingClientRect();\n highlight.style.display = 'block';\n highlight.style.left = `${r.left}px`;\n highlight.style.top = `${r.top}px`;\n highlight.style.width = `${r.width}px`;\n highlight.style.height = `${r.height}px`;\n label.textContent = describe(elm);\n }\n\n function onMove(e: MouseEvent): void {\n if (state !== 'inspect') return;\n const el = document.elementFromPoint(e.clientX, e.clientY);\n if (!el || el === host) {\n current = null;\n setHighlight(null);\n return;\n }\n current = el;\n setHighlight(el);\n }\n\n function onClick(e: MouseEvent): void {\n if (state !== 'inspect') return;\n if (e.target === host) return; // our own UI (launcher) — let it handle itself\n e.preventDefault();\n e.stopPropagation();\n const target = current ?? document.elementFromPoint(e.clientX, e.clientY);\n if (!target || target === host) return;\n openCompose(target);\n }\n\n function onKey(e: KeyboardEvent): void {\n if (e.key !== 'Escape') return;\n if (state === 'compose') {\n closeCompose();\n enterInspect();\n } else if (state === 'inspect') {\n exitInspect();\n }\n }\n\n function enterInspect(): void {\n state = 'inspect';\n if (launcher) launcher.dataset.active = 'true';\n document.addEventListener('mousemove', onMove, true);\n document.addEventListener('click', onClick, true);\n document.addEventListener('keydown', onKey, true);\n }\n\n function exitInspect(): void {\n state = 'idle';\n current = null;\n setHighlight(null);\n if (launcher) launcher.dataset.active = 'false';\n document.removeEventListener('mousemove', onMove, true);\n document.removeEventListener('click', onClick, true);\n document.removeEventListener('keydown', onKey, true);\n }\n\n function button(text: string, cls: string): HTMLButtonElement {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = cls;\n b.textContent = text;\n return b;\n }\n\n function positionPopup(r: DOMRect): void {\n const margin = 8;\n const w = 280;\n let left = r.left;\n let top = r.bottom + margin;\n if (left + w > window.innerWidth - margin) left = window.innerWidth - w - margin;\n if (left < margin) left = margin;\n if (top + 168 > window.innerHeight) top = Math.max(margin, r.top - 168);\n popup.style.left = `${left}px`;\n popup.style.top = `${top}px`;\n }\n\n function openCompose(target: Element): void {\n state = 'compose';\n current = target;\n setHighlight(target);\n // Stop tracking moves/clicks while composing; keep keydown for Escape.\n document.removeEventListener('mousemove', onMove, true);\n document.removeEventListener('click', onClick, true);\n\n const info = snapshotElement(target);\n popup.innerHTML = '';\n const targetLine = document.createElement('div');\n targetLine.className = 'lf-target';\n targetLine.textContent = info.elementId\n ? `${info.tagName} · ${info.elementId}`\n : (info.tagName ?? 'element');\n\n const textarea = document.createElement('textarea');\n textarea.placeholder = \"What's wrong with this element?\";\n\n const row = document.createElement('div');\n row.className = 'lf-row';\n const cancel = button('Cancel', 'lf-btn lf-btn-ghost');\n const send = button('Send', 'lf-btn lf-btn-primary');\n row.append(cancel, send);\n\n popup.append(targetLine, textarea, row);\n positionPopup(target.getBoundingClientRect());\n popup.dataset.open = 'true';\n setTimeout(() => textarea.focus(), 0);\n\n cancel.addEventListener('click', () => {\n closeCompose();\n enterInspect();\n });\n send.addEventListener('click', () => {\n void submitCompose(target, textarea, send);\n });\n }\n\n async function submitCompose(\n target: Element,\n textarea: HTMLTextAreaElement,\n send: HTMLButtonElement,\n ): Promise<void> {\n const text = textarea.value.trim();\n if (!text) {\n textarea.focus();\n return;\n }\n send.disabled = true;\n try {\n await submit({ text, element: target });\n } catch {\n /* delivery errors are surfaced by the transport/console */\n }\n popup.innerHTML = '<div class=\"lf-sent\">Sent ✓</div>';\n setTimeout(() => {\n closeCompose();\n exitInspect();\n }, 900);\n }\n\n function closeCompose(): void {\n popup.dataset.open = 'false';\n popup.innerHTML = '';\n if (state === 'compose') state = 'idle';\n setHighlight(null);\n }\n\n function toggleInspect(): void {\n if (state === 'idle') enterInspect();\n else {\n closeCompose();\n exitInspect();\n }\n }\n\n function open(): void {\n if (state === 'idle') enterInspect();\n }\n\n function close(): void {\n closeCompose();\n exitInspect();\n }\n\n function isInspecting(): boolean {\n return state !== 'idle';\n }\n\n function destroy(): void {\n close();\n host.remove();\n }\n\n return { open, close, toggleInspect, isInspecting, destroy };\n}\n\nlet active: OverlayController | null = null;\n\n/** Mount the overlay into the DOM. Returns an unmount function. SSR-safe (no-op). */\nexport function mountOverlay(opts?: OverlayOptions): () => void {\n const controller = createOverlay(opts);\n active = controller;\n return () => {\n controller.destroy();\n if (active === controller) active = null;\n };\n}\n\n/** Singleton control surface targeting the most recently mounted overlay. */\nexport const overlay: Omit<OverlayController, 'destroy'> = {\n open() {\n active?.open();\n },\n close() {\n active?.close();\n },\n toggleInspect() {\n active?.toggleInspect();\n },\n isInspecting() {\n return active?.isInspecting() ?? false;\n },\n};\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DSN parsing + ingest endpoint derivation.
|
|
3
|
+
*
|
|
4
|
+
* Format (Sentry-inspired):
|
|
5
|
+
* https://<PUBLIC_KEY>@<INGEST_HOST>/o/<ORG_ID>/p/<PROJECT_ID>
|
|
6
|
+
*
|
|
7
|
+
* Self-host vs SaaS is purely the host — same protocol, same packages.
|
|
8
|
+
*/
|
|
9
|
+
type Dsn = {
|
|
10
|
+
raw: string;
|
|
11
|
+
protocol: string;
|
|
12
|
+
publicKey: string;
|
|
13
|
+
/** hostname only (no port). */
|
|
14
|
+
host: string;
|
|
15
|
+
port: string;
|
|
16
|
+
orgId: string;
|
|
17
|
+
projectId: string;
|
|
18
|
+
/** `${protocol}://${host[:port]}` — no trailing slash. */
|
|
19
|
+
baseUrl: string;
|
|
20
|
+
};
|
|
21
|
+
declare function parseDsn(dsn: string): Dsn;
|
|
22
|
+
declare function eventsUrl(dsn: Dsn): string;
|
|
23
|
+
declare function replaysUrl(dsn: Dsn): string;
|
|
24
|
+
declare function manifestsUrl(dsn: Dsn): string;
|
|
25
|
+
declare function resolveUrl(dsn: Dsn): string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Public type surface for @loupfeed/core. The on-the-wire `FeedbackEvent` is
|
|
29
|
+
* specified in docs/04-context-api.md (§The FeedbackEvent envelope).
|
|
30
|
+
*/
|
|
31
|
+
/** Allowed tag values. `null`/`undefined` are dropped at serialization. */
|
|
32
|
+
type Primitive = string | number | boolean | null | undefined;
|
|
33
|
+
type User = {
|
|
34
|
+
id?: string;
|
|
35
|
+
email?: string;
|
|
36
|
+
username?: string;
|
|
37
|
+
ip_address?: string;
|
|
38
|
+
/** Arbitrary developer-supplied fields (plan, role, …). */
|
|
39
|
+
[key: string]: unknown;
|
|
40
|
+
};
|
|
41
|
+
type BreadcrumbLevel = 'debug' | 'info' | 'warning' | 'error';
|
|
42
|
+
type Breadcrumb = {
|
|
43
|
+
/** ISO timestamp; filled in automatically if omitted. */
|
|
44
|
+
timestamp?: string;
|
|
45
|
+
/** 'navigation' | 'ui.click' | 'http' | 'console' | custom. */
|
|
46
|
+
category: string;
|
|
47
|
+
type?: string;
|
|
48
|
+
message?: string;
|
|
49
|
+
level?: BreadcrumbLevel;
|
|
50
|
+
data?: Record<string, unknown>;
|
|
51
|
+
};
|
|
52
|
+
type ElementRect = {
|
|
53
|
+
x: number;
|
|
54
|
+
y: number;
|
|
55
|
+
w: number;
|
|
56
|
+
h: number;
|
|
57
|
+
};
|
|
58
|
+
/** Element anchor captured by the selector engine. */
|
|
59
|
+
type ElementInfo = {
|
|
60
|
+
/** data-fb-id | structural CSS path, relative to the selector root. */
|
|
61
|
+
selector: string;
|
|
62
|
+
/** Opaque build-injected `data-fb` id → resolves to src:line server-side. */
|
|
63
|
+
elementId?: string;
|
|
64
|
+
tagName?: string;
|
|
65
|
+
/** Truncated, masking-aware. */
|
|
66
|
+
text?: string;
|
|
67
|
+
rect?: ElementRect;
|
|
68
|
+
};
|
|
69
|
+
type FeedbackInput = {
|
|
70
|
+
text: string;
|
|
71
|
+
/** The clicked DOM element (the web overlay supplies it). */
|
|
72
|
+
element?: Element;
|
|
73
|
+
/** Non-DOM platforms (React Native) supply the opaque id directly. */
|
|
74
|
+
elementId?: string;
|
|
75
|
+
/** Non-DOM platforms supply a prebuilt anchor (tag/rect/selector) directly. */
|
|
76
|
+
elementInfo?: Partial<ElementInfo>;
|
|
77
|
+
/** Screenshots etc. (uploaded separately by the transport). */
|
|
78
|
+
attachments?: Blob[];
|
|
79
|
+
};
|
|
80
|
+
type AttachmentRef = {
|
|
81
|
+
type: 'image';
|
|
82
|
+
blobId: string;
|
|
83
|
+
};
|
|
84
|
+
/** The on-the-wire envelope ingested by the backend. */
|
|
85
|
+
type FeedbackEvent = {
|
|
86
|
+
eventId: string;
|
|
87
|
+
timestamp: string;
|
|
88
|
+
/** version@commit — the manifest join key. */
|
|
89
|
+
release: string;
|
|
90
|
+
environment: string;
|
|
91
|
+
text: string;
|
|
92
|
+
attachments?: AttachmentRef[];
|
|
93
|
+
element: ElementInfo;
|
|
94
|
+
user?: User;
|
|
95
|
+
contexts?: Record<string, Record<string, unknown>>;
|
|
96
|
+
tags?: Record<string, string | number | boolean>;
|
|
97
|
+
breadcrumbs?: Breadcrumb[];
|
|
98
|
+
request?: {
|
|
99
|
+
url: string;
|
|
100
|
+
route?: string;
|
|
101
|
+
};
|
|
102
|
+
replay?: {
|
|
103
|
+
replayId: string;
|
|
104
|
+
durationMs: number;
|
|
105
|
+
};
|
|
106
|
+
sdk?: {
|
|
107
|
+
name: string;
|
|
108
|
+
version: string;
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
/** Session-replay masking config (replay itself is deferred out of MVP). */
|
|
112
|
+
type ReplayOptions = {
|
|
113
|
+
maskAllText?: boolean;
|
|
114
|
+
maskAllInputs?: boolean;
|
|
115
|
+
blockSelector?: string;
|
|
116
|
+
maskTextSelector?: string;
|
|
117
|
+
};
|
|
118
|
+
type ReplayBuffer = {
|
|
119
|
+
replayId: string;
|
|
120
|
+
durationMs: number;
|
|
121
|
+
/**
|
|
122
|
+
* Replay codec:
|
|
123
|
+
* - 'rrweb' — web DOM (default)
|
|
124
|
+
* - 'wireframe' — React Native view-hierarchy snapshots (maskable, pure-JS)
|
|
125
|
+
* - 'video' — native screen recording (optional, pixels)
|
|
126
|
+
*/
|
|
127
|
+
kind?: 'rrweb' | 'wireframe' | 'video';
|
|
128
|
+
/** rrweb events (kind: 'rrweb'). */
|
|
129
|
+
events?: unknown[];
|
|
130
|
+
/** view-hierarchy frames (kind: 'wireframe'). */
|
|
131
|
+
frames?: unknown[];
|
|
132
|
+
/** recorded viewport, for wireframe reconstruction. */
|
|
133
|
+
viewport?: {
|
|
134
|
+
width: number;
|
|
135
|
+
height: number;
|
|
136
|
+
};
|
|
137
|
+
/** base64-encoded video (kind: 'video'). */
|
|
138
|
+
video?: string;
|
|
139
|
+
mimeType?: string;
|
|
140
|
+
};
|
|
141
|
+
/** Pluggable session recorder. Web = rrweb; React Native = native screen capture. */
|
|
142
|
+
interface Recorder {
|
|
143
|
+
start(): void;
|
|
144
|
+
stop(): void;
|
|
145
|
+
isRecording(): boolean;
|
|
146
|
+
/** Freeze the rolling buffer for the current event (may be async for native capture). */
|
|
147
|
+
snapshot(): ReplayBuffer | Promise<ReplayBuffer>;
|
|
148
|
+
}
|
|
149
|
+
/** Pluggable transport — override for self-host / proxy. */
|
|
150
|
+
interface Transport {
|
|
151
|
+
/** Send one event; resolves with the server-assigned eventId. */
|
|
152
|
+
send(event: FeedbackEvent): Promise<string>;
|
|
153
|
+
/** Upload a frozen replay buffer; resolves with its id + duration. */
|
|
154
|
+
sendReplay?(buffer: ReplayBuffer): Promise<{
|
|
155
|
+
replayId: string;
|
|
156
|
+
durationMs: number;
|
|
157
|
+
}>;
|
|
158
|
+
/** Wait for in-flight sends to settle (up to `timeout` ms). */
|
|
159
|
+
flush(timeout?: number): Promise<boolean>;
|
|
160
|
+
close?(): void;
|
|
161
|
+
}
|
|
162
|
+
type InitOptions = {
|
|
163
|
+
dsn: string;
|
|
164
|
+
environment?: string;
|
|
165
|
+
/** version@commit; build plugin can inject this. Defaults to ''. */
|
|
166
|
+
release?: string;
|
|
167
|
+
/** Fraction of feedbacks that attach a replay. 0..1. (Replay deferred.) */
|
|
168
|
+
replaysSampleRate?: number;
|
|
169
|
+
/** Rolling replay buffer length in seconds. Default 30. (Replay deferred.) */
|
|
170
|
+
replayBufferSeconds?: number;
|
|
171
|
+
replay?: ReplayOptions;
|
|
172
|
+
/** Auto-attach route, viewport, release. Default true. */
|
|
173
|
+
autoContext?: boolean;
|
|
174
|
+
/** Max breadcrumbs retained on the global scope. Default 50. */
|
|
175
|
+
maxBreadcrumbs?: number;
|
|
176
|
+
/** Last-chance scrub. Return null to drop the event. */
|
|
177
|
+
beforeSend?: (event: FeedbackEvent) => FeedbackEvent | null;
|
|
178
|
+
/** Override the transport (self-host / proxy / testing). */
|
|
179
|
+
transport?: Transport;
|
|
180
|
+
debug?: boolean;
|
|
181
|
+
};
|
|
182
|
+
type OverlayOptions = {
|
|
183
|
+
/** Root the selector engine generates paths relative to. Defaults to body. */
|
|
184
|
+
root?: Element | null;
|
|
185
|
+
/** Called when a user submits feedback. Defaults to core's `captureFeedback`. */
|
|
186
|
+
onSubmit?: (input: FeedbackInput) => void | Promise<void>;
|
|
187
|
+
/** Accent color (6-digit hex). Default '#6d28d9'. */
|
|
188
|
+
accentColor?: string;
|
|
189
|
+
/** z-index of the overlay host. Default 2147483600. */
|
|
190
|
+
zIndex?: number;
|
|
191
|
+
/** Show the built-in floating launcher button. Default true. */
|
|
192
|
+
launcher?: boolean;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Client — holds the parsed DSN, normalized options, and the transport. Owns
|
|
197
|
+
* `captureFeedback`: it builds the event from the active scope and sends it.
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
declare class Client {
|
|
201
|
+
readonly dsn: Dsn;
|
|
202
|
+
private readonly options;
|
|
203
|
+
private readonly transport;
|
|
204
|
+
constructor(options: InitOptions);
|
|
205
|
+
getOptions(): InitOptions;
|
|
206
|
+
getDsn(): Dsn;
|
|
207
|
+
getTransport(): Transport;
|
|
208
|
+
captureFeedback(input: FeedbackInput): Promise<string>;
|
|
209
|
+
private maybeAttachReplay;
|
|
210
|
+
flush(timeout?: number): Promise<boolean>;
|
|
211
|
+
close(timeout?: number): Promise<boolean>;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* The init/singleton wiring. `init()` is idempotent and safe to import on the
|
|
216
|
+
* server — no DOM work happens here (the overlay mounts separately, lazily).
|
|
217
|
+
*/
|
|
218
|
+
|
|
219
|
+
declare function init(options: InitOptions): Client;
|
|
220
|
+
declare function getClient(): Client | undefined;
|
|
221
|
+
declare function captureFeedback(input: FeedbackInput): Promise<string>;
|
|
222
|
+
/** Flush + stop. */
|
|
223
|
+
declare function close(timeout?: number): Promise<boolean>;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Scope / context API — generalizes what Trivision's FeedbackProvider hard-codes
|
|
227
|
+
* (tenant/rep/version) into a Sentry-style developer-driven API.
|
|
228
|
+
*
|
|
229
|
+
* - The global scope holds long-lived data (user, tags, persistent contexts).
|
|
230
|
+
* - `withScope(cb)` forks a child for a single capture without polluting global.
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
interface ScopeData {
|
|
234
|
+
user?: User;
|
|
235
|
+
tags: Record<string, Primitive>;
|
|
236
|
+
contexts: Record<string, Record<string, unknown>>;
|
|
237
|
+
breadcrumbs: Breadcrumb[];
|
|
238
|
+
}
|
|
239
|
+
declare class Scope {
|
|
240
|
+
private _user?;
|
|
241
|
+
private _tags;
|
|
242
|
+
private _contexts;
|
|
243
|
+
private _breadcrumbs;
|
|
244
|
+
private _maxBreadcrumbs;
|
|
245
|
+
setUser(user: User | null): this;
|
|
246
|
+
getUser(): User | undefined;
|
|
247
|
+
setTag(key: string, value: Primitive): this;
|
|
248
|
+
setTags(tags: Record<string, Primitive>): this;
|
|
249
|
+
setContext(key: string, data: Record<string, unknown> | null): this;
|
|
250
|
+
addBreadcrumb(breadcrumb: Breadcrumb, maxBreadcrumbs?: number): this;
|
|
251
|
+
setMaxBreadcrumbs(n: number): this;
|
|
252
|
+
clearBreadcrumbs(): this;
|
|
253
|
+
clone(): Scope;
|
|
254
|
+
getScopeData(): ScopeData;
|
|
255
|
+
}
|
|
256
|
+
declare function getGlobalScope(): Scope;
|
|
257
|
+
/** The active scope: the top of the withScope stack, else the global scope. */
|
|
258
|
+
declare function getCurrentScope(): Scope;
|
|
259
|
+
/** Fork a child scope for a single capture; auto-popped when `cb` returns. */
|
|
260
|
+
declare function withScope<T>(cb: (scope: Scope) => T): T;
|
|
261
|
+
declare function setUser(user: User | null): void;
|
|
262
|
+
declare function setContext(key: string, data: Record<string, unknown> | null): void;
|
|
263
|
+
declare function setTag(key: string, value: Primitive): void;
|
|
264
|
+
declare function setTags(tags: Record<string, Primitive>): void;
|
|
265
|
+
declare function addBreadcrumb(breadcrumb: Breadcrumb): void;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Session recorder — wraps rrweb behind loupfeed's own rolling-buffer + masking
|
|
269
|
+
* lifecycle (docs/05). We own the masking *defaults* (mask-by-default), the ring
|
|
270
|
+
* buffer, and the upload lifecycle; rrweb is just the DOM codec, swappable later.
|
|
271
|
+
*
|
|
272
|
+
* rrweb is loaded with a real dynamic import so it (a) stays out of apps that
|
|
273
|
+
* don't enable replay (tree-shakeable / lazy) and (b) is bundler-resolved on web.
|
|
274
|
+
* React Native uses a native recorder instead and stubs `rrweb` in Metro.
|
|
275
|
+
*/
|
|
276
|
+
|
|
277
|
+
/** The public `replay` API (re-exported from core's index). */
|
|
278
|
+
declare const replay: {
|
|
279
|
+
start(): void;
|
|
280
|
+
stop(): void;
|
|
281
|
+
isRecording(): boolean;
|
|
282
|
+
/** Freeze the rolling buffer for the current event. */
|
|
283
|
+
snapshot(): ReplayBuffer;
|
|
284
|
+
};
|
|
285
|
+
declare function setReplayRecorder(recorder: Recorder | null): void;
|
|
286
|
+
declare function getActiveRecorder(): Recorder;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Element-identification engine (lifted + generalized from the Trivision
|
|
290
|
+
* `app/src/feedback/selector.ts`). Produces an identifier per element that:
|
|
291
|
+
* 1. Survives re-renders within a session
|
|
292
|
+
* 2. Survives a page refresh (comments persist across reloads)
|
|
293
|
+
* 3. Tolerates minor markup changes between deploys (best-effort)
|
|
294
|
+
*
|
|
295
|
+
* Three-tier resolution, in priority order:
|
|
296
|
+
* 1. el.closest('[data-fb-id]') → hand-authored stable id
|
|
297
|
+
* 2. el.closest('[data-fb]') → opaque build-injected id → manifest (src:line)
|
|
298
|
+
* 3. structural CSS path → tag + :nth-of-type(n), relative to the root
|
|
299
|
+
*
|
|
300
|
+
* The opaque `data-fb` id never carries a source path; it resolves to
|
|
301
|
+
* `<rel-path>:<line>` server-side via the manifest. The client never sees paths.
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
declare function setSelectorRoot(el: Element | null): void;
|
|
305
|
+
declare function getSelectorRoot(): Element | null;
|
|
306
|
+
/** Generate a stable selector for an element, relative to the root. */
|
|
307
|
+
declare function selectorFor(el: Element): string;
|
|
308
|
+
/** Try to resolve a stored selector back to a live element. */
|
|
309
|
+
declare function resolveSelector(selector: string): Element | null;
|
|
310
|
+
/** Snapshot an element's identity + display metadata at click time. */
|
|
311
|
+
declare function snapshotElement(el: Element): ElementInfo;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Framework-agnostic inspector overlay, rendered into a shadow root so the host
|
|
315
|
+
* app's CSS can neither style nor break it. Generalizes the hit-testing core of
|
|
316
|
+
* Trivision's FeedbackOverlay (elementsFromPoint + pointer-events isolation +
|
|
317
|
+
* portal) into vanilla DOM with zero runtime deps.
|
|
318
|
+
*
|
|
319
|
+
* Capture-only by design: the in-page widget collects element-anchored feedback;
|
|
320
|
+
* triage/threads/replay live in the dashboard (doc 06), not the host page.
|
|
321
|
+
*
|
|
322
|
+
* State machine: idle → inspect (hover-highlight) → compose (comment popup).
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
type OverlayController = {
|
|
326
|
+
open(): void;
|
|
327
|
+
close(): void;
|
|
328
|
+
toggleInspect(): void;
|
|
329
|
+
isInspecting(): boolean;
|
|
330
|
+
destroy(): void;
|
|
331
|
+
};
|
|
332
|
+
/** Mount the overlay into the DOM. Returns an unmount function. SSR-safe (no-op). */
|
|
333
|
+
declare function mountOverlay(opts?: OverlayOptions): () => void;
|
|
334
|
+
/** Singleton control surface targeting the most recently mounted overlay. */
|
|
335
|
+
declare const overlay: Omit<OverlayController, 'destroy'>;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Fetch transport — POSTs the FeedbackEvent envelope (and, when present, the
|
|
339
|
+
* replay blob) to the DSN-derived ingest endpoints. Retries on network / 5xx,
|
|
340
|
+
* tracks in-flight sends for flush(), and uses `keepalive` so a submit can
|
|
341
|
+
* outlive an unload.
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
declare function makeFetchTransport(dsn: Dsn, opts?: {
|
|
345
|
+
debug?: boolean;
|
|
346
|
+
}): Transport;
|
|
347
|
+
|
|
348
|
+
/** SDK version, surfaced on every event's `sdk` field. Bumped by Changesets. */
|
|
349
|
+
declare const SDK_VERSION = "0.0.0";
|
|
350
|
+
|
|
351
|
+
export { type AttachmentRef, type Breadcrumb, type BreadcrumbLevel, Client, type Dsn, type ElementInfo, type ElementRect, type FeedbackEvent, type FeedbackInput, type InitOptions, type OverlayController, type OverlayOptions, type Primitive, type Recorder, type ReplayBuffer, type ReplayOptions, SDK_VERSION, Scope, type ScopeData, type Transport, type User, addBreadcrumb, captureFeedback, close, eventsUrl, getActiveRecorder, getClient, getCurrentScope, getGlobalScope, getSelectorRoot, init, makeFetchTransport, manifestsUrl, mountOverlay, overlay, parseDsn, replay, replaysUrl, resolveSelector, resolveUrl, selectorFor, setContext, setReplayRecorder, setSelectorRoot, setTag, setTags, setUser, snapshotElement, withScope };
|