reflet-sdk 0.1.4 → 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback.js","names":["toBlob"],"sources":["../src/feedback/core/capture.ts","../src/feedback/core/react-source.ts","../src/feedback/core/element-selector.ts","../src/feedback/core/page-context.ts","../src/feedback/types.ts","../src/feedback/core/annotations.ts","../src/feedback/core/annotation-renderer.ts","../src/feedback/ui/icons.tsx","../src/feedback/ui/annotator.tsx","../src/feedback/ui/launcher.tsx","../src/feedback/ui/panel.tsx","../src/feedback/ui/picker.tsx","../src/feedback/ui/styles.ts","../src/feedback/ui/shadow-portal.tsx","../src/feedback/core/console-recorder.ts","../src/feedback/core/submit.ts","../src/feedback/ui/use-widget-state.ts","../src/feedback/widget.tsx"],"sourcesContent":["import type { CapturedImage } from \"../types\";\n\n/** Marks every node the widget owns, so captures never include the panel. */\nexport const WIDGET_MARKER = \"data-reflet-widget\";\n\nconst MAX_PIXEL_RATIO = 2;\nconst DEFAULT_MAX_WIDTH = 2400;\n\nexport interface CaptureOptions {\n /** Capture this element instead of the visible viewport. */\n element?: Element;\n excludeSelectors?: string[];\n maxWidth?: number;\n}\n\ninterface SnapdomOptions {\n cache: \"disabled\";\n clip?: \"viewport\";\n dpr: number;\n embedFonts: boolean;\n exclude: string[];\n fast: boolean;\n}\n\nexport function buildSnapdomOptions(options: {\n devicePixelRatio?: number;\n element?: Element;\n excludeSelectors?: string[];\n}): SnapdomOptions {\n const ratio = options.devicePixelRatio ?? 1;\n\n return {\n cache: \"disabled\",\n clip: options.element ? undefined : \"viewport\",\n dpr: Math.min(Math.max(ratio || 1, 1), MAX_PIXEL_RATIO),\n embedFonts: true,\n exclude: [`[${WIDGET_MARKER}]`, ...(options.excludeSelectors ?? [])],\n fast: true,\n };\n}\n\nexport function fitWithin(\n size: { height: number; width: number },\n maxWidth: number\n): { height: number; scale: number; width: number } {\n if (size.width <= maxWidth) {\n return { height: size.height, scale: 1, width: size.width };\n }\n\n const scale = maxWidth / size.width;\n return {\n height: Math.max(1, Math.round(size.height * scale)),\n scale,\n width: maxWidth,\n };\n}\n\nfunction toBlob(canvas: HTMLCanvasElement): Promise<Blob | null> {\n return new Promise((resolve) => {\n canvas.toBlob(resolve, \"image/png\");\n });\n}\n\nfunction downscale(\n canvas: HTMLCanvasElement,\n target: { height: number; width: number }\n): HTMLCanvasElement {\n const resized = document.createElement(\"canvas\");\n resized.width = target.width;\n resized.height = target.height;\n\n const context = resized.getContext(\"2d\");\n if (!context) {\n return canvas;\n }\n\n context.imageSmoothingQuality = \"high\";\n context.drawImage(canvas, 0, 0, target.width, target.height);\n return resized;\n}\n\n/**\n * Renders what the user is looking at right now.\n *\n * Runs off the DOM rather than `getDisplayMedia` on purpose: a screen-share\n * permission prompt on every report would cost more reports than it captures.\n * Returns null instead of throwing — a screenshot is never worth losing the\n * written feedback.\n */\nexport async function captureViewport(\n options: CaptureOptions = {}\n): Promise<CapturedImage | null> {\n try {\n const { snapdom } = await import(\"@zumer/snapdom\");\n const target = options.element ?? document.documentElement;\n\n const canvas = await snapdom.toCanvas(\n target,\n buildSnapdomOptions({\n devicePixelRatio: window.devicePixelRatio,\n element: options.element,\n excludeSelectors: options.excludeSelectors,\n })\n );\n\n const fitted = fitWithin(\n { height: canvas.height, width: canvas.width },\n options.maxWidth ?? DEFAULT_MAX_WIDTH\n );\n const output = fitted.scale === 1 ? canvas : downscale(canvas, fitted);\n\n const blob = await toBlob(output);\n if (!blob) {\n return null;\n }\n\n return {\n blob,\n height: output.height,\n mimeType: \"image/png\",\n objectUrl: URL.createObjectURL(blob),\n width: output.width,\n };\n } catch {\n return null;\n }\n}\n\nexport function releaseCapture(image: CapturedImage | null | undefined): void {\n if (image) {\n URL.revokeObjectURL(image.objectUrl);\n }\n}\n","const FIBER_KEY_PREFIXES = [\"__reactFiber$\", \"__reactInternalInstance$\"];\nconst MEMO_TYPE = Symbol.for(\"react.memo\");\nconst FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\");\n\nconst MAX_STACK_DEPTH = 6;\nconst MAX_FIBER_WALK = 60;\nconst MAX_OWNER_WALK = 8;\n\nconst ORIGIN_PREFIX = /^[a-z][\\w+.-]*:\\/\\/[^/]*/i;\nconst WEBPACK_PREFIX = /^webpack-internal:\\/{2,}(\\.\\/)?/;\nconst STACK_LOCATION = /([^\\s()]+):(\\d+):(\\d+)\\)?\\s*$/;\nconst NON_SOURCE_FRAME =\n /node_modules|\\/_next\\/|\\/chunks?\\/|\\/\\.vite\\/|\\/dist\\/|\\/build\\/|hot-update/;\nconst SOURCE_EXTENSION = /\\.(?:[cm]?[jt]sx?)$/;\nconst SOURCE_ROOT_MARKERS = [\n \"src\",\n \"app\",\n \"pages\",\n \"components\",\n \"features\",\n \"lib\",\n];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\n/** React attaches the fiber under a randomly suffixed key on the host node. */\nexport function getFiberFromNode(node: Node): unknown {\n for (const key of Object.getOwnPropertyNames(node)) {\n for (const prefix of FIBER_KEY_PREFIXES) {\n if (key.startsWith(prefix)) {\n return Reflect.get(node, key) ?? null;\n }\n }\n }\n return null;\n}\n\nfunction readName(value: unknown): string | null {\n if (typeof value !== \"function\" && !isRecord(value)) {\n return null;\n }\n\n const displayName = Reflect.get(value, \"displayName\");\n if (typeof displayName === \"string\" && displayName) {\n return displayName;\n }\n\n const name = Reflect.get(value, \"name\");\n return typeof name === \"string\" && name ? name : null;\n}\n\nfunction componentName(type: unknown, depth = 0): string | null {\n if (typeof type === \"string\" || type === null || depth > 3) {\n return null;\n }\n\n if (isRecord(type)) {\n const marker = Reflect.get(type, \"$$typeof\");\n if (marker === MEMO_TYPE) {\n return componentName(Reflect.get(type, \"type\"), depth + 1);\n }\n if (marker === FORWARD_REF_TYPE) {\n return componentName(Reflect.get(type, \"render\"), depth + 1);\n }\n }\n\n const name = readName(type);\n if (!name || name.length < 2) {\n return null;\n }\n\n const isMeaningful = name[0] === name[0]?.toUpperCase() || name.includes(\"/\");\n return isMeaningful ? name : null;\n}\n\n/** Component names owning the fiber, innermost first. */\nexport function resolveComponentStack(fiber: unknown): string[] {\n const stack: string[] = [];\n let current = fiber;\n let steps = 0;\n\n while (isRecord(current) && steps < MAX_FIBER_WALK) {\n const name =\n componentName(Reflect.get(current, \"type\")) ??\n componentName(Reflect.get(current, \"elementType\"));\n\n if (name && stack.at(-1) !== name) {\n stack.push(name);\n if (stack.length >= MAX_STACK_DEPTH) {\n break;\n }\n }\n\n current = Reflect.get(current, \"return\");\n steps++;\n }\n\n return stack;\n}\n\nfunction shortenSourcePath(raw: string): string {\n const path = raw\n .replace(WEBPACK_PREFIX, \"\")\n .replace(ORIGIN_PREFIX, \"\")\n .split(\"?\")[0];\n if (!path) {\n return raw;\n }\n\n for (const marker of SOURCE_ROOT_MARKERS) {\n if (path.startsWith(`${marker}/`)) {\n return path;\n }\n const index = path.lastIndexOf(`/${marker}/`);\n if (index !== -1) {\n return path.slice(index + 1);\n }\n }\n\n return path.split(\"/\").filter(Boolean).slice(-3).join(\"/\");\n}\n\nfunction formatLocation(\n fileName: string,\n line: number,\n column?: number\n): string {\n const base = `${shortenSourcePath(fileName)}:${line}`;\n return column === undefined ? base : `${base}:${column}`;\n}\n\nfunction fromDebugSource(source: unknown): string | undefined {\n if (!isRecord(source)) {\n return;\n }\n\n const fileName = Reflect.get(source, \"fileName\");\n const lineNumber = Reflect.get(source, \"lineNumber\");\n if (typeof fileName !== \"string\" || typeof lineNumber !== \"number\") {\n return;\n }\n\n const columnNumber = Reflect.get(source, \"columnNumber\");\n return formatLocation(\n fileName,\n lineNumber,\n typeof columnNumber === \"number\" ? columnNumber : undefined\n );\n}\n\nfunction fromDebugStack(stack: unknown): string | undefined {\n const raw = isRecord(stack) ? Reflect.get(stack, \"stack\") : stack;\n if (typeof raw !== \"string\") {\n return;\n }\n\n for (const line of raw.split(\"\\n\")) {\n const match = STACK_LOCATION.exec(line);\n const file = match?.[1];\n if (!(match && file) || NON_SOURCE_FRAME.test(file)) {\n continue;\n }\n\n const path = file.replace(ORIGIN_PREFIX, \"\").split(\"?\")[0] ?? \"\";\n if (!SOURCE_EXTENSION.test(path)) {\n continue;\n }\n\n return formatLocation(path, Number(match[2]), Number(match[3]));\n }\n}\n\n/**\n * `src/components/login-form.tsx:46:19` when the React build exposes it.\n * Production bundles strip debug info — callers must treat this as optional.\n */\nexport function resolveSourceLocation(fiber: unknown): string | undefined {\n let current = fiber;\n let steps = 0;\n\n while (isRecord(current) && steps < MAX_OWNER_WALK) {\n const located =\n fromDebugSource(Reflect.get(current, \"_debugSource\")) ??\n fromDebugStack(Reflect.get(current, \"_debugStack\"));\n if (located) {\n return located;\n }\n\n current = Reflect.get(current, \"_debugOwner\");\n steps++;\n }\n}\n\nexport function inspectReactElement(element: Element): {\n componentStack: string[];\n sourceLocation?: string;\n} {\n const fiber = getFiberFromNode(element);\n return {\n componentStack: resolveComponentStack(fiber),\n sourceLocation: resolveSourceLocation(fiber),\n };\n}\n","import type { ElementRect, ElementSelection } from \"../../types\";\nimport { inspectReactElement } from \"./react-source\";\n\nconst SAFE_ID = /^[A-Za-z][\\w-]*$/;\nconst WHITESPACE = /\\s+/g;\nconst MAX_LABEL_LENGTH = 80;\nconst MAX_HTML_LENGTH = 600;\nconst MAX_DEPTH = 12;\n// Hard caps enforced by POST /api/v1/feedback/create — over them the whole\n// report is rejected, so clip here rather than lose the submission.\nconst MAX_SELECTOR_LENGTH = 600;\nconst MAX_SOURCE_LOCATION_LENGTH = 400;\n\nfunction isUnique(selector: string): boolean {\n try {\n return document.querySelectorAll(selector).length === 1;\n } catch {\n return false;\n }\n}\n\nfunction escapeAttributeValue(value: string): string {\n return value.replace(/[\"\\\\]/g, \"\\\\$&\");\n}\n\nfunction uniqueHandle(element: Element): string | null {\n const id = element.getAttribute(\"id\");\n if (id && SAFE_ID.test(id) && isUnique(`#${id}`)) {\n return `#${id}`;\n }\n\n const testId = element.getAttribute(\"data-testid\");\n if (testId) {\n const selector = `[data-testid=\"${escapeAttributeValue(testId)}\"]`;\n if (isUnique(selector)) {\n return selector;\n }\n }\n\n return null;\n}\n\nfunction positionalSegment(element: Element): string {\n const tag = element.localName;\n const parent = element.parentElement;\n if (!parent) {\n return tag;\n }\n\n const sameTag = Array.from(parent.children).filter(\n (child) => child.localName === tag\n );\n if (sameTag.length <= 1) {\n return tag;\n }\n\n return `${tag}:nth-of-type(${sameTag.indexOf(element) + 1})`;\n}\n\n/**\n * Shortest selector that still resolves back to `element` from the document.\n */\nexport function buildSelector(element: Element): string {\n if (element === document.documentElement) {\n return \"html\";\n }\n if (element === document.body) {\n return \"body\";\n }\n\n const handle = uniqueHandle(element);\n if (handle) {\n return handle;\n }\n\n const segments: string[] = [];\n let current: Element | null = element;\n let depth = 0;\n\n while (current && depth < MAX_DEPTH) {\n if (current === document.body) {\n segments.unshift(\"body\");\n break;\n }\n if (current === document.documentElement) {\n segments.unshift(\"html\");\n break;\n }\n\n const ancestorHandle = current === element ? null : uniqueHandle(current);\n if (ancestorHandle) {\n segments.unshift(ancestorHandle);\n break;\n }\n\n segments.unshift(positionalSegment(current));\n current = current.parentElement;\n depth++;\n }\n\n return segments.join(\" > \");\n}\n\nfunction truncate(value: string, max: number): string {\n return value.length <= max ? value : `${value.slice(0, max - 1)}…`;\n}\n\nfunction accessibleLabel(element: Element): string {\n const explicit =\n element.getAttribute(\"aria-label\") ??\n element.getAttribute(\"title\") ??\n element.getAttribute(\"alt\") ??\n element.getAttribute(\"placeholder\");\n if (explicit?.trim()) {\n return explicit.trim();\n }\n\n return (element.textContent ?? \"\").replace(WHITESPACE, \" \").trim();\n}\n\n/** Short human label such as `button \"Sign in\"` or `div.card`. */\nexport function describeElement(element: Element): string {\n const tag = element.localName;\n const label = accessibleLabel(element);\n if (label) {\n return truncate(`${tag} \"${label}\"`, MAX_LABEL_LENGTH);\n }\n\n const firstClass = element.classList.item(0);\n return truncate(firstClass ? `${tag}.${firstClass}` : tag, MAX_LABEL_LENGTH);\n}\n\nexport function getElementRect(element: Element): ElementRect {\n const rect = element.getBoundingClientRect();\n return {\n height: Math.round(rect.height),\n width: Math.round(rect.width),\n x: Math.round(rect.x),\n y: Math.round(rect.y),\n };\n}\n\n/** Everything an agent needs to find the picked element back in the codebase. */\nexport function buildElementSelection(element: Element): ElementSelection {\n const { componentStack, sourceLocation } = inspectReactElement(element);\n\n return {\n componentStack,\n html: truncate(element.outerHTML, MAX_HTML_LENGTH),\n label: describeElement(element),\n rect: getElementRect(element),\n selector: truncate(buildSelector(element), MAX_SELECTOR_LENGTH),\n sourceLocation: sourceLocation\n ? truncate(sourceLocation, MAX_SOURCE_LOCATION_LENGTH)\n : sourceLocation,\n };\n}\n","import type { FeedbackContext } from \"../../types\";\n\ninterface AgentInfo {\n browser?: string;\n device: \"desktop\" | \"mobile\" | \"tablet\";\n os?: string;\n}\n\nconst BROWSER_PATTERNS: [string, RegExp][] = [\n [\"Edge\", /Edg(?:e|A|iOS)?\\/([\\d.]+)/],\n [\"Opera\", /OPR\\/([\\d.]+)/],\n [\"Samsung Internet\", /SamsungBrowser\\/([\\d.]+)/],\n [\"Firefox\", /(?:Firefox|FxiOS)\\/([\\d.]+)/],\n [\"Chrome\", /(?:Chrome|CriOS)\\/([\\d.]+)/],\n [\"Safari\", /Version\\/([\\d.]+).*Safari/],\n];\n\nconst OS_PATTERNS: [string, RegExp][] = [\n [\"iOS\", /iPhone|iPad|iPod/],\n [\"Android\", /Android/],\n [\"Windows\", /Windows NT/],\n [\"macOS\", /Mac OS X|Macintosh/],\n [\"ChromeOS\", /CrOS/],\n [\"Linux\", /Linux|X11/],\n];\n\nconst MOBILE_HINT = /Mobile|iPhone|iPod/;\nconst TABLET_HINT = /iPad|Tablet/;\nconst TRAILING_ZERO = /\\.0$/;\nconst ANDROID = /Android/;\n\nfunction shortenVersion(version: string): string {\n return version.split(\".\").slice(0, 2).join(\".\").replace(TRAILING_ZERO, \"\");\n}\n\nfunction detectDevice(userAgent: string): AgentInfo[\"device\"] {\n if (TABLET_HINT.test(userAgent)) {\n return \"tablet\";\n }\n if (MOBILE_HINT.test(userAgent)) {\n return \"mobile\";\n }\n return ANDROID.test(userAgent) ? \"tablet\" : \"desktop\";\n}\n\nexport function parseUserAgent(userAgent: string): AgentInfo {\n const info: AgentInfo = { device: detectDevice(userAgent) };\n\n for (const [name, pattern] of BROWSER_PATTERNS) {\n const version = pattern.exec(userAgent)?.[1];\n if (version) {\n info.browser = `${name} ${shortenVersion(version)}`;\n break;\n }\n }\n\n for (const [name, pattern] of OS_PATTERNS) {\n if (pattern.test(userAgent)) {\n info.os = name;\n break;\n }\n }\n\n return info;\n}\n\n// Hard caps enforced by POST /api/v1/feedback/create — over them the whole\n// report is rejected, so clip here rather than lose the submission.\nconst MAX_PAGE_TITLE_LENGTH = 300;\nconst MAX_URL_LENGTH = 2000;\nconst MAX_USER_AGENT_LENGTH = 600;\n\nfunction clip(value: string, max: number): string {\n return value.length <= max ? value : value.slice(0, max);\n}\n\nfunction optionalText(\n value: string | undefined,\n max: number\n): string | undefined {\n return value?.trim() ? clip(value, max) : undefined;\n}\n\nfunction resolveTimezone(): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n } catch {\n // Intl missing in some embedded webviews\n }\n}\n\n/** Everything about the page that a bug report needs and the DOM already knows. */\nexport function collectPageContext(options?: {\n sdkVersion?: string;\n}): FeedbackContext {\n const userAgent = navigator.userAgent;\n const agent = parseUserAgent(userAgent);\n\n return {\n browser: agent.browser,\n device: agent.device,\n language: navigator.language,\n os: agent.os,\n pageTitle: optionalText(document.title, MAX_PAGE_TITLE_LENGTH),\n referrer: optionalText(document.referrer, MAX_URL_LENGTH),\n screen: { height: window.screen.height, width: window.screen.width },\n sdkVersion: options?.sdkVersion,\n timezone: resolveTimezone(),\n url: clip(window.location.href, MAX_URL_LENGTH),\n userAgent: clip(userAgent, MAX_USER_AGENT_LENGTH),\n viewport: {\n devicePixelRatio: window.devicePixelRatio,\n height: window.innerHeight,\n width: window.innerWidth,\n },\n };\n}\n","import type { RefletUser } from \"../types\";\n\n/** Reported with every submission. Keep in sync with package.json on release. */\nexport const SDK_VERSION = \"0.2.0\";\n\nconst FEEDBACK_WIDGET_CATEGORIES = [\"bug\", \"idea\", \"question\"] as const;\n\nexport type FeedbackWidgetCategory =\n (typeof FEEDBACK_WIDGET_CATEGORIES)[number];\n\nconst ANNOTATION_TOOLS = [\n \"pen\",\n \"arrow\",\n \"rectangle\",\n \"highlight\",\n \"blur\",\n] as const;\n\nexport type AnnotationTool = (typeof ANNOTATION_TOOLS)[number];\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface Annotation {\n color: string;\n end: Point;\n id: string;\n /** Freehand path, in image pixels. Only set for the pen tool. */\n points?: Point[];\n start: Point;\n tool: AnnotationTool;\n}\n\nexport interface CapturedImage {\n blob: Blob;\n height: number;\n mimeType: string;\n /** Object URL owned by the caller — revoke it when the capture is dropped. */\n objectUrl: string;\n width: number;\n}\n\nexport interface FeedbackWidgetLabels {\n annotateHint: string;\n attachScreenshot: string;\n back: string;\n cancel: string;\n categoryBug: string;\n categoryIdea: string;\n categoryQuestion: string;\n clearAnnotations: string;\n descriptionPlaceholder: string;\n dismissForDays: string;\n done: string;\n emailLabel: string;\n emailPlaceholder: string;\n errorGeneric: string;\n errorTitleRequired: string;\n pickElement: string;\n pickElementHint: string;\n recapture: string;\n removeScreenshot: string;\n retakeHint: string;\n submit: string;\n successMessage: string;\n successTitle: string;\n title: string;\n titlePlaceholder: string;\n trigger: string;\n undo: string;\n}\n\nexport const DEFAULT_WIDGET_LABELS: FeedbackWidgetLabels = {\n annotateHint: \"Draw on the screenshot to point at the problem.\",\n attachScreenshot: \"Attach a screenshot\",\n back: \"Back\",\n cancel: \"Cancel\",\n categoryBug: \"Bug\",\n categoryIdea: \"Idea\",\n categoryQuestion: \"Question\",\n clearAnnotations: \"Clear drawing\",\n descriptionPlaceholder: \"What happened? What did you expect?\",\n dismissForDays: \"Hide for {days} days\",\n done: \"Done\",\n emailLabel: \"Email\",\n emailPlaceholder: \"you@company.com\",\n errorGeneric: \"Something went wrong. Please try again.\",\n errorTitleRequired: \"Tell us a bit about it first.\",\n pickElement: \"Point at an element\",\n pickElementHint: \"Click the element you are talking about — cancel with\",\n recapture: \"Retake\",\n removeScreenshot: \"Remove\",\n retakeHint: \"Screenshot of this page\",\n submit: \"Send feedback\",\n successMessage: \"We read every report. Thanks for taking the time.\",\n successTitle: \"Feedback sent\",\n title: \"Send feedback\",\n titlePlaceholder: \"Short summary\",\n trigger: \"Feedback\",\n undo: \"Undo\",\n};\n\nexport interface RefletFeedbackProps {\n /** API base URL override. Falls back to the RefletProvider value. */\n baseUrl?: string;\n /** Record console errors and warnings to attach to bug reports. */\n captureConsole?: boolean;\n /** Take a screenshot of the viewport as soon as the panel opens. */\n captureOnOpen?: boolean;\n categories?: FeedbackWidgetCategory[];\n defaultCategory?: FeedbackWidgetCategory;\n /** Let reporters hide the launcher for this many days. */\n dismissForDays?: number;\n /** Render nothing when false — lets an app gate the widget per user. */\n enabled?: boolean;\n /** Keyboard shortcut opening the panel. Set to null to disable. */\n hotkey?: string | null;\n labels?: Partial<FeedbackWidgetLabels>;\n /** Extra fields merged into the reported context. */\n metadata?: Record<string, string>;\n /** Distance in px from the viewport edges. */\n offset?: number;\n onClose?: () => void;\n onDismiss?: (result: { until: number }) => void;\n onOpen?: () => void;\n onSubmit?: (result: { feedbackId: string }) => void;\n position?: \"bottom-left\" | \"bottom-right\" | \"top-left\" | \"top-right\";\n primaryColor?: string;\n publicKey?: string;\n theme?: \"auto\" | \"dark\" | \"light\";\n user?: RefletUser;\n userToken?: string;\n}\n\nexport type WidgetStep = \"annotate\" | \"compose\" | \"picking\" | \"success\";\n","import type { ElementRect, ScreenshotAnnotation } from \"../../types\";\nimport type { Annotation, AnnotationTool, Point } from \"../types\";\n\nexport const ANNOTATION_COLORS = [\n \"#ef4444\",\n \"#f59e0b\",\n \"#22c55e\",\n \"#3b82f6\",\n \"#111827\",\n] as const;\n\nconst BOX_TOOLS: AnnotationTool[] = [\"rectangle\", \"highlight\", \"blur\"];\nconst MIN_GESTURE_LENGTH = 8;\nconst ARROW_HEAD_ANGLE = Math.PI / 7;\nconst DEFAULT_PATH_TOLERANCE = 2.5;\n\nexport function normalizeRect(start: Point, end: Point): ElementRect {\n return {\n height: Math.abs(end.y - start.y),\n width: Math.abs(end.x - start.x),\n x: Math.min(start.x, end.x),\n y: Math.min(start.y, end.y),\n };\n}\n\n/** The two barbs closing the arrow tip, both `size` px away from `end`. */\nexport function arrowHead(\n start: Point,\n end: Point,\n size: number\n): [Point, Point] {\n const angle = Math.atan2(end.y - start.y, end.x - start.x);\n if (Math.hypot(end.x - start.x, end.y - start.y) === 0) {\n return [end, end];\n }\n\n const barb = (offset: number): Point => ({\n x: end.x - size * Math.cos(angle + offset),\n y: end.y - size * Math.sin(angle + offset),\n });\n\n return [barb(-ARROW_HEAD_ANGLE), barb(ARROW_HEAD_ANGLE)];\n}\n\n/** Drops points a user cannot perceive, keeping the payload small. */\nexport function simplifyPath(\n points: Point[],\n tolerance = DEFAULT_PATH_TOLERANCE\n): Point[] {\n if (points.length < 3) {\n return points;\n }\n\n const [first, ...rest] = points;\n if (!first) {\n return points;\n }\n\n const kept: Point[] = [first];\n let anchor = first;\n\n for (const point of rest.slice(0, -1)) {\n if (Math.hypot(point.x - anchor.x, point.y - anchor.y) >= tolerance) {\n kept.push(point);\n anchor = point;\n }\n }\n\n const last = points.at(-1);\n if (last) {\n kept.push(last);\n }\n\n return kept;\n}\n\nexport function isDegenerate(annotation: Annotation): boolean {\n if (annotation.tool === \"pen\") {\n return (annotation.points?.length ?? 0) < 2;\n }\n\n const { start, end } = annotation;\n return Math.hypot(end.x - start.x, end.y - start.y) < MIN_GESTURE_LENGTH;\n}\n\nfunction toWire(annotation: Annotation): ScreenshotAnnotation {\n const { color, start, end, tool } = annotation;\n\n if (tool === \"pen\") {\n return {\n color,\n points: simplifyPath(annotation.points ?? []),\n type: tool,\n x: start.x,\n y: start.y,\n };\n }\n\n if (BOX_TOOLS.includes(tool)) {\n const rect = normalizeRect(start, end);\n return {\n color,\n height: rect.height,\n type: tool,\n width: rect.width,\n x: rect.x,\n y: rect.y,\n };\n }\n\n return {\n color,\n endX: end.x,\n endY: end.y,\n type: tool,\n x: start.x,\n y: start.y,\n };\n}\n\n/** Serializes to the shape the Reflet API stores next to the screenshot. */\nexport function toWireAnnotations(\n annotations: Annotation[]\n): ScreenshotAnnotation[] {\n return annotations.filter((item) => !isDegenerate(item)).map(toWire);\n}\n","import type { ElementRect } from \"../../types\";\nimport type { Annotation, CapturedImage, Point } from \"../types\";\nimport { arrowHead, isDegenerate, normalizeRect } from \"./annotations\";\n\nconst STROKE_WIDTH = 3;\nconst ARROW_HEAD_SIZE = 16;\nconst HIGHLIGHT_ALPHA = 0.3;\nconst REDACTION_FILL = \"#111827\";\nconst PIXEL_BLOCK = 10;\n\n/**\n * The slice of `CanvasRenderingContext2D` the annotation layer needs.\n * Narrowing it keeps the drawing code testable without a canvas polyfill.\n */\nexport interface AnnotationCanvasContext {\n beginPath: () => void;\n canvas: { height: number; width: number };\n closePath: () => void;\n drawImage: (\n image: CanvasImageSource,\n dx: number,\n dy: number,\n dw: number,\n dh: number\n ) => void;\n fill: () => void;\n fillRect: (x: number, y: number, width: number, height: number) => void;\n fillStyle: string | CanvasGradient | CanvasPattern;\n globalAlpha: number;\n lineCap: CanvasLineCap;\n lineJoin: CanvasLineJoin;\n lineTo: (x: number, y: number) => void;\n lineWidth: number;\n moveTo: (x: number, y: number) => void;\n restore: () => void;\n save: () => void;\n stroke: () => void;\n strokeRect: (x: number, y: number, width: number, height: number) => void;\n strokeStyle: string | CanvasGradient | CanvasPattern;\n}\n\nfunction scalePoint(point: Point, scale: number): Point {\n return { x: point.x * scale, y: point.y * scale };\n}\n\nfunction scaleRect(rect: ElementRect, scale: number): ElementRect {\n return {\n height: rect.height * scale,\n width: rect.width * scale,\n x: rect.x * scale,\n y: rect.y * scale,\n };\n}\n\nfunction isCanvasElement(value: unknown): value is HTMLCanvasElement {\n return (\n typeof HTMLCanvasElement !== \"undefined\" &&\n value instanceof HTMLCanvasElement\n );\n}\n\n/**\n * Downsamples the region and paints it back enlarged, so redacted pixels are\n * unrecoverable. Falls back to an opaque block wherever 2d canvases are absent.\n */\nfunction redact(context: AnnotationCanvasContext, rect: ElementRect): void {\n const source = context.canvas;\n const width = Math.max(1, Math.round(rect.width / PIXEL_BLOCK));\n const height = Math.max(1, Math.round(rect.height / PIXEL_BLOCK));\n\n if (isCanvasElement(source)) {\n const offscreen = document.createElement(\"canvas\");\n offscreen.width = width;\n offscreen.height = height;\n const offscreenContext = offscreen.getContext(\"2d\");\n\n if (offscreenContext) {\n offscreenContext.imageSmoothingEnabled = true;\n offscreenContext.drawImage(\n source,\n rect.x,\n rect.y,\n rect.width,\n rect.height,\n 0,\n 0,\n width,\n height\n );\n context.drawImage(offscreen, rect.x, rect.y, rect.width, rect.height);\n return;\n }\n }\n\n context.fillStyle = REDACTION_FILL;\n context.fillRect(rect.x, rect.y, rect.width, rect.height);\n}\n\nfunction drawArrow(\n context: AnnotationCanvasContext,\n start: Point,\n end: Point,\n scale: number\n): void {\n context.beginPath();\n context.moveTo(start.x, start.y);\n context.lineTo(end.x, end.y);\n context.stroke();\n\n const [left, right] = arrowHead(start, end, ARROW_HEAD_SIZE * scale);\n context.beginPath();\n context.moveTo(end.x, end.y);\n context.lineTo(left.x, left.y);\n context.lineTo(right.x, right.y);\n context.closePath();\n context.fill();\n}\n\nfunction drawPen(\n context: AnnotationCanvasContext,\n points: Point[],\n scale: number\n): void {\n const [first, ...rest] = points;\n if (!first) {\n return;\n }\n\n const head = scalePoint(first, scale);\n context.beginPath();\n context.moveTo(head.x, head.y);\n for (const point of rest) {\n const scaled = scalePoint(point, scale);\n context.lineTo(scaled.x, scaled.y);\n }\n context.stroke();\n}\n\nfunction drawAnnotation(\n context: AnnotationCanvasContext,\n annotation: Annotation,\n scale: number\n): void {\n const { color, tool } = annotation;\n const rect = scaleRect(\n normalizeRect(annotation.start, annotation.end),\n scale\n );\n\n context.save();\n context.lineWidth = STROKE_WIDTH * scale;\n context.lineCap = \"round\";\n context.lineJoin = \"round\";\n context.strokeStyle = color;\n context.fillStyle = color;\n\n switch (tool) {\n case \"pen\":\n drawPen(context, annotation.points ?? [], scale);\n break;\n case \"arrow\":\n drawArrow(\n context,\n scalePoint(annotation.start, scale),\n scalePoint(annotation.end, scale),\n scale\n );\n break;\n case \"rectangle\":\n context.strokeRect(rect.x, rect.y, rect.width, rect.height);\n break;\n case \"highlight\":\n context.globalAlpha = HIGHLIGHT_ALPHA;\n context.fillRect(rect.x, rect.y, rect.width, rect.height);\n break;\n default:\n redact(context, rect);\n break;\n }\n\n context.restore();\n}\n\nexport function drawAnnotations(\n context: AnnotationCanvasContext,\n annotations: Annotation[],\n options?: { scale?: number }\n): void {\n const scale = options?.scale ?? 1;\n for (const annotation of annotations) {\n if (!isDegenerate(annotation)) {\n drawAnnotation(context, annotation, scale);\n }\n }\n}\n\nfunction loadImage(url: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const image = new Image();\n image.onload = () => resolve(image);\n image.onerror = () => reject(new Error(\"Screenshot could not be decoded\"));\n image.src = url;\n });\n}\n\nfunction toBlob(canvas: HTMLCanvasElement): Promise<Blob | null> {\n return new Promise((resolve) => {\n canvas.toBlob(resolve, \"image/png\");\n });\n}\n\n/**\n * Burns the annotations into a copy of the capture so reviewers and agents see\n * the drawing without needing to replay the vector data.\n */\nexport async function renderAnnotatedImage(\n source: CapturedImage,\n annotations: Annotation[]\n): Promise<CapturedImage | null> {\n if (annotations.length === 0) {\n return null;\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = source.width;\n canvas.height = source.height;\n const context = canvas.getContext(\"2d\");\n if (!context) {\n return null;\n }\n\n const image = await loadImage(source.objectUrl);\n context.drawImage(image, 0, 0, source.width, source.height);\n drawAnnotations(context, annotations);\n\n const blob = await toBlob(canvas);\n if (!blob) {\n return null;\n }\n\n return {\n blob,\n height: source.height,\n mimeType: \"image/png\",\n objectUrl: URL.createObjectURL(blob),\n width: source.width,\n };\n}\n","import type { ReactNode } from \"react\";\n\nfunction Svg({ children, size = 16 }: { children: ReactNode; size?: number }) {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height={size}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"1.8\"\n viewBox=\"0 0 24 24\"\n width={size}\n >\n {children}\n </svg>\n );\n}\n\nexport function ChatIcon() {\n return (\n <Svg size={18}>\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </Svg>\n );\n}\n\nexport function CloseIcon() {\n return (\n <Svg>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Svg>\n );\n}\n\nexport function BugIcon() {\n return (\n <Svg size={14}>\n <path d=\"M8 6a4 4 0 0 1 8 0M6 10h12v4a6 6 0 0 1-12 0zM3 12h3M18 12h3M4.5 6.5 7 8M19.5 6.5 17 8M4.5 17.5 7 16M19.5 17.5 17 16\" />\n </Svg>\n );\n}\n\nexport function IdeaIcon() {\n return (\n <Svg size={14}>\n <path d=\"M9 18h6M10 21h4M12 3a6 6 0 0 0-3.6 10.8c.5.4.8.9.9 1.5l.1.7h5.2l.1-.7c.1-.6.4-1.1.9-1.5A6 6 0 0 0 12 3\" />\n </Svg>\n );\n}\n\nexport function QuestionIcon() {\n return (\n <Svg size={14}>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M9.6 9.4a2.5 2.5 0 1 1 3.3 2.4c-.6.2-.9.8-.9 1.4v.3M12 17h.01\" />\n </Svg>\n );\n}\n\nexport function CameraIcon() {\n return (\n <Svg>\n <path d=\"M3 8.5A1.5 1.5 0 0 1 4.5 7h2.2l1.2-2h8.2l1.2 2h2.2A1.5 1.5 0 0 1 21 8.5v9A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5z\" />\n <circle cx=\"12\" cy=\"13\" r=\"3.2\" />\n </Svg>\n );\n}\n\nexport function PencilIcon() {\n return (\n <Svg>\n <path d=\"M16.5 4.5a2.1 2.1 0 0 1 3 3L8 19l-4 1 1-4z\" />\n </Svg>\n );\n}\n\nexport function TargetIcon() {\n return (\n <Svg>\n <path d=\"M12 3v3M12 18v3M3 12h3M18 12h3\" />\n <circle cx=\"12\" cy=\"12\" r=\"5\" />\n </Svg>\n );\n}\n\nexport function TrashIcon() {\n return (\n <Svg>\n <path d=\"M4 7h16M9 7V5h6v2M6 7l1 13h10l1-13M10 11v5M14 11v5\" />\n </Svg>\n );\n}\n\nexport function ArrowIcon() {\n return (\n <Svg>\n <path d=\"M5 19 19 5M11 5h8v8\" />\n </Svg>\n );\n}\n\nexport function SquareIcon() {\n return (\n <Svg>\n <rect height=\"13\" rx=\"1.5\" width=\"16\" x=\"4\" y=\"5.5\" />\n </Svg>\n );\n}\n\nexport function HighlightIcon() {\n return (\n <Svg>\n <path d=\"M4 15h16M6 5h12v7H6z\" />\n </Svg>\n );\n}\n\nexport function BlurIcon() {\n return (\n <Svg>\n <path d=\"M12 3c3.5 4 5.5 6.6 5.5 9.2A5.5 5.5 0 0 1 6.5 12.2C6.5 9.6 8.5 7 12 3\" />\n <path d=\"M9 13h.01M12 15h.01M15 12h.01\" />\n </Svg>\n );\n}\n\nexport function UndoIcon() {\n return (\n <Svg>\n <path d=\"M4 9h11a5 5 0 0 1 0 10h-5M4 9l4-4M4 9l4 4\" />\n </Svg>\n );\n}\n\nexport function CheckIcon({ size = 28 }: { size?: number }) {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height={size}\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.4\"\n viewBox=\"0 0 24 24\"\n width={size}\n >\n <path d=\"m5 13 4 4L19 7\" />\n </svg>\n );\n}\n","import {\n type ComponentType,\n type PointerEvent as ReactPointerEvent,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { drawAnnotations } from \"../core/annotation-renderer\";\nimport { ANNOTATION_COLORS, isDegenerate } from \"../core/annotations\";\nimport type {\n Annotation,\n AnnotationTool,\n CapturedImage,\n FeedbackWidgetLabels,\n Point,\n} from \"../types\";\nimport {\n ArrowIcon,\n BlurIcon,\n HighlightIcon,\n PencilIcon,\n SquareIcon,\n TrashIcon,\n UndoIcon,\n} from \"./icons\";\n\nconst TOOLS: Array<{\n icon: ComponentType;\n id: AnnotationTool;\n label: string;\n}> = [\n { icon: PencilIcon, id: \"pen\", label: \"Draw\" },\n { icon: ArrowIcon, id: \"arrow\", label: \"Arrow\" },\n { icon: SquareIcon, id: \"rectangle\", label: \"Box\" },\n { icon: HighlightIcon, id: \"highlight\", label: \"Highlight\" },\n { icon: BlurIcon, id: \"blur\", label: \"Hide\" },\n];\n\nfunction toImagePoint(\n canvas: HTMLCanvasElement,\n clientX: number,\n clientY: number\n): Point {\n const bounds = canvas.getBoundingClientRect();\n return {\n x: ((clientX - bounds.left) / bounds.width) * canvas.width,\n y: ((clientY - bounds.top) / bounds.height) * canvas.height,\n };\n}\n\nexport function Annotator({\n annotations,\n capture,\n labels,\n onChange,\n onDone,\n}: {\n annotations: Annotation[];\n capture: CapturedImage;\n labels: FeedbackWidgetLabels;\n onChange: (annotations: Annotation[]) => void;\n onDone: () => void;\n}) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const nextId = useRef(0);\n const [tool, setTool] = useState<AnnotationTool>(\"pen\");\n const [color, setColor] = useState<string>(ANNOTATION_COLORS[0]);\n const [draft, setDraft] = useState<Annotation | null>(null);\n // State, not a ref: the redraw effect must re-run once the bitmap is decoded.\n const [base, setBase] = useState<HTMLImageElement | null>(null);\n\n useEffect(() => {\n let active = true;\n const image = new Image();\n image.onload = () => {\n if (active) {\n setBase(image);\n }\n };\n image.src = capture.objectUrl;\n return () => {\n active = false;\n setBase(null);\n };\n }, [capture.objectUrl]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n const context = canvas?.getContext(\"2d\");\n if (!(canvas && context)) {\n return;\n }\n\n context.clearRect(0, 0, canvas.width, canvas.height);\n if (base) {\n context.drawImage(base, 0, 0, canvas.width, canvas.height);\n }\n drawAnnotations(context, draft ? [...annotations, draft] : annotations);\n }, [annotations, base, draft]);\n\n const onPointerDown = (event: ReactPointerEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!canvas) {\n return;\n }\n\n canvas.setPointerCapture(event.pointerId);\n const point = toImagePoint(canvas, event.clientX, event.clientY);\n nextId.current += 1;\n\n setDraft({\n color,\n end: point,\n id: `a${nextId.current}`,\n points: tool === \"pen\" ? [point] : undefined,\n start: point,\n tool,\n });\n };\n\n const onPointerMove = (event: ReactPointerEvent<HTMLCanvasElement>) => {\n const canvas = canvasRef.current;\n if (!(canvas && draft)) {\n return;\n }\n\n const point = toImagePoint(canvas, event.clientX, event.clientY);\n setDraft(\n draft.tool === \"pen\"\n ? { ...draft, end: point, points: [...(draft.points ?? []), point] }\n : { ...draft, end: point }\n );\n };\n\n const onPointerUp = () => {\n if (!draft) {\n return;\n }\n if (!isDegenerate(draft)) {\n onChange([...annotations, draft]);\n }\n setDraft(null);\n };\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n onDone();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [onDone]);\n\n return (\n <div className=\"overlay\">\n <div className=\"editor\">\n <canvas\n height={capture.height}\n onPointerCancel={onPointerUp}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n ref={canvasRef}\n width={capture.width}\n />\n </div>\n\n <div className=\"toolbar\">\n <div className=\"group\">\n {TOOLS.map(({ icon: Icon, id, label }) => (\n <button\n aria-label={label}\n aria-pressed={tool === id}\n className=\"tool\"\n key={id}\n onClick={() => setTool(id)}\n title={label}\n type=\"button\"\n >\n <Icon />\n </button>\n ))}\n </div>\n\n <div className=\"group\">\n {ANNOTATION_COLORS.map((value) => (\n <button\n aria-label={`Color ${value}`}\n aria-pressed={color === value}\n className=\"swatch\"\n key={value}\n onClick={() => setColor(value)}\n style={{ background: value }}\n type=\"button\"\n />\n ))}\n </div>\n\n <div className=\"group\">\n <button\n aria-label={labels.undo}\n className=\"tool\"\n disabled={annotations.length === 0}\n onClick={() => onChange(annotations.slice(0, -1))}\n title={labels.undo}\n type=\"button\"\n >\n <UndoIcon />\n </button>\n <button\n aria-label={labels.clearAnnotations}\n className=\"tool\"\n disabled={annotations.length === 0}\n onClick={() => onChange([])}\n title={labels.clearAnnotations}\n type=\"button\"\n >\n <TrashIcon />\n </button>\n <button className=\"done-btn\" onClick={onDone} type=\"button\">\n {labels.done}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { ChatIcon, CloseIcon } from \"./icons\";\n\nexport function Launcher({\n compact,\n isOpen,\n label,\n onClick,\n}: {\n compact: boolean;\n isOpen: boolean;\n label: string;\n onClick: () => void;\n}) {\n return (\n <button\n aria-expanded={isOpen}\n aria-label={label}\n className=\"launcher\"\n data-compact={compact || isOpen ? \"true\" : \"false\"}\n onClick={onClick}\n type=\"button\"\n >\n {isOpen ? <CloseIcon /> : <ChatIcon />}\n {!(compact || isOpen) && label}\n </button>\n );\n}\n","import { type ComponentType, useEffect, useRef } from \"react\";\nimport type { FeedbackWidgetCategory, FeedbackWidgetLabels } from \"../types\";\nimport {\n BugIcon,\n CameraIcon,\n CheckIcon,\n CloseIcon,\n IdeaIcon,\n PencilIcon,\n QuestionIcon,\n TargetIcon,\n TrashIcon,\n} from \"./icons\";\nimport type { WidgetState } from \"./use-widget-state\";\n\nconst CATEGORY_META: Record<\n FeedbackWidgetCategory,\n { icon: ComponentType; labelKey: keyof FeedbackWidgetLabels }\n> = {\n bug: { icon: BugIcon, labelKey: \"categoryBug\" },\n idea: { icon: IdeaIcon, labelKey: \"categoryIdea\" },\n question: { icon: QuestionIcon, labelKey: \"categoryQuestion\" },\n};\n\nfunction Attachment({\n labels,\n state,\n}: {\n labels: FeedbackWidgetLabels;\n state: WidgetState;\n}) {\n if (state.isCapturing) {\n return (\n <div className=\"attachment\">\n <div className=\"thumb\" />\n <div className=\"meta\">\n <strong>{labels.retakeHint}</strong>\n <span>…</span>\n </div>\n </div>\n );\n }\n\n if (!state.capture) {\n return (\n <button\n className=\"ghost-btn\"\n onClick={() => state.takeCapture()}\n type=\"button\"\n >\n <CameraIcon />\n {labels.attachScreenshot}\n </button>\n );\n }\n\n const annotationCount = state.annotations.length;\n\n return (\n <div className=\"attachment\">\n <div className=\"thumb\">\n <img\n alt=\"\"\n height={state.capture.height}\n src={state.capture.objectUrl}\n width={state.capture.width}\n />\n </div>\n <div className=\"meta\">\n <strong>{labels.retakeHint}</strong>\n <span>\n {state.capture.width}×{state.capture.height}\n {annotationCount > 0 ? ` · ${annotationCount} marks` : \"\"}\n </span>\n </div>\n <div className=\"actions\">\n <button\n aria-label={labels.annotateHint}\n className=\"icon-btn\"\n onClick={() => state.setStep(\"annotate\")}\n title={labels.annotateHint}\n type=\"button\"\n >\n <PencilIcon />\n </button>\n <button\n aria-label={labels.recapture}\n className=\"icon-btn\"\n onClick={() => state.takeCapture()}\n title={labels.recapture}\n type=\"button\"\n >\n <CameraIcon />\n </button>\n <button\n aria-label={labels.removeScreenshot}\n className=\"icon-btn\"\n onClick={state.removeCapture}\n title={labels.removeScreenshot}\n type=\"button\"\n >\n <TrashIcon />\n </button>\n </div>\n </div>\n );\n}\n\nfunction SelectionChip({\n labels,\n state,\n}: {\n labels: FeedbackWidgetLabels;\n state: WidgetState;\n}) {\n const { selection } = state;\n if (!selection) {\n return (\n <button\n className=\"ghost-btn\"\n onClick={() => state.setStep(\"picking\")}\n type=\"button\"\n >\n <TargetIcon />\n {labels.pickElement}\n </button>\n );\n }\n\n const component = selection.componentStack[0];\n\n return (\n <span className=\"chip\">\n <TargetIcon />\n <span className=\"truncate\">\n {component ? <strong>{`<${component}>`}</strong> : selection.label}{\" \"}\n <code>{selection.sourceLocation ?? selection.selector}</code>\n </span>\n <button\n aria-label={labels.cancel}\n className=\"icon-btn\"\n onClick={state.clearSelection}\n type=\"button\"\n >\n <CloseIcon />\n </button>\n </span>\n );\n}\n\nexport function FeedbackPanel({\n categories,\n labels,\n state,\n}: {\n categories: FeedbackWidgetCategory[];\n labels: FeedbackWidgetLabels;\n state: WidgetState;\n}) {\n const messageRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n messageRef.current?.focus();\n }, []);\n\n if (state.step === \"success\") {\n return (\n <section aria-live=\"polite\" className=\"panel\">\n <div className=\"done\">\n <CheckIcon />\n <h2>{labels.successTitle}</h2>\n <p>{labels.successMessage}</p>\n </div>\n </section>\n );\n }\n\n return (\n <section aria-label={labels.title} className=\"panel\">\n <header className=\"head\">\n <h2>{labels.title}</h2>\n <span className=\"spacer\" />\n <button\n aria-label={labels.cancel}\n className=\"icon-btn\"\n onClick={state.close}\n type=\"button\"\n >\n <CloseIcon />\n </button>\n </header>\n\n <form\n className=\"body\"\n onSubmit={(event) => {\n event.preventDefault();\n state.submit();\n }}\n >\n {categories.length > 1 && (\n <fieldset className=\"segmented\">\n {categories.map((value) => {\n const { icon: Icon, labelKey } = CATEGORY_META[value];\n return (\n <button\n aria-pressed={state.category === value}\n key={value}\n onClick={() => state.setCategory(value)}\n type=\"button\"\n >\n <Icon />\n {labels[labelKey]}\n </button>\n );\n })}\n </fieldset>\n )}\n\n <textarea\n aria-label={labels.descriptionPlaceholder}\n maxLength={4000}\n onChange={(event) => state.setMessage(event.target.value)}\n placeholder={labels.descriptionPlaceholder}\n ref={messageRef}\n value={state.message}\n />\n\n <Attachment labels={labels} state={state} />\n <SelectionChip labels={labels} state={state} />\n\n {state.isAnonymous && (\n <input\n aria-label={labels.emailLabel}\n autoComplete=\"email\"\n onChange={(event) => state.setEmail(event.target.value)}\n placeholder={labels.emailPlaceholder}\n type=\"email\"\n value={state.email}\n />\n )}\n\n <div aria-hidden=\"true\" className=\"hp\">\n <input\n autoComplete=\"off\"\n name=\"company-website\"\n onChange={(event) => state.setHoneypot(event.target.value)}\n tabIndex={-1}\n value={state.honeypot}\n />\n </div>\n\n {state.error && <p className=\"error\">{state.error}</p>}\n\n <button\n className=\"submit\"\n disabled={state.isSubmitting || !state.message.trim()}\n type=\"submit\"\n >\n {state.isSubmitting ? <span className=\"spinner\" /> : labels.submit}\n </button>\n </form>\n\n <footer className=\"footer\" data-dismissible={state.canDismiss}>\n {state.canDismiss && (\n <button className=\"dismiss-btn\" onClick={state.dismiss} type=\"button\">\n {labels.dismissForDays.replace(\n \"{days}\",\n String(state.dismissForDays)\n )}\n </button>\n )}\n <span>\n Powered by{\" \"}\n <a\n href=\"https://reflet.app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Reflet\n </a>\n </span>\n </footer>\n </section>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport { WIDGET_MARKER } from \"../core/capture\";\nimport { buildSelector, describeElement } from \"../core/element-selector\";\nimport { getFiberFromNode, resolveComponentStack } from \"../core/react-source\";\n\nconst LABEL_HEIGHT = 28;\nconst LABEL_GAP = 6;\n\ninterface HoverTarget {\n componentName?: string;\n label: string;\n rect: DOMRect;\n selector: string;\n}\n\nfunction isWidgetOwned(element: Element): boolean {\n return element.closest(`[${WIDGET_MARKER}]`) !== null;\n}\n\nfunction elementUnder(x: number, y: number): Element | null {\n const element = document.elementFromPoint(x, y);\n if (!element || isWidgetOwned(element)) {\n return null;\n }\n return element;\n}\n\nfunction describeTarget(element: Element): HoverTarget {\n return {\n componentName: resolveComponentStack(getFiberFromNode(element))[0],\n label: describeElement(element),\n rect: element.getBoundingClientRect(),\n selector: buildSelector(element),\n };\n}\n\n/**\n * Points at any element in the page the way a coding agent needs it: the React\n * component that owns it plus a selector that resolves back to it.\n */\nexport function ElementPicker({\n hint,\n onCancel,\n onPick,\n}: {\n hint: string;\n onCancel: () => void;\n onPick: (element: Element) => void;\n}) {\n const [target, setTarget] = useState<HoverTarget | null>(null);\n\n useEffect(() => {\n const swallow = (event: Event) => {\n event.preventDefault();\n event.stopPropagation();\n };\n\n const onMove = (event: PointerEvent) => {\n const element = elementUnder(event.clientX, event.clientY);\n setTarget(element ? describeTarget(element) : null);\n };\n\n const onClick = (event: MouseEvent) => {\n swallow(event);\n const element = elementUnder(event.clientX, event.clientY);\n if (element) {\n onPick(element);\n }\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n swallow(event);\n onCancel();\n }\n };\n\n // Capture phase everywhere: the host app must not react to the pick.\n document.addEventListener(\"pointermove\", onMove, true);\n document.addEventListener(\"pointerdown\", swallow, true);\n document.addEventListener(\"mousedown\", swallow, true);\n document.addEventListener(\"mouseup\", swallow, true);\n document.addEventListener(\"click\", onClick, true);\n document.addEventListener(\"keydown\", onKeyDown, true);\n\n const previousCursor = document.body.style.cursor;\n document.body.style.cursor = \"crosshair\";\n\n return () => {\n document.removeEventListener(\"pointermove\", onMove, true);\n document.removeEventListener(\"pointerdown\", swallow, true);\n document.removeEventListener(\"mousedown\", swallow, true);\n document.removeEventListener(\"mouseup\", swallow, true);\n document.removeEventListener(\"click\", onClick, true);\n document.removeEventListener(\"keydown\", onKeyDown, true);\n document.body.style.cursor = previousCursor;\n };\n }, [onCancel, onPick]);\n\n const rect = target?.rect;\n const labelAbove = rect ? rect.top > LABEL_HEIGHT + LABEL_GAP : true;\n\n return (\n <div>\n {rect && (\n <div\n className=\"picker-box\"\n style={{\n height: rect.height,\n left: rect.left,\n top: rect.top,\n width: rect.width,\n }}\n />\n )}\n {rect && target && (\n <div\n className=\"picker-label\"\n style={{\n left: Math.max(4, rect.left),\n top: labelAbove\n ? rect.top - LABEL_HEIGHT - LABEL_GAP\n : rect.bottom + LABEL_GAP,\n }}\n >\n {target.componentName ? (\n <strong>{`<${target.componentName}>`}</strong>\n ) : (\n <strong>{target.label}</strong>\n )}\n <code>{target.selector}</code>\n </div>\n )}\n <div className=\"picker-hint\">\n {hint} <kbd>Esc</kbd>\n </div>\n </div>\n );\n}\n","/**\n * Styles for the feedback widget. Injected into a shadow root, so nothing here\n * leaks into the host app and nothing from the host app leaks in.\n */\nexport const WIDGET_STYLES = `\n:host {\n --rf-bg: #ffffff;\n --rf-bg-subtle: #f6f7f9;\n --rf-border: #e4e6eb;\n --rf-text: #16181d;\n --rf-text-muted: #6b7280;\n --rf-primary: #4f46e5;\n --rf-primary-text: #ffffff;\n --rf-danger: #dc2626;\n --rf-success: #16a34a;\n --rf-radius: 14px;\n --rf-shadow: 0 1px 2px rgb(16 24 40 / 6%), 0 12px 32px -8px rgb(16 24 40 / 18%);\n --rf-ring: 0 0 0 3px color-mix(in srgb, var(--rf-primary) 28%, transparent);\n --rf-ease: cubic-bezier(0.32, 0.72, 0, 1);\n color-scheme: light;\n all: initial;\n font-family: var(--rf-font, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif);\n}\n\n:host([data-theme=\"dark\"]) {\n --rf-bg: #17181c;\n --rf-bg-subtle: #212228;\n --rf-border: #2e3038;\n --rf-text: #f3f4f6;\n --rf-text-muted: #9aa1ad;\n --rf-shadow: 0 1px 2px rgb(0 0 0 / 40%), 0 16px 40px -12px rgb(0 0 0 / 60%);\n color-scheme: dark;\n}\n\n*, *::before, *::after { box-sizing: border-box; }\n\n.root {\n position: fixed;\n z-index: 2147483000;\n font-family: inherit;\n font-size: 14px;\n line-height: 1.45;\n color: var(--rf-text);\n}\n\n.root[data-position=\"bottom-right\"] { bottom: var(--rf-offset); right: var(--rf-offset); align-items: flex-end; }\n.root[data-position=\"bottom-left\"] { bottom: var(--rf-offset); left: var(--rf-offset); align-items: flex-start; }\n.root[data-position=\"top-right\"] { top: var(--rf-offset); right: var(--rf-offset); align-items: flex-end; }\n.root[data-position=\"top-left\"] { top: var(--rf-offset); left: var(--rf-offset); align-items: flex-start; }\n\n.stack { display: flex; flex-direction: column; gap: 12px; }\n.root[data-position^=\"top\"] .stack { flex-direction: column-reverse; }\n\nbutton {\n font: inherit;\n color: inherit;\n margin: 0;\n cursor: pointer;\n border: 0;\n background: none;\n}\n\n:focus-visible { outline: none; box-shadow: var(--rf-ring); }\n\n.launcher {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 44px;\n padding: 0 16px;\n border-radius: 999px;\n background: var(--rf-primary);\n color: var(--rf-primary-text);\n font-weight: 550;\n box-shadow: var(--rf-shadow);\n transition: transform 160ms var(--rf-ease), filter 160ms var(--rf-ease);\n}\n.launcher:hover { transform: translateY(-1px); filter: brightness(1.06); }\n.launcher:active { transform: translateY(0) scale(0.97); }\n.launcher[data-compact=\"true\"] { width: 44px; padding: 0; justify-content: center; }\n\n.panel {\n width: min(384px, calc(100vw - 32px));\n max-height: min(620px, calc(100vh - 96px));\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--rf-bg);\n border: 1px solid var(--rf-border);\n border-radius: var(--rf-radius);\n box-shadow: var(--rf-shadow);\n animation: rf-in 220ms var(--rf-ease);\n}\n\n@keyframes rf-in {\n from { opacity: 0; transform: translateY(8px) scale(0.98); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panel, .launcher { animation: none; transition: none; }\n}\n\n.head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 14px 10px;\n}\n.head h2 { margin: 0; font-size: 15px; font-weight: 600; }\n.head .spacer { flex: 1; }\n\n.icon-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n border-radius: 8px;\n color: var(--rf-text-muted);\n transition: background 120ms var(--rf-ease), color 120ms var(--rf-ease);\n}\n.icon-btn:hover { background: var(--rf-bg-subtle); color: var(--rf-text); }\n\n.body { display: flex; flex-direction: column; gap: 12px; padding: 0 14px 14px; overflow-y: auto; }\n\n.segmented {\n border: 0;\n margin: 0;\n min-inline-size: 0;\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: 1fr;\n gap: 4px;\n padding: 4px;\n background: var(--rf-bg-subtle);\n border-radius: 10px;\n}\n.segmented button {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 32px;\n border-radius: 7px;\n font-size: 13px;\n font-weight: 500;\n color: var(--rf-text-muted);\n transition: background 140ms var(--rf-ease), color 140ms var(--rf-ease);\n}\n.segmented button[aria-pressed=\"true\"] {\n background: var(--rf-bg);\n color: var(--rf-text);\n box-shadow: 0 1px 2px rgb(16 24 40 / 8%);\n}\n\ntextarea, input[type=\"email\"] {\n width: 100%;\n padding: 10px 12px;\n font: inherit;\n color: var(--rf-text);\n background: var(--rf-bg);\n border: 1px solid var(--rf-border);\n border-radius: 10px;\n transition: border-color 140ms var(--rf-ease), box-shadow 140ms var(--rf-ease);\n}\ntextarea { min-height: 92px; max-height: 220px; resize: none; }\ntextarea::placeholder, input::placeholder { color: var(--rf-text-muted); }\ntextarea:focus, input:focus { outline: none; border-color: var(--rf-primary); box-shadow: var(--rf-ring); }\n\n.attachment {\n display: flex;\n gap: 10px;\n padding: 8px;\n border: 1px solid var(--rf-border);\n border-radius: 10px;\n background: var(--rf-bg-subtle);\n}\n.thumb {\n position: relative;\n flex: 0 0 84px;\n height: 56px;\n overflow: hidden;\n border-radius: 6px;\n border: 1px solid var(--rf-border);\n background: var(--rf-bg);\n}\n.thumb img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }\n.attachment .meta { display: flex; flex-direction: column; justify-content: center; gap: 4px; min-width: 0; }\n.attachment .meta strong { font-size: 12.5px; font-weight: 550; }\n.attachment .meta span { font-size: 12px; color: var(--rf-text-muted); }\n.attachment .actions { display: flex; gap: 4px; margin-left: auto; align-items: center; }\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n padding: 5px 8px;\n font-size: 12px;\n border: 1px solid var(--rf-border);\n border-radius: 8px;\n background: var(--rf-bg-subtle);\n color: var(--rf-text-muted);\n}\n.chip code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; color: var(--rf-text); }\n.chip .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n.row { display: flex; gap: 8px; align-items: center; }\n.ghost-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 32px;\n padding: 0 10px;\n font-size: 13px;\n font-weight: 500;\n color: var(--rf-text-muted);\n border: 1px solid var(--rf-border);\n border-radius: 9px;\n transition: background 140ms var(--rf-ease), color 140ms var(--rf-ease);\n}\n.ghost-btn:hover { background: var(--rf-bg-subtle); color: var(--rf-text); }\n\n.submit {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n height: 38px;\n font-weight: 550;\n color: var(--rf-primary-text);\n background: var(--rf-primary);\n border-radius: 10px;\n transition: filter 140ms var(--rf-ease);\n}\n.submit:hover:not(:disabled) { filter: brightness(1.06); }\n.submit:disabled { opacity: 0.55; cursor: not-allowed; }\n\n.error { margin: 0; font-size: 12.5px; color: var(--rf-danger); }\n.hint { margin: 0; font-size: 12px; color: var(--rf-text-muted); }\n\n.footer {\n min-height: 44px;\n padding: 0 14px;\n border-top: 1px solid var(--rf-border);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n font-size: 11.5px;\n color: var(--rf-text-muted);\n}\n.footer[data-dismissible=\"true\"] { justify-content: space-between; }\n.footer a { color: inherit; text-decoration: none; font-weight: 550; }\n.footer a:hover { color: var(--rf-text); }\n.dismiss-btn {\n align-self: stretch;\n color: inherit;\n font-size: 11.5px;\n text-decoration: underline;\n text-underline-offset: 3px;\n}\n.dismiss-btn:hover { color: var(--rf-text); }\n\n.done { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 32px 20px 36px; text-align: center; }\n.done svg { color: var(--rf-success); }\n.done h2 { margin: 0; font-size: 15px; }\n.done p { margin: 0; font-size: 13px; color: var(--rf-text-muted); }\n\n.spinner {\n width: 15px;\n height: 15px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: rf-spin 700ms linear infinite;\n}\n@keyframes rf-spin { to { transform: rotate(360deg); } }\n\n.hp { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }\n\n.overlay {\n position: fixed;\n inset: 0;\n z-index: 2147483001;\n display: flex;\n flex-direction: column;\n background: rgb(9 10 13 / 78%);\n backdrop-filter: blur(2px);\n}\n\n.editor { flex: 1; display: flex; align-items: center; justify-content: center; padding: 24px 24px 0; min-height: 0; }\n.editor canvas {\n max-width: 100%;\n max-height: 100%;\n border-radius: 8px;\n box-shadow: 0 24px 60px -12px rgb(0 0 0 / 60%);\n cursor: crosshair;\n touch-action: none;\n}\n\n.toolbar {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n flex-wrap: wrap;\n padding: 14px 16px calc(14px + env(safe-area-inset-bottom));\n}\n.toolbar .group {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 5px;\n background: var(--rf-bg);\n border: 1px solid var(--rf-border);\n border-radius: 12px;\n box-shadow: var(--rf-shadow);\n}\n.tool {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 34px;\n height: 34px;\n border-radius: 8px;\n color: var(--rf-text-muted);\n transition: background 140ms var(--rf-ease), color 140ms var(--rf-ease);\n}\n.tool:hover { background: var(--rf-bg-subtle); color: var(--rf-text); }\n.tool[aria-pressed=\"true\"] { background: var(--rf-primary); color: var(--rf-primary-text); }\n.swatch {\n width: 22px;\n height: 22px;\n border-radius: 50%;\n border: 2px solid transparent;\n transition: transform 140ms var(--rf-ease);\n}\n.swatch[aria-pressed=\"true\"] { border-color: var(--rf-text); transform: scale(1.12); }\n.toolbar .done-btn {\n height: 34px;\n padding: 0 14px;\n font-weight: 550;\n border-radius: 8px;\n color: var(--rf-primary-text);\n background: var(--rf-primary);\n}\n\n.picker { position: fixed; inset: 0; z-index: 2147483002; cursor: crosshair; }\n.picker-box {\n position: fixed;\n pointer-events: none;\n border: 2px solid var(--rf-primary);\n border-radius: 3px;\n background: color-mix(in srgb, var(--rf-primary) 12%, transparent);\n transition: all 90ms var(--rf-ease);\n}\n.picker-label {\n position: fixed;\n pointer-events: none;\n display: flex;\n align-items: center;\n gap: 6px;\n max-width: min(420px, 90vw);\n padding: 5px 9px;\n font-size: 12px;\n font-weight: 500;\n color: var(--rf-primary-text);\n background: var(--rf-primary);\n border-radius: 7px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.picker-label code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; opacity: 0.82; }\n.picker-hint {\n position: fixed;\n left: 50%;\n bottom: 24px;\n transform: translateX(-50%);\n padding: 9px 14px;\n font-size: 13px;\n color: var(--rf-text);\n background: var(--rf-bg);\n border: 1px solid var(--rf-border);\n border-radius: 10px;\n box-shadow: var(--rf-shadow);\n}\n.picker-hint kbd {\n padding: 1px 5px;\n font: inherit;\n font-size: 11.5px;\n border: 1px solid var(--rf-border);\n border-radius: 4px;\n background: var(--rf-bg-subtle);\n}\n@media (pointer: coarse) {\n .icon-btn, .tool, .swatch {\n width: 44px;\n height: 44px;\n }\n\n .segmented button, .ghost-btn, .submit, .toolbar .done-btn {\n min-height: 44px;\n }\n\n .dismiss-btn, .footer a {\n display: inline-flex;\n min-height: 44px;\n align-items: center;\n }\n\n .footer a {\n min-width: 44px;\n justify-content: center;\n }\n}\n\n`;\n","import { type ReactNode, useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { WIDGET_MARKER } from \"../core/capture\";\nimport { WIDGET_STYLES } from \"./styles\";\n\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\nexport type WidgetTheme = \"auto\" | \"dark\" | \"light\";\n\nfunction useResolvedTheme(theme: WidgetTheme): \"dark\" | \"light\" {\n const [systemDark, setSystemDark] = useState(false);\n\n useEffect(() => {\n if (theme !== \"auto\" || typeof window.matchMedia !== \"function\") {\n return;\n }\n\n const query = window.matchMedia(DARK_QUERY);\n setSystemDark(query.matches);\n\n const onChange = (event: MediaQueryListEvent) =>\n setSystemDark(event.matches);\n query.addEventListener(\"change\", onChange);\n return () => query.removeEventListener(\"change\", onChange);\n }, [theme]);\n\n if (theme === \"auto\") {\n return systemDark ? \"dark\" : \"light\";\n }\n return theme;\n}\n\n/**\n * Hosts the widget in a shadow root: the app's CSS cannot reach the panel and\n * the panel's CSS cannot reach the app. Direct DOM work is unavoidable here —\n * React has no declarative way to create a shadow root.\n */\nexport function ShadowPortal({\n children,\n offset,\n primaryColor,\n theme,\n}: {\n children: ReactNode;\n offset: number;\n primaryColor?: string;\n theme: WidgetTheme;\n}) {\n const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);\n const resolvedTheme = useResolvedTheme(theme);\n\n useEffect(() => {\n const host = document.createElement(\"div\");\n host.setAttribute(WIDGET_MARKER, \"\");\n const root = host.attachShadow({ mode: \"open\" });\n\n const style = document.createElement(\"style\");\n style.textContent = WIDGET_STYLES;\n root.append(style);\n document.body.append(host);\n setShadowRoot(root);\n\n return () => host.remove();\n }, []);\n\n useEffect(() => {\n const host = shadowRoot?.host;\n if (!(host instanceof HTMLElement)) {\n return;\n }\n\n host.setAttribute(\"data-theme\", resolvedTheme);\n host.style.setProperty(\"--rf-offset\", `${offset}px`);\n if (primaryColor) {\n host.style.setProperty(\"--rf-primary\", primaryColor);\n }\n }, [shadowRoot, resolvedTheme, primaryColor, offset]);\n\n if (!shadowRoot) {\n return null;\n }\n\n return createPortal(children, shadowRoot);\n}\n","import type { ConsoleEvent } from \"../../types\";\n\nconst DEFAULT_LIMIT = 30;\nconst MAX_MESSAGE_LENGTH = 1000;\nconst RECORDED_METHODS = [\"error\", \"warn\"] as const;\n\ntype RecordedMethod = (typeof RECORDED_METHODS)[number];\n\nexport interface ConsoleRecorder {\n events: () => ConsoleEvent[];\n stop: () => void;\n}\n\nfunction serializeArgument(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value instanceof Error) {\n return `${value.name}: ${value.message}`;\n }\n if (value === null || value === undefined) {\n return String(value);\n }\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value) ?? \"[unserializable]\";\n } catch {\n return \"[unserializable]\";\n }\n }\n if (typeof value === \"function\") {\n return \"[function]\";\n }\n return String(value);\n}\n\nfunction formatMessage(args: unknown[]): string {\n const message = args.map(serializeArgument).join(\" \");\n return message.length > MAX_MESSAGE_LENGTH\n ? `${message.slice(0, MAX_MESSAGE_LENGTH - 1)}…`\n : message;\n}\n\n/**\n * Buffers the console noise a user saw right before reporting a bug.\n * Wrappers delegate to the previous implementation, so nothing is swallowed.\n */\nexport function startConsoleRecorder(options?: {\n limit?: number;\n}): ConsoleRecorder {\n const limit = options?.limit ?? DEFAULT_LIMIT;\n const buffer: ConsoleEvent[] = [];\n let active = true;\n\n const push = (level: ConsoleEvent[\"level\"], message: string) => {\n if (!(active && message)) {\n return;\n }\n buffer.push({ level, message, timestamp: Date.now() });\n if (buffer.length > limit) {\n buffer.splice(0, buffer.length - limit);\n }\n };\n\n const originals = new Map<RecordedMethod, (...args: unknown[]) => void>();\n const wrappers = new Map<RecordedMethod, (...args: unknown[]) => void>();\n\n for (const method of RECORDED_METHODS) {\n const original = console[method];\n const wrapper = (...args: unknown[]) => {\n push(method, formatMessage(args));\n Reflect.apply(original, console, args);\n };\n originals.set(method, original);\n wrappers.set(method, wrapper);\n console[method] = wrapper;\n }\n\n const onError = (event: ErrorEvent) => {\n const where = event.filename\n ? ` (${event.filename}:${event.lineno}:${event.colno})`\n : \"\";\n push(\"error\", `${event.message}${where}`);\n };\n\n const onRejection = (event: PromiseRejectionEvent) => {\n push(\"error\", `Unhandled rejection: ${serializeArgument(event.reason)}`);\n };\n\n window.addEventListener(\"error\", onError);\n window.addEventListener(\"unhandledrejection\", onRejection);\n\n return {\n events: () => buffer.slice(),\n stop: () => {\n if (!active) {\n return;\n }\n active = false;\n buffer.length = 0;\n\n for (const method of RECORDED_METHODS) {\n const original = originals.get(method);\n // Another recorder wrapped ours — leave its chain intact.\n if (original && console[method] === wrappers.get(method)) {\n console[method] = original;\n }\n }\n\n window.removeEventListener(\"error\", onError);\n window.removeEventListener(\"unhandledrejection\", onRejection);\n },\n };\n}\n","import type { Reflet } from \"../../client\";\nimport type {\n CreateFeedbackParams,\n CreateFeedbackResponse,\n FeedbackContext,\n SaveScreenshotParams,\n} from \"../../types\";\nimport type {\n Annotation,\n CapturedImage,\n FeedbackWidgetCategory,\n} from \"../types\";\nimport { toWireAnnotations } from \"./annotations\";\n\nconst MAX_TITLE_LENGTH = 100;\nconst NEWLINE = /\\r?\\n/;\n\nexport interface FeedbackTransport {\n create: (params: CreateFeedbackParams) => Promise<CreateFeedbackResponse>;\n getScreenshotUploadUrl: () => Promise<{ uploadUrl: string }>;\n saveScreenshot: (\n params: SaveScreenshotParams\n ) => Promise<{ screenshotId: string }>;\n uploadImage: (uploadUrl: string, image: CapturedImage) => Promise<string>;\n}\n\nexport interface WidgetSubmission {\n annotated: CapturedImage | null;\n annotations: Annotation[];\n category: FeedbackWidgetCategory;\n context: FeedbackContext;\n email?: string;\n isAnonymous: boolean;\n message: string;\n screenshot: CapturedImage | null;\n}\n\nexport interface SubmitResult {\n feedbackId: string;\n screenshotSaved: boolean;\n}\n\n/** First line of the message, cut on a word boundary so titles stay readable. */\nexport function deriveTitle(message: string): string {\n const firstLine =\n message\n .split(NEWLINE)\n .map((line) => line.trim())\n .find(Boolean) ?? \"\";\n\n if (firstLine.length <= MAX_TITLE_LENGTH) {\n return firstLine;\n }\n\n const clipped = firstLine.slice(0, MAX_TITLE_LENGTH - 1);\n const lastSpace = clipped.lastIndexOf(\" \");\n return `${(lastSpace > 0 ? clipped.slice(0, lastSpace) : clipped).trimEnd()}…`;\n}\n\nexport function buildDescription(params: {\n category: FeedbackWidgetCategory;\n email?: string;\n isAnonymous: boolean;\n message: string;\n}): string {\n const { category, email, isAnonymous, message } = params;\n const label = category.charAt(0).toUpperCase() + category.slice(1);\n const contact = isAnonymous && email ? `\\n\\n---\\nContact: ${email}` : \"\";\n\n return `[${label}] ${message.trim()}${contact}`;\n}\n\nasync function attachScreenshot(\n transport: FeedbackTransport,\n feedbackId: string,\n submission: WidgetSubmission\n): Promise<boolean> {\n const { annotated, annotations, context, screenshot } = submission;\n if (!screenshot) {\n return false;\n }\n\n const original = await transport.getScreenshotUploadUrl();\n const storageId = await transport.uploadImage(original.uploadUrl, screenshot);\n\n let annotatedStorageId: string | undefined;\n if (annotated) {\n const target = await transport.getScreenshotUploadUrl();\n annotatedStorageId = await transport.uploadImage(\n target.uploadUrl,\n annotated\n );\n }\n\n const wireAnnotations = toWireAnnotations(annotations);\n\n await transport.saveScreenshot({\n annotatedStorageId,\n annotations: wireAnnotations.length > 0 ? wireAnnotations : undefined,\n feedbackId,\n filename: \"screenshot.png\",\n height: screenshot.height,\n mimeType: screenshot.mimeType,\n pageUrl: context.url,\n size: screenshot.blob.size,\n storageId,\n width: screenshot.width,\n });\n\n return true;\n}\n\n/**\n * Creates the feedback first, then attaches the capture. A failed upload is\n * reported back but never discards what the user wrote.\n */\nexport async function submitWidgetFeedback(\n transport: FeedbackTransport,\n submission: WidgetSubmission\n): Promise<SubmitResult> {\n const title = deriveTitle(submission.message);\n if (!title) {\n throw new Error(\"Please describe your feedback before sending it.\");\n }\n\n const { feedbackId } = await transport.create({\n context: submission.context,\n description: buildDescription(submission),\n title,\n });\n\n let screenshotSaved = false;\n try {\n screenshotSaved = await attachScreenshot(transport, feedbackId, submission);\n } catch {\n screenshotSaved = false;\n }\n\n return { feedbackId, screenshotSaved };\n}\n\nfunction isStorageResponse(value: unknown): value is { storageId: string } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof Reflect.get(value, \"storageId\") === \"string\"\n );\n}\n\nexport function createFeedbackTransport(client: Reflet): FeedbackTransport {\n return {\n create: (params) => client.create(params),\n getScreenshotUploadUrl: () => client.getScreenshotUploadUrl(),\n saveScreenshot: (params) => client.saveScreenshot(params),\n uploadImage: async (uploadUrl, image) => {\n const response = await fetch(uploadUrl, {\n body: image.blob,\n headers: { \"Content-Type\": image.mimeType },\n method: \"POST\",\n });\n\n if (!response.ok) {\n throw new Error(`Screenshot upload failed (${response.status})`);\n }\n\n const payload: unknown = await response.json();\n if (!isStorageResponse(payload)) {\n throw new Error(\"Screenshot upload returned no storage id\");\n }\n\n return payload.storageId;\n },\n };\n}\n","import {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Reflet } from \"../../client\";\nimport { RefletContext } from \"../../react-context\";\nimport type { ElementSelection } from \"../../types\";\nimport { renderAnnotatedImage } from \"../core/annotation-renderer\";\nimport { captureViewport, releaseCapture } from \"../core/capture\";\nimport {\n type ConsoleRecorder,\n startConsoleRecorder,\n} from \"../core/console-recorder\";\nimport { buildElementSelection } from \"../core/element-selector\";\nimport { collectPageContext } from \"../core/page-context\";\nimport { createFeedbackTransport, submitWidgetFeedback } from \"../core/submit\";\nimport {\n type Annotation,\n type CapturedImage,\n type FeedbackWidgetCategory,\n type RefletFeedbackProps,\n SDK_VERSION,\n type WidgetStep,\n} from \"../types\";\n\nconst SUCCESS_CLOSE_DELAY = 2400;\nconst IS_APPLE = /Mac|iPhone|iPad/;\nconst MILLISECONDS_PER_DAY = 86_400_000;\nconst DISMISSAL_STORAGE_PREFIX = \"reflet-feedback-dismissed\";\n\nfunction readDismissedUntil(key: string): number {\n if (typeof window === \"undefined\") {\n return 0;\n }\n\n try {\n const value = Number.parseInt(window.localStorage.getItem(key) ?? \"\", 10);\n if (Number.isFinite(value) && value > Date.now()) {\n return value;\n }\n window.localStorage.removeItem(key);\n } catch {\n return 0;\n }\n\n return 0;\n}\n\nfunction writeDismissedUntil(key: string, until: number): void {\n try {\n window.localStorage.setItem(key, String(until));\n } catch {\n // storage blocked (private mode, quota) — dismissal just does not persist\n }\n}\n\n/**\n * Matches shortcuts written as `alt+f` or `mod+shift+k`, where `mod` is the\n * platform's command key.\n */\nexport function matchesHotkey(\n event: Pick<\n KeyboardEvent,\n \"altKey\" | \"ctrlKey\" | \"key\" | \"metaKey\" | \"shiftKey\"\n >,\n hotkey: string,\n platform = typeof navigator === \"undefined\" ? \"\" : navigator.platform\n): boolean {\n const parts = hotkey\n .toLowerCase()\n .split(\"+\")\n .map((part) => part.trim());\n const key = parts.at(-1);\n if (!key || event.key.toLowerCase() !== key) {\n return false;\n }\n\n const isApple = IS_APPLE.test(platform);\n const wantsMod = parts.includes(\"mod\");\n const expected = {\n alt: parts.includes(\"alt\") || parts.includes(\"option\"),\n ctrl: parts.includes(\"ctrl\") || (wantsMod && !isApple),\n meta:\n parts.includes(\"meta\") || parts.includes(\"cmd\") || (wantsMod && isApple),\n shift: parts.includes(\"shift\"),\n };\n\n return (\n event.altKey === expected.alt &&\n event.ctrlKey === expected.ctrl &&\n event.metaKey === expected.meta &&\n event.shiftKey === expected.shift\n );\n}\n\nfunction highlightFor(\n selection: ElementSelection,\n capture: CapturedImage\n): Annotation {\n const scale = capture.width / window.innerWidth;\n const { rect } = selection;\n\n return {\n color: \"#4f46e5\",\n end: {\n x: (rect.x + rect.width) * scale,\n y: (rect.y + rect.height) * scale,\n },\n id: `selection-${rect.x}-${rect.y}`,\n start: { x: rect.x * scale, y: rect.y * scale },\n tool: \"rectangle\",\n };\n}\n\nexport function useWidgetState(props: RefletFeedbackProps) {\n const context = useContext(RefletContext);\n const publicKey = props.publicKey ?? context?.publicKey;\n const baseUrl = props.baseUrl ?? context?.baseUrl;\n const user = props.user ?? context?.user;\n const userToken = props.userToken ?? context?.userToken;\n const isAnonymous = !(user || userToken);\n const dismissForDays =\n props.dismissForDays !== undefined &&\n Number.isFinite(props.dismissForDays) &&\n props.dismissForDays > 0\n ? props.dismissForDays\n : null;\n const dismissalKey = `${DISMISSAL_STORAGE_PREFIX}:${publicKey ?? \"default\"}:${user?.id ?? \"anonymous\"}`;\n\n const [isOpen, setIsOpen] = useState(false);\n const [step, setStep] = useState<WidgetStep>(\"compose\");\n const [category, setCategory] = useState<FeedbackWidgetCategory>(\n props.defaultCategory ?? \"bug\"\n );\n const [message, setMessage] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [honeypot, setHoneypot] = useState(\"\");\n const [capture, setCapture] = useState<CapturedImage | null>(null);\n const [annotations, setAnnotations] = useState<Annotation[]>([]);\n const [selection, setSelection] = useState<ElementSelection | null>(null);\n const [isCapturing, setIsCapturing] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [dismissedUntil, setDismissedUntil] = useState(() =>\n readDismissedUntil(dismissalKey)\n );\n\n const captureRef = useRef<CapturedImage | null>(null);\n const consoleRef = useRef<ConsoleRecorder | null>(null);\n\n useEffect(() => {\n captureRef.current = capture;\n }, [capture]);\n useEffect(() => {\n setDismissedUntil(readDismissedUntil(dismissalKey));\n }, [dismissalKey]);\n\n useEffect(() => {\n if (props.captureConsole === false) {\n return;\n }\n const recorder = startConsoleRecorder();\n consoleRef.current = recorder;\n return () => {\n consoleRef.current = null;\n recorder.stop();\n };\n }, [props.captureConsole]);\n\n useEffect(\n () => () => {\n releaseCapture(captureRef.current);\n },\n []\n );\n\n const replaceCapture = useCallback((next: CapturedImage | null) => {\n releaseCapture(captureRef.current);\n setCapture(next);\n }, []);\n\n const takeCapture = useCallback(\n (element?: Element): void => {\n setIsCapturing(true);\n captureViewport({ element })\n .catch(() => null)\n .then((image) => {\n setIsCapturing(false);\n replaceCapture(image);\n });\n },\n [replaceCapture]\n );\n\n const reset = useCallback(() => {\n releaseCapture(captureRef.current);\n setCapture(null);\n setAnnotations([]);\n setSelection(null);\n setMessage(\"\");\n setEmail(\"\");\n setHoneypot(\"\");\n setError(null);\n setStep(\"compose\");\n setCategory(props.defaultCategory ?? \"bug\");\n }, [props.defaultCategory]);\n\n const close = useCallback(() => {\n setIsOpen(false);\n reset();\n props.onClose?.();\n }, [reset, props.onClose]);\n const dismiss = useCallback(() => {\n if (dismissForDays === null) {\n return;\n }\n\n const until = Date.now() + dismissForDays * MILLISECONDS_PER_DAY;\n writeDismissedUntil(dismissalKey, until);\n setIsOpen(false);\n reset();\n setDismissedUntil(until);\n props.onDismiss?.({ until });\n }, [dismissForDays, dismissalKey, props.onDismiss, reset]);\n\n const open = useCallback(() => {\n setIsOpen(true);\n setStep(\"compose\");\n props.onOpen?.();\n if (props.captureOnOpen !== false) {\n takeCapture();\n }\n }, [props.captureOnOpen, props.onOpen, takeCapture]);\n\n const selectElement = useCallback((element: Element) => {\n const picked = buildElementSelection(element);\n setSelection(picked);\n setStep(\"compose\");\n\n const current = captureRef.current;\n if (current) {\n setAnnotations((previous) => [\n ...previous.filter((item) => !item.id.startsWith(\"selection-\")),\n highlightFor(picked, current),\n ]);\n }\n }, []);\n\n const clearSelection = useCallback(() => {\n setSelection(null);\n setAnnotations((previous) =>\n previous.filter((item) => !item.id.startsWith(\"selection-\"))\n );\n }, []);\n\n const removeCapture = useCallback(() => {\n replaceCapture(null);\n setAnnotations([]);\n }, [replaceCapture]);\n\n const client = useMemo(\n () =>\n publicKey ? new Reflet({ baseUrl, publicKey, user, userToken }) : null,\n [baseUrl, publicKey, user, userToken]\n );\n\n const submit = useCallback(async () => {\n if (honeypot) {\n setStep(\"success\");\n return;\n }\n if (!client) {\n setError(\n \"Reflet is missing a publicKey. Pass one to RefletFeedback or RefletProvider.\"\n );\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n\n let annotated: CapturedImage | null = null;\n\n try {\n annotated = capture\n ? await renderAnnotatedImage(capture, annotations)\n : null;\n\n const result = await submitWidgetFeedback(\n createFeedbackTransport(client),\n {\n annotated,\n annotations,\n category,\n context: {\n ...collectPageContext({ sdkVersion: SDK_VERSION }),\n consoleEvents: consoleRef.current?.events(),\n metadata: props.metadata,\n selection: selection ?? undefined,\n },\n email,\n isAnonymous,\n message,\n screenshot: capture,\n }\n );\n\n setStep(\"success\");\n props.onSubmit?.({ feedbackId: result.feedbackId });\n setTimeout(close, SUCCESS_CLOSE_DELAY);\n } catch (submitError) {\n setError(\n submitError instanceof Error\n ? submitError.message\n : \"Something went wrong. Please try again.\"\n );\n } finally {\n releaseCapture(annotated);\n setIsSubmitting(false);\n }\n }, [\n annotations,\n capture,\n category,\n client,\n close,\n email,\n honeypot,\n isAnonymous,\n message,\n props.metadata,\n props.onSubmit,\n selection,\n ]);\n\n return {\n annotations,\n canDismiss: dismissForDays !== null,\n capture,\n category,\n clearSelection,\n close,\n dismiss,\n dismissForDays,\n email,\n error,\n honeypot,\n isAnonymous,\n isCapturing,\n isDismissed: dismissedUntil > Date.now(),\n isOpen,\n isSubmitting,\n message,\n open,\n removeCapture,\n selectElement,\n selection,\n setAnnotations,\n setCategory,\n setEmail,\n setHoneypot,\n setMessage,\n setStep,\n step,\n submit,\n takeCapture,\n };\n}\n\nexport type WidgetState = ReturnType<typeof useWidgetState>;\n","import { useEffect } from \"react\";\nimport {\n DEFAULT_WIDGET_LABELS,\n type FeedbackWidgetCategory,\n type RefletFeedbackProps,\n} from \"./types\";\nimport { Annotator } from \"./ui/annotator\";\nimport { Launcher } from \"./ui/launcher\";\nimport { FeedbackPanel } from \"./ui/panel\";\nimport { ElementPicker } from \"./ui/picker\";\nimport { ShadowPortal } from \"./ui/shadow-portal\";\nimport { matchesHotkey, useWidgetState } from \"./ui/use-widget-state\";\n\nconst DEFAULT_CATEGORIES: FeedbackWidgetCategory[] = [\n \"bug\",\n \"idea\",\n \"question\",\n];\nconst DEFAULT_OFFSET = 20;\n\n/**\n * Floating feedback button with a screenshot, annotation and element picker\n * flow. Mount it once, anywhere below `RefletProvider` or with its own\n * `publicKey`.\n */\nexport function RefletFeedback(props: RefletFeedbackProps) {\n const {\n categories = DEFAULT_CATEGORIES,\n enabled = true,\n hotkey = null,\n offset = DEFAULT_OFFSET,\n position = \"bottom-right\",\n theme = \"auto\",\n } = props;\n\n const labels = { ...DEFAULT_WIDGET_LABELS, ...props.labels };\n const state = useWidgetState(props);\n const { close, isOpen, open } = state;\n\n useEffect(() => {\n if (!(hotkey && enabled)) {\n return;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (matchesHotkey(event, hotkey)) {\n event.preventDefault();\n if (isOpen) {\n close();\n } else {\n open();\n }\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [close, enabled, hotkey, isOpen, open]);\n\n useEffect(() => {\n if (!isOpen || state.step !== \"compose\") {\n return;\n }\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n close();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [close, isOpen, state.step]);\n\n if (!enabled || state.isDismissed) {\n return null;\n }\n\n const showPanel =\n isOpen && state.step !== \"picking\" && state.step !== \"annotate\";\n\n return (\n <ShadowPortal\n offset={offset}\n primaryColor={props.primaryColor}\n theme={theme}\n >\n <div className=\"root\" data-position={position}>\n <div className=\"stack\">\n {showPanel && (\n <FeedbackPanel\n categories={categories}\n labels={labels}\n state={state}\n />\n )}\n <Launcher\n compact={isOpen}\n isOpen={isOpen}\n label={labels.trigger}\n onClick={isOpen ? close : open}\n />\n </div>\n </div>\n\n {isOpen && state.step === \"annotate\" && state.capture && (\n <Annotator\n annotations={state.annotations}\n capture={state.capture}\n labels={labels}\n onChange={state.setAnnotations}\n onDone={() => state.setStep(\"compose\")}\n />\n )}\n\n {isOpen && state.step === \"picking\" && (\n <ElementPicker\n hint={labels.pickElementHint}\n onCancel={() => state.setStep(\"compose\")}\n onPick={state.selectElement}\n />\n )}\n </ShadowPortal>\n );\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,302 +1,3 @@
1
- /**
2
- * Reflet SDK Types
3
- */
4
- interface RefletConfig {
5
- /** Your board's public API key (fb_pub_xxx) */
6
- publicKey: string;
7
- /** API base URL (optional, defaults to Reflet production API) */
8
- baseUrl?: string;
9
- /** User identification for SSO */
10
- user?: RefletUser;
11
- /** Pre-signed user token (alternative to user object) */
12
- userToken?: string;
13
- }
14
- interface RefletUser {
15
- /** Unique identifier for the user in your system */
16
- id: string;
17
- /** User's email address */
18
- email?: string;
19
- /** User's display name */
20
- name?: string;
21
- /** URL to user's avatar image */
22
- avatar?: string;
23
- /** Additional metadata */
24
- metadata?: Record<string, unknown>;
25
- }
26
- interface BoardConfig {
27
- id: string;
28
- name: string;
29
- slug: string;
30
- description?: string;
31
- isPublic: boolean;
32
- settings?: BoardSettings;
33
- organization: {
34
- id: string;
35
- name: string;
36
- slug: string;
37
- logo?: string;
38
- primaryColor?: string;
39
- };
40
- statuses: BoardStatus[];
41
- }
42
- interface BoardSettings {
43
- allowAnonymousVoting?: boolean;
44
- requireApproval?: boolean;
45
- defaultStatus?: FeedbackStatus;
46
- }
47
- interface BoardStatus {
48
- id: string;
49
- name: string;
50
- color: string;
51
- icon?: string;
52
- order: number;
53
- }
54
- type FeedbackStatus = "open" | "under_review" | "planned" | "in_progress" | "completed" | "closed";
55
- interface FeedbackItem {
56
- id: string;
57
- title: string;
58
- description: string;
59
- status: FeedbackStatus;
60
- voteCount: number;
61
- commentCount: number;
62
- isPinned: boolean;
63
- hasVoted: boolean;
64
- createdAt: number;
65
- updatedAt: number;
66
- completedAt?: number;
67
- tags: FeedbackTag[];
68
- boardStatus: {
69
- id: string;
70
- name: string;
71
- color: string;
72
- } | null;
73
- author: FeedbackAuthor | null;
74
- }
75
- interface FeedbackDetail extends FeedbackItem {
76
- isSubscribed: boolean;
77
- }
78
- interface FeedbackTag {
79
- id: string;
80
- name: string;
81
- color: string;
82
- }
83
- interface FeedbackAuthor {
84
- name?: string;
85
- email?: string;
86
- avatar?: string;
87
- isExternal: boolean;
88
- }
89
- interface FeedbackListResponse {
90
- items: FeedbackItem[];
91
- total: number;
92
- hasMore: boolean;
93
- }
94
- interface FeedbackListParams {
95
- /** Filter by custom status ID */
96
- statusId?: string;
97
- /** Filter by status name */
98
- status?: FeedbackStatus;
99
- /** Search in title and description */
100
- search?: string;
101
- /** Sort order */
102
- sortBy?: "votes" | "newest" | "oldest" | "comments";
103
- /** Number of items to return (max 100) */
104
- limit?: number;
105
- /** Offset for pagination */
106
- offset?: number;
107
- }
108
- interface CreateFeedbackParams {
109
- title: string;
110
- description: string;
111
- }
112
- interface CreateFeedbackResponse {
113
- feedbackId: string;
114
- isApproved: boolean;
115
- }
116
- interface VoteResponse {
117
- voted: boolean;
118
- voteCount: number;
119
- }
120
- interface Comment {
121
- id: string;
122
- body: string;
123
- isOfficial: boolean;
124
- author: FeedbackAuthor | null;
125
- replies: CommentReply[];
126
- createdAt: number;
127
- updatedAt: number;
128
- }
129
- interface CommentReply {
130
- id: string;
131
- body: string;
132
- isOfficial: boolean;
133
- author: FeedbackAuthor | null;
134
- createdAt: number;
135
- updatedAt: number;
136
- }
137
- interface AddCommentParams {
138
- feedbackId: string;
139
- body: string;
140
- parentId?: string;
141
- }
142
- interface AddCommentResponse {
143
- commentId: string;
144
- }
145
- interface SubscribeResponse {
146
- subscribed: boolean;
147
- alreadySubscribed?: boolean;
148
- }
149
- interface UnsubscribeResponse {
150
- unsubscribed: boolean;
151
- wasNotSubscribed?: boolean;
152
- }
153
- interface Roadmap {
154
- lanes: RoadmapLane[];
155
- }
156
- interface RoadmapLane {
157
- id: string;
158
- name: string;
159
- color: string;
160
- items: RoadmapItem[];
161
- }
162
- interface RoadmapItem {
163
- id: string;
164
- title: string;
165
- status: FeedbackStatus;
166
- voteCount: number;
167
- }
168
- interface ChangelogEntry {
169
- id: string;
170
- title: string;
171
- description?: string;
172
- version?: string;
173
- publishedAt?: number;
174
- feedback: {
175
- id: string;
176
- title: string;
177
- }[];
178
- }
179
- declare class RefletError extends Error {
180
- readonly status: number;
181
- readonly code?: string;
182
- constructor(message: string, status: number, code?: string);
183
- }
184
- declare class RefletAuthError extends RefletError {
185
- constructor(message: string);
186
- }
187
- declare class RefletValidationError extends RefletError {
188
- constructor(message: string);
189
- }
190
- declare class RefletNotFoundError extends RefletError {
191
- constructor(message: string);
192
- }
193
-
194
- /**
195
- * Reflet SDK Client
196
- *
197
- * @example
198
- * ```ts
199
- * import { Reflet } from 'reflet-sdk';
200
- *
201
- * const reflet = new Reflet({
202
- * publicKey: 'fb_pub_xxx',
203
- * user: { id: 'user_123', email: 'user@example.com', name: 'John' }
204
- * });
205
- *
206
- * // List feedback
207
- * const { items } = await reflet.list({ status: 'open' });
208
- *
209
- * // Vote on feedback
210
- * await reflet.vote('feedback_id');
211
- *
212
- * // Submit new feedback
213
- * await reflet.create({ title: 'Great idea', description: 'Details...' });
214
- * ```
215
- */
216
- declare class Reflet {
217
- private readonly publicKey;
218
- private readonly baseUrl;
219
- private userToken;
220
- private user;
221
- constructor(config: RefletConfig);
222
- /**
223
- * Update the user identification
224
- */
225
- setUser(user: RefletUser | undefined): void;
226
- /**
227
- * Set the user token directly (for server-signed tokens)
228
- */
229
- setUserToken(token: string | undefined): void;
230
- /**
231
- * Get the board configuration
232
- */
233
- getConfig(): Promise<BoardConfig>;
234
- /**
235
- * List feedback items with optional filtering
236
- */
237
- list(params?: FeedbackListParams): Promise<FeedbackListResponse>;
238
- /**
239
- * Get a single feedback item by ID
240
- */
241
- get(feedbackId: string): Promise<FeedbackDetail>;
242
- /**
243
- * Create new feedback
244
- * Requires user identification
245
- */
246
- create(params: CreateFeedbackParams): Promise<CreateFeedbackResponse>;
247
- /**
248
- * Toggle vote on feedback
249
- * Requires user identification
250
- */
251
- vote(feedbackId: string, type?: "upvote" | "downvote"): Promise<VoteResponse>;
252
- /**
253
- * Get comments for a feedback item
254
- */
255
- getComments(feedbackId: string, sortBy?: "newest" | "oldest"): Promise<Comment[]>;
256
- /**
257
- * Add a comment to feedback
258
- * Requires user identification
259
- */
260
- comment(params: AddCommentParams): Promise<AddCommentResponse>;
261
- /**
262
- * Subscribe to feedback updates
263
- * Requires user identification
264
- */
265
- subscribe(feedbackId: string): Promise<SubscribeResponse>;
266
- /**
267
- * Unsubscribe from feedback updates
268
- * Requires user identification
269
- */
270
- unsubscribe(feedbackId: string): Promise<UnsubscribeResponse>;
271
- /**
272
- * Get roadmap data
273
- */
274
- getRoadmap(): Promise<Roadmap>;
275
- /**
276
- * Get changelog entries
277
- */
278
- getChangelog(limit?: number): Promise<ChangelogEntry[]>;
279
- /**
280
- * Build request headers with authentication
281
- */
282
- private buildHeaders;
283
- /**
284
- * Parse JSON response text safely
285
- */
286
- private parseJsonSafely;
287
- /**
288
- * Throw appropriate error based on status code
289
- */
290
- private throwHttpError;
291
- /**
292
- * Make an authenticated API request
293
- */
294
- private request;
295
- /**
296
- * Generate a simple user token for client-side use
297
- * Note: For production, use server-side token signing
298
- */
299
- private generateUserToken;
300
- }
301
-
302
- export { type AddCommentParams, type AddCommentResponse, type BoardConfig, type BoardSettings, type BoardStatus, type ChangelogEntry, type Comment, type CommentReply, type CreateFeedbackParams, type CreateFeedbackResponse, type FeedbackAuthor, type FeedbackDetail, type FeedbackItem, type FeedbackListParams, type FeedbackListResponse, type FeedbackStatus, type FeedbackTag, Reflet, RefletAuthError, type RefletConfig, RefletError, RefletNotFoundError, type RefletUser, RefletValidationError, type Roadmap, type RoadmapItem, type RoadmapLane, type SubscribeResponse, type UnsubscribeResponse, type VoteResponse };
1
+ import { A as SubscribeResponse, C as RefletNotFoundError, D as RoadmapItem, E as Roadmap, M as VoteResponse, O as RoadmapLane, S as RefletError, T as RefletValidationError, _ as OrganizationConfig, a as CommentReply, b as RefletAuthError, d as FeedbackDetail, f as FeedbackItem, g as FeedbackTag, h as FeedbackStatus, i as Comment, j as UnsubscribeResponse, l as FeedbackAuthor, m as FeedbackListResponse, n as AddCommentResponse, o as CreateFeedbackParams, p as FeedbackListParams, r as ChangelogEntry, s as CreateFeedbackResponse, t as AddCommentParams, v as OrganizationSettings, w as RefletUser, x as RefletConfig, y as OrganizationStatus } from "./types-xyOadyfX.js";
2
+ import { t as Reflet } from "./client-Bi-GlSii.js";
3
+ export { type AddCommentParams, type AddCommentResponse, type ChangelogEntry, type Comment, type CommentReply, type CreateFeedbackParams, type CreateFeedbackResponse, type FeedbackAuthor, type FeedbackDetail, type FeedbackItem, type FeedbackListParams, type FeedbackListResponse, type FeedbackStatus, type FeedbackTag, type OrganizationConfig, type OrganizationSettings, type OrganizationStatus, Reflet, RefletAuthError, type RefletConfig, RefletError, RefletNotFoundError, type RefletUser, RefletValidationError, type Roadmap, type RoadmapItem, type RoadmapLane, type SubscribeResponse, type UnsubscribeResponse, type VoteResponse };
package/dist/index.js CHANGED
@@ -1,3 +1,2 @@
1
- export { Reflet, RefletAuthError, RefletError, RefletNotFoundError, RefletValidationError } from './chunk-U7TQSXOE.js';
2
- //# sourceMappingURL=index.js.map
3
- //# sourceMappingURL=index.js.map
1
+ import { a as RefletValidationError, i as RefletNotFoundError, n as RefletAuthError, r as RefletError, t as Reflet } from "./client-BYuSKJw5.js";
2
+ export { Reflet, RefletAuthError, RefletError, RefletNotFoundError, RefletValidationError };