blocfeed 0.7.3 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.1 — 2026-02-24
4
+
5
+ ### Bug fixes
6
+
7
+ - **Recording flow: widget no longer closes when clicking the page** — During video recording, the overlay and backdrop are removed so users can freely interact with the page to demonstrate bugs. The full panel collapses into a compact floating recording bar (pulsing dot + timer + stop button) positioned at the widget corner. When recording stops, the panel re-opens with the video preview attached.
8
+
9
+ ---
10
+
11
+ ## 0.8.0 — 2026-02-24
12
+
13
+ ### New features
14
+
15
+ - **Video recording** — Users can record a short screen capture clip alongside their feedback to demonstrate bug reproduction steps. Uses the browser's Screen Capture API (`getDisplayMedia`) with WebM output via `MediaRecorder`.
16
+ - Enabled via `config.recording.enabled: true` (off by default)
17
+ - Configurable max duration (`maxDurationMs`, default 30s) with auto-stop
18
+ - Configurable bitrate (`videoBitsPerSecond`, default 2.5 Mbps, ~9 MB for 30s)
19
+ - Codec negotiation: VP9 → VP8 → plain WebM
20
+ - Record button appears in review phase; pulsing red dot + timer during recording
21
+ - Video preview with playback controls before submission
22
+ - Direct upload to object storage via presigned URL (no server proxy)
23
+ - Auto-hidden on unsupported browsers (Safari, older browsers without `getDisplayMedia` + WebM `MediaRecorder`)
24
+ - **Programmatic recording API** — `startRecording()` and `stopRecording()` on `BlocFeedHandle` ref and `useBlocFeed()` hook
25
+
26
+ ### Improvements
27
+
28
+ - New types exported: `RecordingConfig`, `VideoAsset`, `VideoIntent`, `VideoMime`.
29
+ - Engine exports: `startRecording`, `isRecordingSupported`, `RecordingSession` for headless usage.
30
+ - `BlocFeedStrings` extended with `recordButton`, `stopRecordButton`, `recordingText`, `recordingDeniedText`, `videoPreviewLabel`, `removeVideoButton`.
31
+ - Offline queue now strips video blobs (in addition to screenshots) before `localStorage` serialization.
32
+ - `SessionPhase` extended with `"recording"` phase.
33
+ - `BlocFeedError.kind` extended with `"recording_failed"`.
34
+
35
+ ### Platform changes (blocfeed-frontend)
36
+
37
+ - New SQL migration `scripts/032_video_recording.sql` adds `video_url`, `video_mime`, `video_duration_ms`, `video_size_bytes`, `video_uploaded_at` columns with partial index.
38
+ - `POST /api/feedback` now accepts `video_intent`, inserts video metadata, and returns `upload_urls.video` presigned URL.
39
+ - New `POST /api/feedback/:id/video` fallback endpoint for uploading video blobs when presigned URLs are unavailable.
40
+ - Dashboard feedback detail panel shows a Video tab with `<video>` player when a recording is attached.
41
+ - Fixed `createPresignedUploadUrl` default content type from `"audio/webm"` to `"application/octet-stream"`.
42
+
43
+ ---
44
+
3
45
  ## 0.7.3 — 2026-02-23
4
46
 
5
47
  ### Improvements
package/README.md CHANGED
@@ -15,6 +15,7 @@ Drop-in in-app feedback widget for **Next.js** and **React**:
15
15
  - **Dark / Light mode** — `"dark"`, `"light"`, or `"auto"` (follows system preference)
16
16
  - **Conditional display** — show/hide widget by route pattern or custom predicate
17
17
  - **Programmatic API** — `ref.open()`, `ref.close()`, `ref.submit(msg)` via React ref
18
+ - **Video recording** — record a short screen capture clip (via `getDisplayMedia`) to show bug reproduction steps
18
19
  - **Secret leak detection** — scans client-side code for exposed API keys, database credentials, and tokens
19
20
 
20
21
  Docs live in `docs/` (start at `docs/index.md`). Architecture pointers are in `ARCHITECTURE.md`.
@@ -132,6 +133,13 @@ All configuration is passed via the `config` prop on `<BlocFeedWidget>` or `<Blo
132
133
  // ignoreUrls: [], // override default blocked domains (see docs below)
133
134
  },
134
135
 
136
+ // Video recording (screen capture)
137
+ recording: {
138
+ enabled: true,
139
+ maxDurationMs: 30_000,
140
+ videoBitsPerSecond: 2_500_000,
141
+ },
142
+
135
143
  // Screenshot defaults
136
144
  capture: {
137
145
  element: true,
@@ -601,7 +609,7 @@ When a submission fails due to a network error, the payload is automatically sav
601
609
  - On the next page load (1s after controller initialization)
602
610
  - When the browser comes back online (`online` event)
603
611
 
604
- Screenshots are stripped from queued payloads to stay within `localStorage` limits. The queue holds up to 50 items (FIFO eviction).
612
+ Screenshots and video recordings are stripped from queued payloads to stay within `localStorage` limits. The queue holds up to 50 items (FIFO eviction).
605
613
 
606
614
  ## Picking rules (ignore / filter)
607
615
 
@@ -652,6 +660,85 @@ Screenshots are uploaded efficiently using a two-phase flow:
652
660
 
653
661
  Both **element** and **full-page** screenshots are supported and stored on the platform.
654
662
 
663
+ ## Video Recording
664
+
665
+ Let users record a short screen capture clip alongside their feedback. Uses the browser's Screen Capture API (`getDisplayMedia`) to record the current tab as WebM video.
666
+
667
+ ```tsx
668
+ <BlocFeedWidget
669
+ blocfeed_id="bf_..."
670
+ config={{
671
+ recording: {
672
+ enabled: true, // default: false
673
+ maxDurationMs: 30_000, // default: 30s — auto-stops at this limit
674
+ videoBitsPerSecond: 2_500_000, // default: 2.5 Mbps (~9 MB for 30s)
675
+ },
676
+ }}
677
+ />
678
+ ```
679
+
680
+ ### `RecordingConfig` options
681
+
682
+ | Option | Type | Default | Description |
683
+ |--------|------|---------|-------------|
684
+ | `enabled` | `boolean` | `false` | Show the Record button in the review phase |
685
+ | `maxDurationMs` | `number` | `30000` | Maximum recording duration in ms. Auto-stops when reached |
686
+ | `mime` | `"video/webm"` | `"video/webm"` | Output format (WebM is the only supported format) |
687
+ | `videoBitsPerSecond` | `number` | `2500000` | Video bitrate. Lower = smaller files, faster uploads |
688
+
689
+ ### Bitrate & file size guide
690
+
691
+ | `videoBitsPerSecond` | 30s file size | Upload time (10 Mbps) |
692
+ |---|---|---|
693
+ | `1_000_000` (1 Mbps) | ~3.75 MB | ~3s |
694
+ | `2_500_000` (2.5 Mbps) | ~9.4 MB | ~7s |
695
+ | `5_000_000` (5 Mbps) | ~18.8 MB | ~15s |
696
+
697
+ Lower bitrates are fine for bug reproduction clips. 2.5 Mbps (default) gives crisp screen recordings.
698
+
699
+ ### How it works
700
+
701
+ 1. A **Record** button appears in the review phase (after element selection)
702
+ 2. Clicking it triggers the browser's screen sharing permission prompt
703
+ 3. A pulsing red dot + elapsed timer shows during recording
704
+ 4. Recording stops when the user clicks **Stop**, the max duration is reached, or the browser's "Stop sharing" button is clicked
705
+ 5. A video preview with playback controls appears — the user can remove it or submit
706
+ 6. On submit, the video is uploaded directly to object storage via a presigned URL
707
+
708
+ ### Browser support
709
+
710
+ Video recording requires `getDisplayMedia` and `MediaRecorder` with WebM support. The Record button is **automatically hidden** on unsupported browsers.
711
+
712
+ | Browser | Supported |
713
+ |---------|-----------|
714
+ | Chrome / Edge | Yes |
715
+ | Firefox | Yes |
716
+ | Safari 16+ | No (WebM not supported by MediaRecorder) |
717
+
718
+ ### Programmatic API
719
+
720
+ ```tsx
721
+ const ref = useRef<BlocFeedHandle>(null);
722
+
723
+ ref.current?.startRecording(); // start recording (must be in review phase)
724
+ ref.current?.stopRecording(); // stop recording
725
+ ```
726
+
727
+ ### Localization
728
+
729
+ Override recording-related UI text via `config.ui.strings`:
730
+
731
+ ```tsx
732
+ strings: {
733
+ recordButton: "Record",
734
+ stopRecordButton: "Stop",
735
+ recordingText: "Recording…",
736
+ recordingDeniedText: "Screen recording permission was denied.",
737
+ videoPreviewLabel: "Video preview",
738
+ removeVideoButton: "Remove video",
739
+ }
740
+ ```
741
+
655
742
  ### Known limitations
656
743
 
657
744
  The default screenshot engine (`html-to-image`) has known issues with:
@@ -761,6 +848,10 @@ import type {
761
848
  TransportConfig,
762
849
  TriggerStyle,
763
850
  WidgetPosition,
851
+ RecordingConfig,
852
+ VideoAsset,
853
+ VideoIntent,
854
+ VideoMime,
764
855
  SecurityConfig,
765
856
  SecurityFinding,
766
857
  SecuritySnapshot,
@@ -0,0 +1,2 @@
1
+ function E(){return typeof window<"u"&&typeof document<"u"}function he(e){let t=globalThis.CSS;return typeof t?.escape=="function"?t.escape(e):e.replace(/[^a-zA-Z0-9_-]/g,n=>{let r=n.codePointAt(0);return r===void 0?"":`\\${r.toString(16)} `})}function te(e){return {x:e.x,y:e.y,width:e.width,height:e.height}}function $e(e){return {x:e.x+window.scrollX,y:e.y+window.scrollY,width:e.width,height:e.height}}function je(e){return e.replace(/\s+/g," ").trim()}function Ve(e,t=140){let n=e.textContent;if(!n)return;let r=je(n);if(r)return r.length<=t?r:`${r.slice(0,t-1)}\u2026`}function Xe(e){let t=1;for(let n=e.previousElementSibling;n;n=n.previousElementSibling)n.tagName===e.tagName&&(t+=1);return t}var Ee=["data-testid","data-test-id","data-test","data-qa","data-cy"],we="data-blocfeed-component";function Ze(e){let t=e.closest(`[${we}]`);if(!t)return;let r=t.getAttribute(we)?.trim();return r||void 0}function We(e){for(let t of Ee){let n=e.closest(`[${t}]`);if(!n)continue;let o=n.getAttribute(t)?.trim();if(o)return o}}function be(e){try{let t=e,n=Object.getOwnPropertyNames(t);for(let r of n)if(r.startsWith("__reactFiber$")||r.startsWith("__reactInternalInstance$")){let o=t[r];if(o&&typeof o=="object")return o}}catch{}return null}function B(e){if(e.length<=1||e.length===2&&e[0]===e[0].toLowerCase())return true;let t=e[0];return t>="a"&&t<="z"}function q(e){if(e){for(let t of e)if(typeof t.name=="string"&&t.name&&!B(t.name))return t.name}}function A(e){if(e&&typeof e!="string"){if(typeof e=="function"){let t=e;return typeof t.displayName=="string"&&t.displayName?t.displayName:typeof t.name=="string"&&t.name?t.name:void 0}if(typeof e=="object"){let t=e,n=t.displayName;if(typeof n=="string"&&n)return n;let r=t.render;if(typeof r=="function"){let i=r;if(typeof i.displayName=="string"&&i.displayName)return i.displayName;if(typeof i.name=="string"&&i.name)return i.name}let o=t.type;return A(o)}}}function Ke(e){let t=be(e);if(!t)return;let n=q(t._debugInfo);if(n)return n;let r=t._debugOwner!==void 0;if(r){let s=t._debugOwner;for(let c=0;s&&c<50;c+=1){let h=q(s._debugInfo);if(h)return h;let p=A(s.type)??A(s.elementType);if(p&&!B(p))return p;s=s._debugOwner;}}if(t._owner!==void 0&&t._owner!==t._debugOwner){let s=t._owner;for(let c=0;s&&c<50;c+=1){let h=q(s._debugInfo);if(h)return h;let p=A(s.type)??A(s.elementType);if(p&&!B(p))return p;s=s._owner;}}let i=t,l=r?80:25;for(let s=0;i&&s<l;s+=1){let c=q(i._debugInfo);if(c)return c;let h=A(i.type)??A(i.elementType);if(h&&!B(h))return h;i=i.return;}let a=e.parentElement;for(let s=0;a&&s<15;s+=1){let c=be(a);if(c){let h=q(c._debugInfo);if(h)return h;let p=A(c.type)??A(c.elementType);if(p&&!B(p))return p;if(c._debugOwner){let m=A(c._debugOwner.type)??A(c._debugOwner.elementType);if(m&&!B(m))return m}if(c._owner&&c._owner!==c._debugOwner){let m=A(c._owner.type)??A(c._owner.elementType);if(m&&!B(m))return m}}a=a.parentElement;}}function Qe(e){let t=e.tagName.toLowerCase(),n=e.getAttribute("id");if(n)return `#${he(n)}`;for(let r of Ee){let o=e.getAttribute(r);if(o)return `${t}[${r}="${he(o)}"]`}return `${t}:nth-of-type(${Xe(e)})`}function Ye(e,t=10){let n=[],r=e;for(;r&&n.length<t;){let o=Qe(r);if(n.unshift(o),o.startsWith("#"))break;r=r.parentElement;}return n.join(" > ")}function ye(e,t){if(!t||t.length===0)return false;for(let n of t)if(e.closest(n))return true;return false}function ne(e,t){if(!e||ye(e,t.ignoreSelectors))return null;let n=e;for(;n;){if(ye(n,t.ignoreSelectors))return null;if(t.isSelectable?.(n)??Ge(n))return n;n=n.parentElement;}return null}function Ge(e){let t=e.tagName;return !(t==="HTML"||t==="BODY")}function Se(e){let t=e.getBoundingClientRect(),n={selector:Ye(e),tagName:e.tagName.toLowerCase(),rect:te(t),pageRect:$e(t)},r=e.getAttribute("id");r&&(n.id=r);let o=e.className;typeof o=="string"&&o.trim()&&(n.className=o);let i=Ve(e);i&&(n.textSnippet=i);let l=Ze(e)??Ke(e);l&&(n.componentName=l);let a=We(e);return a&&(n.testId=a),n}var re=null;async function ke(){return re||(re=import('html-to-image')),re}async function Je(e){return await new Promise((t,n)=>{let r=new Image;r.onload=()=>t({width:r.naturalWidth,height:r.naturalHeight}),r.onerror=()=>n(new Error("Failed to load generated screenshot")),r.src=e;})}async function _e(e,t){let{width:n,height:r}=await Je(e);return {dataUrl:e,mime:t,width:n,height:r}}function O(e){if(e?.aborted)throw new Error("Aborted")}function ve(){return {async captureElement(e,t){if(!E())throw new Error("captureElement can only run in the browser");O(t.signal);let n=await ke();O(t.signal);let r=t.mime==="image/jpeg"?await n.toJpeg(e,{quality:t.quality??.92,pixelRatio:t.pixelRatio}):await n.toPng(e,{pixelRatio:t.pixelRatio});return O(t.signal),await _e(r,t.mime)},async captureFullPage(e){if(!E())throw new Error("captureFullPage can only run in the browser");O(e.signal);let t=document.documentElement,n=Math.max(t.scrollWidth,t.clientWidth),r=Math.max(t.scrollHeight,t.clientHeight),o=Math.min(1,e.maxDimension/Math.max(n,r)),i=Math.max(1,Math.round(n*o)),l=Math.max(1,Math.round(r*o)),a=await ke();O(e.signal);let s=e.mime==="image/jpeg"?await a.toJpeg(t,{width:i,height:l,quality:e.quality??.92,pixelRatio:e.pixelRatio}):await a.toPng(t,{width:i,height:l,pixelRatio:e.pixelRatio});return O(e.signal),await _e(s,e.mime)}}}function et(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return "Unknown error"}}function w(e,t,n){let r={kind:e,message:et(t)};return n&&(r.detail=n),r}var tt=12e3,nt=2048,rt=.92;function Re(){return Date.now()}function ot(e){return new Promise((t,n)=>{let r=()=>n(new Error("Aborted"));if(e.aborted){r();return}e.addEventListener("abort",r,{once:true});})}async function Ae(e,t,n){let r=new Promise((i,l)=>{let a=setTimeout(()=>l(new Error("Timeout")),t);typeof a.unref=="function"&&a.unref();}),o=[e,r];return n&&o.push(ot(n)),await Promise.race(o)}function it(e){if(!E())return 1;let t=window.devicePixelRatio||1,n=e?.pixelRatio??Math.min(t,2);return Math.max(.1,n)}function at(e){return !!(e?.element||e?.fullPage)}function Te(e){let t={mime:e.mime,pixelRatio:e.pixelRatio,maxDimension:e.maxDimension};return e.includeQuality&&(t.quality=e.quality),e.signal&&(t.signal=e.signal),t}async function Pe(e){let{selectionElement:t,capture:n,signal:r}=e;if(!E()||!at(n))return;let o=Re(),i=[],l=n?.timeoutMs??tt,a=n?.maxDimension??nt,s=n?.mime??"image/png",c=n?.quality??rt,h=n?.adapter??ve(),p={},m=it(n);if(n?.element&&t)try{let f=t.getBoundingClientRect(),g=Math.min(1,a/Math.max(f.width,f.height)),k=Math.min(m,m*g),v=await Ae(Promise.resolve(h.captureElement(t,{...Te({mime:s,quality:c,pixelRatio:k,maxDimension:a,includeQuality:s==="image/jpeg",...r?{signal:r}:{}})})),l,r);p.element=v;}catch(f){if(r?.aborted)throw f;i.push(w("capture_failed",f,{target:"element"}));}if(n?.fullPage)try{let f=await Ae(Promise.resolve(h.captureFullPage(Te({mime:s,quality:c,pixelRatio:m,maxDimension:a,includeQuality:s==="image/jpeg",...r?{signal:r}:{}}))),l,r);p.fullPage=f;}catch(f){if(r?.aborted)throw f;i.push(w("capture_failed",f,{target:"fullPage"}));}let b=Re(),u={startedAt:o,finishedAt:b,durationMs:Math.max(0,b-o)};return i.length>0&&(u.errors=i),{...p,diagnostics:u}}function st(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return}}function ct(){return E()?{url:window.location.href,title:document.title,referrer:document.referrer||void 0,userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},scroll:{x:window.scrollX,y:window.scrollY},devicePixelRatio:window.devicePixelRatio||1,timezone:st()}:{}}function lt(e){if(!e)return {};let t={};return e.id&&(t.userId=e.id),e.email&&(t.userEmail=e.email),e.name&&(t.userName=e.name),t}async function xe(e){let{config:t,context:n,user:r}=e;if(t?.enabled===false)return {};let o={...ct(),...lt(r)},i=t?.enrich;if(!i)return o;try{let l=await i(n);return {...o,...l}}catch(l){let a=w("unknown",l);return {...o,blocfeedMetadataError:a.message}}}var oe="blocfeed-queue",ut=50;function ie(){if(!E())return [];try{let e=localStorage.getItem(oe);if(!e)return [];let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return []}}function ae(e){if(E())try{e.length===0?localStorage.removeItem(oe):localStorage.setItem(oe,JSON.stringify(e));}catch{}}function dt(e){let t={...e};if(t.screenshots){let n={...t.screenshots};n.element&&(n.element={...n.element,dataUrl:""}),n.fullPage&&(n.fullPage={...n.fullPage,dataUrl:""}),t.screenshots=n;}return delete t.video,t}function se(e){let t=ie(),n=dt(e);for(n.metadata={...n.metadata,_queued:true},t.push({payload:n,timestamp:Date.now()});t.length>ut;)t.shift();ae(t);}function Fe(){let e=ie();return e.length===0?[]:(ae([]),e.map(t=>t.payload))}function Jt(){ae([]);}function en(){return ie().length}var ft=3e4,mt=25e5,Ce="video/webm",pt=250,gt=1e3,ht=["video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm"];function Me(){if(typeof MediaRecorder>"u")return null;for(let e of ht)if(MediaRecorder.isTypeSupported(e))return e;return null}function wt(){return !E()||typeof navigator?.mediaDevices?.getDisplayMedia!="function"?false:Me()!==null}async function ce(e){let{config:t,signal:n}=e;if(!E()||typeof navigator?.mediaDevices?.getDisplayMedia!="function")throw w("recording_failed",new Error("Screen recording is not supported in this browser"));let r=Me();if(!r)throw w("recording_failed",new Error("No supported video codec found (WebM required)"));if(n?.aborted)throw w("aborted",new Error("Recording aborted before start"));let o;try{o=await navigator.mediaDevices.getDisplayMedia({video:{displaySurface:"browser"},audio:!1});}catch(g){let k=g instanceof DOMException&&g.name==="NotAllowedError"?"Screen share permission denied":"Failed to start screen share";throw w("recording_failed",new Error(k))}if(n?.aborted)throw o.getTracks().forEach(g=>g.stop()),w("aborted",new Error("Recording aborted after permission"));let i=t?.maxDurationMs??ft,l=t?.videoBitsPerSecond??mt,a=new MediaRecorder(o,{mimeType:r,videoBitsPerSecond:l}),s=[],c=[],h=0,p=null,m=null,b=false,u=()=>{p!==null&&(clearInterval(p),p=null),m!==null&&(clearTimeout(m),m=null),o.getTracks().forEach(g=>g.stop());},f=new Promise((g,k)=>{a.ondataavailable=y=>{y.data.size>0&&s.push(y.data);},a.onstop=()=>{if(b)return;b=true,u();let y=Date.now()-h,P=new Blob(s,{type:Ce}),M=URL.createObjectURL(P);g({mime:Ce,blobUrl:M,blob:P,durationMs:y,sizeBytes:P.size});},a.onerror=()=>{b||(b=true,u(),k(w("recording_failed",new Error("MediaRecorder error"))));};let v=o.getVideoTracks()[0];if(v&&v.addEventListener("ended",()=>{a.state!=="inactive"&&a.stop();}),n){let y=()=>{b||(b=true,a.state!=="inactive"&&a.stop(),u(),k(w("aborted",new Error("Recording aborted"))));};n.addEventListener("abort",y,{once:true});}});return a.start(gt),h=Date.now(),p=setInterval(()=>{let g=Date.now()-h;for(let k of c)k(g);},pt),m=setTimeout(()=>{!b&&a.state!=="inactive"&&a.stop();},i),{result:f,stop(){!b&&a.state!=="inactive"&&a.stop();},onTick(g){c.push(g);},abort(){b||(b=true,a.state!=="inactive"&&a.stop(),u());}}}function le(e){let t=null,n=null,r=(...o)=>{n=o,t===null&&(t=requestAnimationFrame(()=>{if(t=null,!n)return;let i=n;n=null,e(...i);}));};return r.cancel=()=>{t!==null&&cancelAnimationFrame(t),t=null,n=null;},r}function K(e){return e instanceof Element?!!e.closest("[data-blocfeed-ui]"):false}function Q(e){e.stopPropagation(),e.stopImmediatePropagation?.();}function Le(e,t){if(!E())throw new Error("BlocFeed picker can only run in a browser environment.");let n=e.ignoreSelectors,r=e.isSelectable,o={};n&&n.length>0&&(o.ignoreSelectors=n),r&&(o.isSelectable=r);let i=null,l=null,a=(u,f=false)=>{if(!u){i=null,l=null,t.onHover(null);return}let g=te(u.getBoundingClientRect()),k=`${Math.round(g.x)}:${Math.round(g.y)}:${Math.round(g.width)}:${Math.round(g.height)}`;!f&&u===i&&k===l||(i=u,l=k,t.onHover({element:u,rect:g}));},s=le(u=>{if(K(u.target))return;let f=document.elementFromPoint(u.clientX,u.clientY),g=ne(f,o);a(g);}),c=le(()=>{i&&a(i,true);}),h=u=>{K(u.target)||(Q(u),u.pointerType==="mouse"&&u.preventDefault());},p=u=>{K(u.target)||(Q(u),u.pointerType==="mouse"&&u.preventDefault());},m=u=>{if(K(u.target))return;Q(u),u.preventDefault();let f=document.elementFromPoint(u.clientX,u.clientY),g=ne(f,o);g&&t.onSelect({element:g,descriptor:Se(g)});},b=u=>{u.key==="Escape"&&(Q(u),u.preventDefault(),t.onCancel());};return window.addEventListener("pointermove",s,{capture:true,passive:true}),window.addEventListener("pointerdown",h,{capture:true}),window.addEventListener("pointerup",p,{capture:true}),window.addEventListener("click",m,{capture:true}),window.addEventListener("keydown",b,{capture:true}),window.addEventListener("scroll",c,{capture:true,passive:true}),window.addEventListener("resize",c,{passive:true}),{stop(){window.removeEventListener("pointermove",s,{capture:true}),window.removeEventListener("pointerdown",h,{capture:true}),window.removeEventListener("pointerup",p,{capture:true}),window.removeEventListener("click",m,{capture:true}),window.removeEventListener("keydown",b,{capture:true}),window.removeEventListener("scroll",c,{capture:true}),window.removeEventListener("resize",c),s.cancel(),c.cancel(),t.onHover(null);}}}var bt=12e3,yt=2,Et=500,St=2e3,ue="https://blocfeed.com/api/feedback",De=0;function Be(e,t){return new Promise((n,r)=>{if(t?.aborted){r(new Error("Aborted"));return}let o=setTimeout(n,e),i=()=>{clearTimeout(o),r(new Error("Aborted"));};t?.addEventListener("abort",i,{once:true});})}function kt(e){return e>=500&&e<=599}function _t(e){let[t,n]=e.split(",",2);if(!t||!n)throw new Error("Invalid data URL");let o=/data:(.*?);base64/.exec(t)?.[1]||"application/octet-stream",i=atob(n),l=new Uint8Array(i.length);for(let a=0;a<i.length;a+=1)l[a]=i.charCodeAt(a);return new Blob([l],{type:o})}function vt(e){let t={},n={},r={...e};if(r.screenshots){let o={},i={...r.screenshots};i.element&&(t.element=i.element.dataUrl,o.element={mime:i.element.mime,width:i.element.width,height:i.element.height},i.element={...i.element,dataUrl:""}),i.fullPage&&(t.fullPage=i.fullPage.dataUrl,o.fullPage={mime:i.fullPage.mime,width:i.fullPage.width,height:i.fullPage.height},i.fullPage={...i.fullPage,dataUrl:""}),r.screenshots=i,(o.element||o.fullPage)&&(r.screenshot_intent=o);}return r.video&&(n.blob=r.video.blob,r.video_intent={mime:r.video.mime,durationMs:r.video.durationMs,sizeBytes:r.video.sizeBytes},delete r.video),{lean:r,extracted:t,extractedVideo:n}}async function Ie(e,t,n){let r=_t(t);await fetch(e,{method:"PUT",body:r,headers:{"content-type":r.type},...n?{signal:n}:{}});}async function Rt(e){let{feedbackId:t,extracted:n,screenshots:r,signal:o}=e,i={};n.element&&r?.element&&(i.element={dataUrl:n.element,mime:r.element.mime,width:r.element.width,height:r.element.height}),n.fullPage&&r?.fullPage&&(i.fullPage={dataUrl:n.fullPage,mime:r.fullPage.mime,width:r.fullPage.width,height:r.fullPage.height}),Object.keys(i).length!==0&&await fetch(`${ue}/${t}/screenshots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i),...o?{signal:o}:{}});}async function At(e){await fetch(`${ue}/${e.feedbackId}/video`,{method:"POST",body:e.blob,headers:{"content-type":e.blob.type},...e.signal?{signal:e.signal}:{}});}async function Ne(e){let{signal:t,transport:n}=e;if(Date.now()-De<St)return {ok:false,error:w("configuration",new Error("Please wait before submitting again"))};let o=n?.timeoutMs??bt,i=n?.maxAttempts??yt,l=n?.backoffMs??Et,a=!!(e.payload.screenshots?.element?.dataUrl||e.payload.screenshots?.fullPage?.dataUrl),s=!!e.payload.video?.blob,c=a||s,{lean:h,extracted:p,extractedVideo:m}=c?vt(e.payload):{lean:e.payload,extracted:{},extractedVideo:{}},b={...p,...e.screenshotDataUrls};for(let u=1;u<=i;u+=1){let f=new AbortController,g=setTimeout(()=>f.abort(),o),k=()=>f.abort();t&&t.addEventListener("abort",k,{once:true});try{let v=await fetch(ue,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(h),signal:f.signal});if(v.ok){De=Date.now();let y;try{y=await v.json();}catch{}if((b.element||b.fullPage)&&y){let d=y.upload_urls;if(d){let S=[];b.element&&d.element&&S.push(Ie(d.element,b.element,t)),b.fullPage&&d.fullPage&&S.push(Ie(d.fullPage,b.fullPage,t));try{await Promise.all(S);}catch{}}else if(y.feedback_id)try{await Rt({feedbackId:y.feedback_id,extracted:b,screenshots:e.payload.screenshots,...t?{signal:t}:{}});}catch{}}if(m.blob&&y){let d=y.upload_urls;if(d?.video)try{await fetch(d.video,{method:"PUT",body:m.blob,headers:{"content-type":m.blob.type},...t?{signal:t}:{}});}catch{}else if(y.feedback_id)try{await At({feedbackId:y.feedback_id,blob:m.blob,...t?{signal:t}:{}});}catch{}}let M={ok:!0,status:v.status};return y&&(M.apiResponse=y),M}if(u<i&&kt(v.status)){let y=.85+Math.random()*.3,P=Math.round(l*2**(u-1)*y);await Be(P,t);continue}return {ok:!1,status:v.status,error:w("api_failed",new Error(`HTTP ${v.status}`))}}catch(v){if(f.signal.aborted||t?.aborted)return {ok:false,error:w("aborted",v)};if(u<i){let y=.85+Math.random()*.3,P=Math.round(l*2**(u-1)*y);await Be(P,t);continue}return {ok:false,error:w("api_failed",v)}}finally{clearTimeout(g),t&&t.removeEventListener("abort",k);}}return {ok:false,error:w("api_failed",new Error("Failed"))}}async function de(e){let{signal:t,transport:n}=e,r={ok:false};try{let o={payload:e.payload,...t?{signal:t}:{},...n?{transport:n}:{}};r.api=await Ne(o),r.ok=!!r.api?.ok;}catch(o){r.api={ok:false,error:w("api_failed",o)},r.ok=false;}return {payload:e.payload,result:r}}var Tt=["[data-blocfeed-ui]","[data-blocfeed-ignore]"];function Pt(e){let t=[...Tt,...e?.ignoreSelectors??[]],n=Array.from(new Set(t));return {...e,ignoreSelectors:n}}function Oe(){return {phase:"idle"}}function xt(e){if(e.ok)return false;let t=e.api;return t?t.status&&t.status>=400&&t.status<500||t.error?.kind==="aborted"||t.error?.kind==="configuration"?false:!t.ok:true}function Rn(e){let t=e,n=Oe(),r=new Set,o=new Set,i=null,l=null,a=null,s=null,c=0,h=null,p=null,m=null,b=()=>{for(let d of r)d(n);},u=d=>{for(let S of o)S(d);},f=d=>{n=d,b();},g=()=>{c+=1,s?.abort(),s=null;},k=()=>{i?.stop(),i=null,u(null),a!==null&&E()&&(document.documentElement.style.cursor=a,a=null);},v=()=>{p&&(p.abort(),p=null),m&&(URL.revokeObjectURL(m.blobUrl),m=null);},y=()=>{g(),k(),v(),l=null,f(Oe());},P=()=>{if(!E())return;k(),l=null;let d=Pt(t.picker);a=document.documentElement.style.cursor,document.documentElement.style.cursor="crosshair",f({phase:"picking"}),i=Le(d,{onHover:u,onSelect:({element:S,descriptor:x})=>{l=S,k(),f({phase:"review",selection:x});},onCancel:()=>{y();}});},M=()=>{let d=Fe();if(d.length!==0)for(let S of d)de({payload:S,...t.transport?{transport:t.transport}:{}}).catch(()=>{se(S);});};if(E()){setTimeout(M,1e3);let d=()=>M();window.addEventListener("online",d),h=()=>window.removeEventListener("online",d);}return {getState:()=>n,subscribe(d){return r.add(d),()=>r.delete(d)},subscribeHover(d){return o.add(d),()=>o.delete(d)},start(){n.phase==="capturing"||n.phase==="submitting"||n.phase==="recording"||n.phase!=="picking"&&P();},stop(){y();},clearSelection(){n.phase==="capturing"||n.phase==="submitting"||n.phase==="recording"||P();},setConfig(d){t=d;},async submit(d,S){if(!E()){let R=w("configuration",new Error("BlocFeed submit can only run in the browser"));return f({phase:"error",lastError:R}),{ok:false}}let x=t.blocfeed_id?.trim?.()??"";if(!x){let L={phase:"error",lastError:w("configuration",new Error("Missing blocfeed_id. Create a project in BlocFeed and pass its blocfeed_id."))};return n.selection&&(L.selection=n.selection),f(L),{ok:false}}if(n.phase==="capturing"||n.phase==="submitting"||n.phase==="recording")return {ok:false};let F=c+1;c=F,s?.abort(),s=new AbortController;let T=s.signal,_=n.selection,U=S?.capture?{...t.capture,...S.capture}:t.capture,H=!!(U?.element||U?.fullPage),ge={phase:H?"capturing":"submitting"};_&&(ge.selection=_),f(ge);try{let R=H?await Pe({selectionElement:l,capture:U,signal:T}):void 0;if(T.aborted||c!==F)return {ok:!1};let L={phase:"submitting"};_&&(L.selection=_),R&&(L.capture=R),f(L);let N={};_&&(N.selection=_),R&&(N.capture=R);let qe=await xe({config:t.metadata,context:N,...t.user?{user:t.user}:{}}),D={version:1,createdAt:new Date().toISOString(),blocfeed_id:x,message:d,metadata:qe};S?.category&&(D.category=S.category),t.user&&(D.user=t.user),_&&(D.selection=_),R&&(D.screenshots=R),m&&(D.video=m);let{result:C}=await de({payload:D,signal:T,...t.transport?{transport:t.transport}:{}});if(T.aborted||c!==F)return C;if(C.ok){m&&(URL.revokeObjectURL(m.blobUrl),m=null);let ee={phase:"success",lastSubmit:C};return _&&(ee.selection=_),R&&(ee.capture=R),f(ee),C}xt(C)&&se(D);let ze=C.api?.error??w("unknown",new Error("Submission failed")),J={phase:"error",lastSubmit:C,lastError:ze};return _&&(J.selection=_),R&&(J.capture=R),f(J),C}catch(R){if(T.aborted||c!==F)return {ok:false};let N={phase:"error",lastError:T.aborted?w("aborted",R):w("unknown",R)};return _&&(N.selection=_),f(N),{ok:false}}finally{c===F&&(s=null);}},async startRecording(){if(n.phase!=="review"||!t.recording?.enabled)return;let d=n.selection,S={phase:"recording",recordingElapsedMs:0};d&&(S.selection=d),f(S);try{let x={config:t.recording};s&&(x.signal=s.signal);let F=await ce(x);p=F,F.onTick(U=>{if(n.phase==="recording"){let H={phase:"recording",recordingElapsedMs:U};d&&(H.selection=d),f(H);}});let T=await F.result;p=null,m=T;let _={phase:"review",video:T};d&&(_.selection=d),f(_);}catch(x){p=null;let T={phase:"review",lastError:x?.kind?x:w("recording_failed",x)};d&&(T.selection=d),f(T);}},stopRecording(){n.phase!=="recording"||!p||p.stop();},removeVideo(){m&&(URL.revokeObjectURL(m.blobUrl),m=null);let d=n.selection,S={phase:"review"};d&&(S.selection=d),f(S);},__unsafeGetSelectedElement(){return l},destroy(){y(),r.clear(),o.clear(),h?.(),h=null;}}}var z=[],$=[],Ue=20,He=15,Y=[],j={},V=null,X=null,Z=null,G=false,Ft=["blocfeed.com","google-analytics.com","googletagmanager.com","analytics.google.com","googleads.g.doubleclick.net","googlesyndication.com","googleadservices.com","google.com/pagead","google.com/ads","facebook.net","facebook.com/tr","connect.facebook.net","graph.facebook.com","api.mixpanel.com","api-js.mixpanel.com","api.amplitude.com","api2.amplitude.com","api.segment.io","cdn.segment.com","vars.hotjar.com","in.hotjar.com","script.hotjar.com","heapanalytics.com","fullstory.com/s/fs.js","rs.fullstory.com","app.posthog.com","us.posthog.com","eu.posthog.com","api-iam.intercom.io","widget.intercom.io","sentry.io/api","browser.sentry-cdn.com","browser-intake-datadoghq.com","clarity.ms","js.hs-analytics.net","api.hubapi.com","forms.hubspot.com","plausible.io/api","client.crisp.chat","js.driftt.com","r.logrocket.com","app.pendo.io","events.launchdarkly.com","app.launchdarkly.com","grammarly.com","gnar.grammarly.com","capi.grammarly.com","api.languagetool.org","api.languagetoolplus.com","fonts.googleapis.com","fonts.gstatic.com","cdn.cookielaw.org","consent.cookiebot.com","js.stripe.com","api.stripe.com/v1/tokens","google.com/recaptcha","hcaptcha.com","bam.nr-data.net","rec.smartlook.com","o2.mouseflow.com","api.luckyorange.com","static.zdassets.com","ekr.zdassets.com"];function Ct(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}function Mt(e,t){let n=t.map(Ct).join(" "),r=t.find(i=>i instanceof Error),o={level:e,message:n.slice(0,2e3),timestamp:Date.now()};for(r?.stack&&(o.stack=r.stack.slice(0,2e3)),z.push(o);z.length>Ue;)z.shift();}function fe(e){let t=e.url.toLowerCase();for(let n of Y)if(t.includes(n))return;for($.push(e);$.length>He;)$.shift();}function Pn(e={}){if(G||!E())return;G=true,Ue=e.consoleLimit??20,He=e.networkLimit??15;let t=e.ignoreUrls;if(t!==void 0?Y=t.map(n=>n.toLowerCase()):Y=[...Ft],e.console!==false){let n=e.consoleLevels??["error","warn"];for(let r of n)j[r]=console[r],console[r]=(...o)=>{Mt(r,o),j[r]?.apply(console,o);};}if(e.network!==false&&typeof window.fetch=="function"){V=window.fetch;let n=V;window.fetch=async function(o,i){let l=typeof o=="string"?o:o instanceof URL?o.toString():o.url,a=(i?.method??"GET").toUpperCase(),s=Date.now();try{let c=await n.call(window,o,i);return c.ok||fe({url:l.slice(0,500),method:a,status:c.status,statusText:c.statusText,timestamp:s,durationMs:Date.now()-s}),c}catch(c){throw fe({url:l.slice(0,500),method:a,status:0,statusText:c instanceof Error?c.message:"Network error",timestamp:s,durationMs:Date.now()-s}),c}};}if(e.network!==false&&typeof XMLHttpRequest<"u"){X=XMLHttpRequest.prototype.open,Z=XMLHttpRequest.prototype.send;let n=X,r=Z;XMLHttpRequest.prototype.open=function(o,i,...l){return this.__bf_method=o.toUpperCase(),this.__bf_url=String(i),n.apply(this,[o,i,...l])},XMLHttpRequest.prototype.send=function(...o){let i=this.__bf_method||"GET",l=this.__bf_url||"",a=Date.now();return this.addEventListener("loadend",function(){if(this.status>=400||this.status===0){let s={url:l.slice(0,500),method:i,status:this.status,timestamp:a,durationMs:Date.now()-a};this.statusText&&(s.statusText=this.statusText),fe(s);}}),r.apply(this,o)};}}function xn(){if(G){for(let[e,t]of Object.entries(j))console[e]=t;for(let e of Object.keys(j))delete j[e];V&&(window.fetch=V,V=null),X&&(XMLHttpRequest.prototype.open=X,X=null),Z&&(XMLHttpRequest.prototype.send=Z,Z=null),Y=[],G=false;}}function Fn(){return {consoleLogs:[...z],networkErrors:[...$]}}function Cn(){z=[],$=[];}var Lt=[{name:"supabase_service_role_key",pattern:/SUPABASE_SERVICE_ROLE_KEY["'=:\s]+[A-Za-z0-9_.=-]{30,}/},{name:"supabase_db_password",pattern:/SUPABASE_DB_PASSWORD["'=:\s]+[^\s"']{6,}/},{name:"postgres_password",pattern:/POSTGRES_PASSWORD["'=:\s]+[^\s"']{6,}/},{name:"database_url_with_creds",pattern:/(?:postgres|postgresql|mysql|mongodb|redis|amqp):\/\/[^:]+:[^@\s"']+@/},{name:"aws_access_key",pattern:/AKIA[0-9A-Z]{16}/},{name:"aws_secret_key",pattern:/AWS_SECRET_ACCESS_KEY["'=:\s]+[A-Za-z0-9/+=]{30,}/},{name:"aws_session_token",pattern:/AWS_SESSION_TOKEN["'=:\s]+[A-Za-z0-9/+=]{30,}/},{name:"stripe_secret_key",pattern:/sk_live_[a-zA-Z0-9]{10,}/},{name:"stripe_secret_key_test",pattern:/sk_test_[a-zA-Z0-9]{10,}/},{name:"stripe_restricted_key",pattern:/rk_(?:live|test)_[a-zA-Z0-9]{10,}/},{name:"github_pat",pattern:/ghp_[A-Za-z0-9_]{36,}/},{name:"github_oauth",pattern:/gho_[A-Za-z0-9_]{36,}/},{name:"github_user_token",pattern:/ghu_[A-Za-z0-9_]{36,}/},{name:"github_server_token",pattern:/ghs_[A-Za-z0-9_]{36,}/},{name:"github_fine_grained",pattern:/github_pat_[A-Za-z0-9_]{22,}/},{name:"openai_api_key",pattern:/sk-[a-zA-Z0-9]{20,}(?![a-zA-Z0-9_])/},{name:"anthropic_api_key",pattern:/sk-ant-[a-zA-Z0-9\-_]{20,}/},{name:"private_key",pattern:/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/},{name:"sendgrid_api_key",pattern:/SG\.[a-zA-Z0-9_-]{22,}\.[a-zA-Z0-9_-]{22,}/},{name:"twilio_auth_token",pattern:/TWILIO_AUTH_TOKEN["'=:\s]+[a-f0-9]{32}/},{name:"generic_secret_key",pattern:/[A-Z_]{2,}_SECRET_KEY["'=:\s]+[^\s"']{8,}/},{name:"generic_secret",pattern:/[A-Z_]{2,}_SECRET["'=:\s]+[^\s"']{8,}/},{name:"generic_password",pattern:/[A-Z_]{2,}_PASSWORD["'=:\s]+[^\s"']{6,}/},{name:"generic_private_key_var",pattern:/[A-Z_]{2,}_PRIVATE_KEY["'=:\s]+[^\s"']{8,}/}],I=[],pe=0,me=false;function Dt(e){let t=e.slice(0,80);return t.length<=6?"***":t.slice(0,6)+"***"}function Bt(e,t,n,r){if(I.some(l=>l.rule===e&&l.source===t))return;let i={rule:e,source:t,hint:Dt(n),timestamp:Date.now()};r&&(i.location=r),I.push(i);}function W(e,t,n,r){for(let{name:o,pattern:i}of n){let l=i.exec(e);l&&Bt(o,t,l[0],r);}}function It(e){try{let t=window;if(t.__NEXT_DATA__){let n=JSON.stringify(t.__NEXT_DATA__);W(n,"hydration",e,"__NEXT_DATA__");}if(t.__NUXT__){let n=JSON.stringify(t.__NUXT__);W(n,"hydration",e,"__NUXT__");}}catch{}}function Nt(e){try{document.querySelectorAll("script:not([src])").forEach((n,r)=>{let o=n.textContent;o&&o.length>0&&W(o,"scripts",e,`inline-script[${r}]`);});}catch{}}function Ot(e){try{document.querySelectorAll("meta[content]").forEach(n=>{let r=n.getAttribute("content"),o=n.getAttribute("name")||n.getAttribute("property")||"";r&&r.length>10&&W(r,"meta",e,o?`meta[${o}]`:void 0);});}catch{}}function Ut(e){try{document.querySelectorAll("[data-api-key], [data-secret], [data-token], [data-password]").forEach(n=>{let r=n.attributes;for(let o=0;o<r.length;o++){let i=r[o];i.name.startsWith("data-")&&i.value.length>10&&W(i.value,"dom",e,`${n.tagName.toLowerCase()}[${i.name}]`);}});}catch{}}function Dn(e={}){if(me||!E()||(me=true,e.secretScan===false))return;let t=[...Lt,...e.customPatterns??[]],n=e.scanTargets??["hydration","scripts","meta","dom"];setTimeout(()=>{pe=Date.now(),n.includes("hydration")&&It(t),n.includes("scripts")&&Nt(t),n.includes("meta")&&Ot(t),n.includes("dom")&&Ut(t);let r=e.notify??"both";I.length>0&&(r==="console"||r==="both")&&console.warn(`[BlocFeed Security] Found ${I.length} potential secret(s) exposed in client code:`,I.map(o=>`${o.rule} (${o.source}${o.location?`: ${o.location}`:""})`));},100);}function Bn(){return {findings:[...I],scannedAt:pe}}function In(){I=[],pe=0,me=false;}
2
+ export{E as a,te as b,ve as c,Pe as d,xe as e,se as f,Fe as g,Jt as h,en as i,wt as j,ce as k,Rn as l,Pn as m,xn as n,Fn as o,Cn as p,Dn as q,Bn as r,In as s};
@@ -0,0 +1,2 @@
1
+ 'use strict';function E(){return typeof window<"u"&&typeof document<"u"}function he(e){let t=globalThis.CSS;return typeof t?.escape=="function"?t.escape(e):e.replace(/[^a-zA-Z0-9_-]/g,n=>{let r=n.codePointAt(0);return r===void 0?"":`\\${r.toString(16)} `})}function te(e){return {x:e.x,y:e.y,width:e.width,height:e.height}}function $e(e){return {x:e.x+window.scrollX,y:e.y+window.scrollY,width:e.width,height:e.height}}function je(e){return e.replace(/\s+/g," ").trim()}function Ve(e,t=140){let n=e.textContent;if(!n)return;let r=je(n);if(r)return r.length<=t?r:`${r.slice(0,t-1)}\u2026`}function Xe(e){let t=1;for(let n=e.previousElementSibling;n;n=n.previousElementSibling)n.tagName===e.tagName&&(t+=1);return t}var Ee=["data-testid","data-test-id","data-test","data-qa","data-cy"],we="data-blocfeed-component";function Ze(e){let t=e.closest(`[${we}]`);if(!t)return;let r=t.getAttribute(we)?.trim();return r||void 0}function We(e){for(let t of Ee){let n=e.closest(`[${t}]`);if(!n)continue;let o=n.getAttribute(t)?.trim();if(o)return o}}function be(e){try{let t=e,n=Object.getOwnPropertyNames(t);for(let r of n)if(r.startsWith("__reactFiber$")||r.startsWith("__reactInternalInstance$")){let o=t[r];if(o&&typeof o=="object")return o}}catch{}return null}function B(e){if(e.length<=1||e.length===2&&e[0]===e[0].toLowerCase())return true;let t=e[0];return t>="a"&&t<="z"}function q(e){if(e){for(let t of e)if(typeof t.name=="string"&&t.name&&!B(t.name))return t.name}}function A(e){if(e&&typeof e!="string"){if(typeof e=="function"){let t=e;return typeof t.displayName=="string"&&t.displayName?t.displayName:typeof t.name=="string"&&t.name?t.name:void 0}if(typeof e=="object"){let t=e,n=t.displayName;if(typeof n=="string"&&n)return n;let r=t.render;if(typeof r=="function"){let i=r;if(typeof i.displayName=="string"&&i.displayName)return i.displayName;if(typeof i.name=="string"&&i.name)return i.name}let o=t.type;return A(o)}}}function Ke(e){let t=be(e);if(!t)return;let n=q(t._debugInfo);if(n)return n;let r=t._debugOwner!==void 0;if(r){let s=t._debugOwner;for(let c=0;s&&c<50;c+=1){let h=q(s._debugInfo);if(h)return h;let p=A(s.type)??A(s.elementType);if(p&&!B(p))return p;s=s._debugOwner;}}if(t._owner!==void 0&&t._owner!==t._debugOwner){let s=t._owner;for(let c=0;s&&c<50;c+=1){let h=q(s._debugInfo);if(h)return h;let p=A(s.type)??A(s.elementType);if(p&&!B(p))return p;s=s._owner;}}let i=t,l=r?80:25;for(let s=0;i&&s<l;s+=1){let c=q(i._debugInfo);if(c)return c;let h=A(i.type)??A(i.elementType);if(h&&!B(h))return h;i=i.return;}let a=e.parentElement;for(let s=0;a&&s<15;s+=1){let c=be(a);if(c){let h=q(c._debugInfo);if(h)return h;let p=A(c.type)??A(c.elementType);if(p&&!B(p))return p;if(c._debugOwner){let m=A(c._debugOwner.type)??A(c._debugOwner.elementType);if(m&&!B(m))return m}if(c._owner&&c._owner!==c._debugOwner){let m=A(c._owner.type)??A(c._owner.elementType);if(m&&!B(m))return m}}a=a.parentElement;}}function Qe(e){let t=e.tagName.toLowerCase(),n=e.getAttribute("id");if(n)return `#${he(n)}`;for(let r of Ee){let o=e.getAttribute(r);if(o)return `${t}[${r}="${he(o)}"]`}return `${t}:nth-of-type(${Xe(e)})`}function Ye(e,t=10){let n=[],r=e;for(;r&&n.length<t;){let o=Qe(r);if(n.unshift(o),o.startsWith("#"))break;r=r.parentElement;}return n.join(" > ")}function ye(e,t){if(!t||t.length===0)return false;for(let n of t)if(e.closest(n))return true;return false}function ne(e,t){if(!e||ye(e,t.ignoreSelectors))return null;let n=e;for(;n;){if(ye(n,t.ignoreSelectors))return null;if(t.isSelectable?.(n)??Ge(n))return n;n=n.parentElement;}return null}function Ge(e){let t=e.tagName;return !(t==="HTML"||t==="BODY")}function Se(e){let t=e.getBoundingClientRect(),n={selector:Ye(e),tagName:e.tagName.toLowerCase(),rect:te(t),pageRect:$e(t)},r=e.getAttribute("id");r&&(n.id=r);let o=e.className;typeof o=="string"&&o.trim()&&(n.className=o);let i=Ve(e);i&&(n.textSnippet=i);let l=Ze(e)??Ke(e);l&&(n.componentName=l);let a=We(e);return a&&(n.testId=a),n}var re=null;async function ke(){return re||(re=import('html-to-image')),re}async function Je(e){return await new Promise((t,n)=>{let r=new Image;r.onload=()=>t({width:r.naturalWidth,height:r.naturalHeight}),r.onerror=()=>n(new Error("Failed to load generated screenshot")),r.src=e;})}async function _e(e,t){let{width:n,height:r}=await Je(e);return {dataUrl:e,mime:t,width:n,height:r}}function O(e){if(e?.aborted)throw new Error("Aborted")}function ve(){return {async captureElement(e,t){if(!E())throw new Error("captureElement can only run in the browser");O(t.signal);let n=await ke();O(t.signal);let r=t.mime==="image/jpeg"?await n.toJpeg(e,{quality:t.quality??.92,pixelRatio:t.pixelRatio}):await n.toPng(e,{pixelRatio:t.pixelRatio});return O(t.signal),await _e(r,t.mime)},async captureFullPage(e){if(!E())throw new Error("captureFullPage can only run in the browser");O(e.signal);let t=document.documentElement,n=Math.max(t.scrollWidth,t.clientWidth),r=Math.max(t.scrollHeight,t.clientHeight),o=Math.min(1,e.maxDimension/Math.max(n,r)),i=Math.max(1,Math.round(n*o)),l=Math.max(1,Math.round(r*o)),a=await ke();O(e.signal);let s=e.mime==="image/jpeg"?await a.toJpeg(t,{width:i,height:l,quality:e.quality??.92,pixelRatio:e.pixelRatio}):await a.toPng(t,{width:i,height:l,pixelRatio:e.pixelRatio});return O(e.signal),await _e(s,e.mime)}}}function et(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return "Unknown error"}}function w(e,t,n){let r={kind:e,message:et(t)};return n&&(r.detail=n),r}var tt=12e3,nt=2048,rt=.92;function Re(){return Date.now()}function ot(e){return new Promise((t,n)=>{let r=()=>n(new Error("Aborted"));if(e.aborted){r();return}e.addEventListener("abort",r,{once:true});})}async function Ae(e,t,n){let r=new Promise((i,l)=>{let a=setTimeout(()=>l(new Error("Timeout")),t);typeof a.unref=="function"&&a.unref();}),o=[e,r];return n&&o.push(ot(n)),await Promise.race(o)}function it(e){if(!E())return 1;let t=window.devicePixelRatio||1,n=e?.pixelRatio??Math.min(t,2);return Math.max(.1,n)}function at(e){return !!(e?.element||e?.fullPage)}function Te(e){let t={mime:e.mime,pixelRatio:e.pixelRatio,maxDimension:e.maxDimension};return e.includeQuality&&(t.quality=e.quality),e.signal&&(t.signal=e.signal),t}async function Pe(e){let{selectionElement:t,capture:n,signal:r}=e;if(!E()||!at(n))return;let o=Re(),i=[],l=n?.timeoutMs??tt,a=n?.maxDimension??nt,s=n?.mime??"image/png",c=n?.quality??rt,h=n?.adapter??ve(),p={},m=it(n);if(n?.element&&t)try{let f=t.getBoundingClientRect(),g=Math.min(1,a/Math.max(f.width,f.height)),k=Math.min(m,m*g),v=await Ae(Promise.resolve(h.captureElement(t,{...Te({mime:s,quality:c,pixelRatio:k,maxDimension:a,includeQuality:s==="image/jpeg",...r?{signal:r}:{}})})),l,r);p.element=v;}catch(f){if(r?.aborted)throw f;i.push(w("capture_failed",f,{target:"element"}));}if(n?.fullPage)try{let f=await Ae(Promise.resolve(h.captureFullPage(Te({mime:s,quality:c,pixelRatio:m,maxDimension:a,includeQuality:s==="image/jpeg",...r?{signal:r}:{}}))),l,r);p.fullPage=f;}catch(f){if(r?.aborted)throw f;i.push(w("capture_failed",f,{target:"fullPage"}));}let b=Re(),u={startedAt:o,finishedAt:b,durationMs:Math.max(0,b-o)};return i.length>0&&(u.errors=i),{...p,diagnostics:u}}function st(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return}}function ct(){return E()?{url:window.location.href,title:document.title,referrer:document.referrer||void 0,userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,viewport:{width:window.innerWidth,height:window.innerHeight},screen:{width:window.screen.width,height:window.screen.height},scroll:{x:window.scrollX,y:window.scrollY},devicePixelRatio:window.devicePixelRatio||1,timezone:st()}:{}}function lt(e){if(!e)return {};let t={};return e.id&&(t.userId=e.id),e.email&&(t.userEmail=e.email),e.name&&(t.userName=e.name),t}async function xe(e){let{config:t,context:n,user:r}=e;if(t?.enabled===false)return {};let o={...ct(),...lt(r)},i=t?.enrich;if(!i)return o;try{let l=await i(n);return {...o,...l}}catch(l){let a=w("unknown",l);return {...o,blocfeedMetadataError:a.message}}}var oe="blocfeed-queue",ut=50;function ie(){if(!E())return [];try{let e=localStorage.getItem(oe);if(!e)return [];let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return []}}function ae(e){if(E())try{e.length===0?localStorage.removeItem(oe):localStorage.setItem(oe,JSON.stringify(e));}catch{}}function dt(e){let t={...e};if(t.screenshots){let n={...t.screenshots};n.element&&(n.element={...n.element,dataUrl:""}),n.fullPage&&(n.fullPage={...n.fullPage,dataUrl:""}),t.screenshots=n;}return delete t.video,t}function se(e){let t=ie(),n=dt(e);for(n.metadata={...n.metadata,_queued:true},t.push({payload:n,timestamp:Date.now()});t.length>ut;)t.shift();ae(t);}function Fe(){let e=ie();return e.length===0?[]:(ae([]),e.map(t=>t.payload))}function Jt(){ae([]);}function en(){return ie().length}var ft=3e4,mt=25e5,Ce="video/webm",pt=250,gt=1e3,ht=["video/webm;codecs=vp9","video/webm;codecs=vp8","video/webm"];function Me(){if(typeof MediaRecorder>"u")return null;for(let e of ht)if(MediaRecorder.isTypeSupported(e))return e;return null}function wt(){return !E()||typeof navigator?.mediaDevices?.getDisplayMedia!="function"?false:Me()!==null}async function ce(e){let{config:t,signal:n}=e;if(!E()||typeof navigator?.mediaDevices?.getDisplayMedia!="function")throw w("recording_failed",new Error("Screen recording is not supported in this browser"));let r=Me();if(!r)throw w("recording_failed",new Error("No supported video codec found (WebM required)"));if(n?.aborted)throw w("aborted",new Error("Recording aborted before start"));let o;try{o=await navigator.mediaDevices.getDisplayMedia({video:{displaySurface:"browser"},audio:!1});}catch(g){let k=g instanceof DOMException&&g.name==="NotAllowedError"?"Screen share permission denied":"Failed to start screen share";throw w("recording_failed",new Error(k))}if(n?.aborted)throw o.getTracks().forEach(g=>g.stop()),w("aborted",new Error("Recording aborted after permission"));let i=t?.maxDurationMs??ft,l=t?.videoBitsPerSecond??mt,a=new MediaRecorder(o,{mimeType:r,videoBitsPerSecond:l}),s=[],c=[],h=0,p=null,m=null,b=false,u=()=>{p!==null&&(clearInterval(p),p=null),m!==null&&(clearTimeout(m),m=null),o.getTracks().forEach(g=>g.stop());},f=new Promise((g,k)=>{a.ondataavailable=y=>{y.data.size>0&&s.push(y.data);},a.onstop=()=>{if(b)return;b=true,u();let y=Date.now()-h,P=new Blob(s,{type:Ce}),M=URL.createObjectURL(P);g({mime:Ce,blobUrl:M,blob:P,durationMs:y,sizeBytes:P.size});},a.onerror=()=>{b||(b=true,u(),k(w("recording_failed",new Error("MediaRecorder error"))));};let v=o.getVideoTracks()[0];if(v&&v.addEventListener("ended",()=>{a.state!=="inactive"&&a.stop();}),n){let y=()=>{b||(b=true,a.state!=="inactive"&&a.stop(),u(),k(w("aborted",new Error("Recording aborted"))));};n.addEventListener("abort",y,{once:true});}});return a.start(gt),h=Date.now(),p=setInterval(()=>{let g=Date.now()-h;for(let k of c)k(g);},pt),m=setTimeout(()=>{!b&&a.state!=="inactive"&&a.stop();},i),{result:f,stop(){!b&&a.state!=="inactive"&&a.stop();},onTick(g){c.push(g);},abort(){b||(b=true,a.state!=="inactive"&&a.stop(),u());}}}function le(e){let t=null,n=null,r=(...o)=>{n=o,t===null&&(t=requestAnimationFrame(()=>{if(t=null,!n)return;let i=n;n=null,e(...i);}));};return r.cancel=()=>{t!==null&&cancelAnimationFrame(t),t=null,n=null;},r}function K(e){return e instanceof Element?!!e.closest("[data-blocfeed-ui]"):false}function Q(e){e.stopPropagation(),e.stopImmediatePropagation?.();}function Le(e,t){if(!E())throw new Error("BlocFeed picker can only run in a browser environment.");let n=e.ignoreSelectors,r=e.isSelectable,o={};n&&n.length>0&&(o.ignoreSelectors=n),r&&(o.isSelectable=r);let i=null,l=null,a=(u,f=false)=>{if(!u){i=null,l=null,t.onHover(null);return}let g=te(u.getBoundingClientRect()),k=`${Math.round(g.x)}:${Math.round(g.y)}:${Math.round(g.width)}:${Math.round(g.height)}`;!f&&u===i&&k===l||(i=u,l=k,t.onHover({element:u,rect:g}));},s=le(u=>{if(K(u.target))return;let f=document.elementFromPoint(u.clientX,u.clientY),g=ne(f,o);a(g);}),c=le(()=>{i&&a(i,true);}),h=u=>{K(u.target)||(Q(u),u.pointerType==="mouse"&&u.preventDefault());},p=u=>{K(u.target)||(Q(u),u.pointerType==="mouse"&&u.preventDefault());},m=u=>{if(K(u.target))return;Q(u),u.preventDefault();let f=document.elementFromPoint(u.clientX,u.clientY),g=ne(f,o);g&&t.onSelect({element:g,descriptor:Se(g)});},b=u=>{u.key==="Escape"&&(Q(u),u.preventDefault(),t.onCancel());};return window.addEventListener("pointermove",s,{capture:true,passive:true}),window.addEventListener("pointerdown",h,{capture:true}),window.addEventListener("pointerup",p,{capture:true}),window.addEventListener("click",m,{capture:true}),window.addEventListener("keydown",b,{capture:true}),window.addEventListener("scroll",c,{capture:true,passive:true}),window.addEventListener("resize",c,{passive:true}),{stop(){window.removeEventListener("pointermove",s,{capture:true}),window.removeEventListener("pointerdown",h,{capture:true}),window.removeEventListener("pointerup",p,{capture:true}),window.removeEventListener("click",m,{capture:true}),window.removeEventListener("keydown",b,{capture:true}),window.removeEventListener("scroll",c,{capture:true}),window.removeEventListener("resize",c),s.cancel(),c.cancel(),t.onHover(null);}}}var bt=12e3,yt=2,Et=500,St=2e3,ue="https://blocfeed.com/api/feedback",De=0;function Be(e,t){return new Promise((n,r)=>{if(t?.aborted){r(new Error("Aborted"));return}let o=setTimeout(n,e),i=()=>{clearTimeout(o),r(new Error("Aborted"));};t?.addEventListener("abort",i,{once:true});})}function kt(e){return e>=500&&e<=599}function _t(e){let[t,n]=e.split(",",2);if(!t||!n)throw new Error("Invalid data URL");let o=/data:(.*?);base64/.exec(t)?.[1]||"application/octet-stream",i=atob(n),l=new Uint8Array(i.length);for(let a=0;a<i.length;a+=1)l[a]=i.charCodeAt(a);return new Blob([l],{type:o})}function vt(e){let t={},n={},r={...e};if(r.screenshots){let o={},i={...r.screenshots};i.element&&(t.element=i.element.dataUrl,o.element={mime:i.element.mime,width:i.element.width,height:i.element.height},i.element={...i.element,dataUrl:""}),i.fullPage&&(t.fullPage=i.fullPage.dataUrl,o.fullPage={mime:i.fullPage.mime,width:i.fullPage.width,height:i.fullPage.height},i.fullPage={...i.fullPage,dataUrl:""}),r.screenshots=i,(o.element||o.fullPage)&&(r.screenshot_intent=o);}return r.video&&(n.blob=r.video.blob,r.video_intent={mime:r.video.mime,durationMs:r.video.durationMs,sizeBytes:r.video.sizeBytes},delete r.video),{lean:r,extracted:t,extractedVideo:n}}async function Ie(e,t,n){let r=_t(t);await fetch(e,{method:"PUT",body:r,headers:{"content-type":r.type},...n?{signal:n}:{}});}async function Rt(e){let{feedbackId:t,extracted:n,screenshots:r,signal:o}=e,i={};n.element&&r?.element&&(i.element={dataUrl:n.element,mime:r.element.mime,width:r.element.width,height:r.element.height}),n.fullPage&&r?.fullPage&&(i.fullPage={dataUrl:n.fullPage,mime:r.fullPage.mime,width:r.fullPage.width,height:r.fullPage.height}),Object.keys(i).length!==0&&await fetch(`${ue}/${t}/screenshots`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i),...o?{signal:o}:{}});}async function At(e){await fetch(`${ue}/${e.feedbackId}/video`,{method:"POST",body:e.blob,headers:{"content-type":e.blob.type},...e.signal?{signal:e.signal}:{}});}async function Ne(e){let{signal:t,transport:n}=e;if(Date.now()-De<St)return {ok:false,error:w("configuration",new Error("Please wait before submitting again"))};let o=n?.timeoutMs??bt,i=n?.maxAttempts??yt,l=n?.backoffMs??Et,a=!!(e.payload.screenshots?.element?.dataUrl||e.payload.screenshots?.fullPage?.dataUrl),s=!!e.payload.video?.blob,c=a||s,{lean:h,extracted:p,extractedVideo:m}=c?vt(e.payload):{lean:e.payload,extracted:{},extractedVideo:{}},b={...p,...e.screenshotDataUrls};for(let u=1;u<=i;u+=1){let f=new AbortController,g=setTimeout(()=>f.abort(),o),k=()=>f.abort();t&&t.addEventListener("abort",k,{once:true});try{let v=await fetch(ue,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(h),signal:f.signal});if(v.ok){De=Date.now();let y;try{y=await v.json();}catch{}if((b.element||b.fullPage)&&y){let d=y.upload_urls;if(d){let S=[];b.element&&d.element&&S.push(Ie(d.element,b.element,t)),b.fullPage&&d.fullPage&&S.push(Ie(d.fullPage,b.fullPage,t));try{await Promise.all(S);}catch{}}else if(y.feedback_id)try{await Rt({feedbackId:y.feedback_id,extracted:b,screenshots:e.payload.screenshots,...t?{signal:t}:{}});}catch{}}if(m.blob&&y){let d=y.upload_urls;if(d?.video)try{await fetch(d.video,{method:"PUT",body:m.blob,headers:{"content-type":m.blob.type},...t?{signal:t}:{}});}catch{}else if(y.feedback_id)try{await At({feedbackId:y.feedback_id,blob:m.blob,...t?{signal:t}:{}});}catch{}}let M={ok:!0,status:v.status};return y&&(M.apiResponse=y),M}if(u<i&&kt(v.status)){let y=.85+Math.random()*.3,P=Math.round(l*2**(u-1)*y);await Be(P,t);continue}return {ok:!1,status:v.status,error:w("api_failed",new Error(`HTTP ${v.status}`))}}catch(v){if(f.signal.aborted||t?.aborted)return {ok:false,error:w("aborted",v)};if(u<i){let y=.85+Math.random()*.3,P=Math.round(l*2**(u-1)*y);await Be(P,t);continue}return {ok:false,error:w("api_failed",v)}}finally{clearTimeout(g),t&&t.removeEventListener("abort",k);}}return {ok:false,error:w("api_failed",new Error("Failed"))}}async function de(e){let{signal:t,transport:n}=e,r={ok:false};try{let o={payload:e.payload,...t?{signal:t}:{},...n?{transport:n}:{}};r.api=await Ne(o),r.ok=!!r.api?.ok;}catch(o){r.api={ok:false,error:w("api_failed",o)},r.ok=false;}return {payload:e.payload,result:r}}var Tt=["[data-blocfeed-ui]","[data-blocfeed-ignore]"];function Pt(e){let t=[...Tt,...e?.ignoreSelectors??[]],n=Array.from(new Set(t));return {...e,ignoreSelectors:n}}function Oe(){return {phase:"idle"}}function xt(e){if(e.ok)return false;let t=e.api;return t?t.status&&t.status>=400&&t.status<500||t.error?.kind==="aborted"||t.error?.kind==="configuration"?false:!t.ok:true}function Rn(e){let t=e,n=Oe(),r=new Set,o=new Set,i=null,l=null,a=null,s=null,c=0,h=null,p=null,m=null,b=()=>{for(let d of r)d(n);},u=d=>{for(let S of o)S(d);},f=d=>{n=d,b();},g=()=>{c+=1,s?.abort(),s=null;},k=()=>{i?.stop(),i=null,u(null),a!==null&&E()&&(document.documentElement.style.cursor=a,a=null);},v=()=>{p&&(p.abort(),p=null),m&&(URL.revokeObjectURL(m.blobUrl),m=null);},y=()=>{g(),k(),v(),l=null,f(Oe());},P=()=>{if(!E())return;k(),l=null;let d=Pt(t.picker);a=document.documentElement.style.cursor,document.documentElement.style.cursor="crosshair",f({phase:"picking"}),i=Le(d,{onHover:u,onSelect:({element:S,descriptor:x})=>{l=S,k(),f({phase:"review",selection:x});},onCancel:()=>{y();}});},M=()=>{let d=Fe();if(d.length!==0)for(let S of d)de({payload:S,...t.transport?{transport:t.transport}:{}}).catch(()=>{se(S);});};if(E()){setTimeout(M,1e3);let d=()=>M();window.addEventListener("online",d),h=()=>window.removeEventListener("online",d);}return {getState:()=>n,subscribe(d){return r.add(d),()=>r.delete(d)},subscribeHover(d){return o.add(d),()=>o.delete(d)},start(){n.phase==="capturing"||n.phase==="submitting"||n.phase==="recording"||n.phase!=="picking"&&P();},stop(){y();},clearSelection(){n.phase==="capturing"||n.phase==="submitting"||n.phase==="recording"||P();},setConfig(d){t=d;},async submit(d,S){if(!E()){let R=w("configuration",new Error("BlocFeed submit can only run in the browser"));return f({phase:"error",lastError:R}),{ok:false}}let x=t.blocfeed_id?.trim?.()??"";if(!x){let L={phase:"error",lastError:w("configuration",new Error("Missing blocfeed_id. Create a project in BlocFeed and pass its blocfeed_id."))};return n.selection&&(L.selection=n.selection),f(L),{ok:false}}if(n.phase==="capturing"||n.phase==="submitting"||n.phase==="recording")return {ok:false};let F=c+1;c=F,s?.abort(),s=new AbortController;let T=s.signal,_=n.selection,U=S?.capture?{...t.capture,...S.capture}:t.capture,H=!!(U?.element||U?.fullPage),ge={phase:H?"capturing":"submitting"};_&&(ge.selection=_),f(ge);try{let R=H?await Pe({selectionElement:l,capture:U,signal:T}):void 0;if(T.aborted||c!==F)return {ok:!1};let L={phase:"submitting"};_&&(L.selection=_),R&&(L.capture=R),f(L);let N={};_&&(N.selection=_),R&&(N.capture=R);let qe=await xe({config:t.metadata,context:N,...t.user?{user:t.user}:{}}),D={version:1,createdAt:new Date().toISOString(),blocfeed_id:x,message:d,metadata:qe};S?.category&&(D.category=S.category),t.user&&(D.user=t.user),_&&(D.selection=_),R&&(D.screenshots=R),m&&(D.video=m);let{result:C}=await de({payload:D,signal:T,...t.transport?{transport:t.transport}:{}});if(T.aborted||c!==F)return C;if(C.ok){m&&(URL.revokeObjectURL(m.blobUrl),m=null);let ee={phase:"success",lastSubmit:C};return _&&(ee.selection=_),R&&(ee.capture=R),f(ee),C}xt(C)&&se(D);let ze=C.api?.error??w("unknown",new Error("Submission failed")),J={phase:"error",lastSubmit:C,lastError:ze};return _&&(J.selection=_),R&&(J.capture=R),f(J),C}catch(R){if(T.aborted||c!==F)return {ok:false};let N={phase:"error",lastError:T.aborted?w("aborted",R):w("unknown",R)};return _&&(N.selection=_),f(N),{ok:false}}finally{c===F&&(s=null);}},async startRecording(){if(n.phase!=="review"||!t.recording?.enabled)return;let d=n.selection,S={phase:"recording",recordingElapsedMs:0};d&&(S.selection=d),f(S);try{let x={config:t.recording};s&&(x.signal=s.signal);let F=await ce(x);p=F,F.onTick(U=>{if(n.phase==="recording"){let H={phase:"recording",recordingElapsedMs:U};d&&(H.selection=d),f(H);}});let T=await F.result;p=null,m=T;let _={phase:"review",video:T};d&&(_.selection=d),f(_);}catch(x){p=null;let T={phase:"review",lastError:x?.kind?x:w("recording_failed",x)};d&&(T.selection=d),f(T);}},stopRecording(){n.phase!=="recording"||!p||p.stop();},removeVideo(){m&&(URL.revokeObjectURL(m.blobUrl),m=null);let d=n.selection,S={phase:"review"};d&&(S.selection=d),f(S);},__unsafeGetSelectedElement(){return l},destroy(){y(),r.clear(),o.clear(),h?.(),h=null;}}}var z=[],$=[],Ue=20,He=15,Y=[],j={},V=null,X=null,Z=null,G=false,Ft=["blocfeed.com","google-analytics.com","googletagmanager.com","analytics.google.com","googleads.g.doubleclick.net","googlesyndication.com","googleadservices.com","google.com/pagead","google.com/ads","facebook.net","facebook.com/tr","connect.facebook.net","graph.facebook.com","api.mixpanel.com","api-js.mixpanel.com","api.amplitude.com","api2.amplitude.com","api.segment.io","cdn.segment.com","vars.hotjar.com","in.hotjar.com","script.hotjar.com","heapanalytics.com","fullstory.com/s/fs.js","rs.fullstory.com","app.posthog.com","us.posthog.com","eu.posthog.com","api-iam.intercom.io","widget.intercom.io","sentry.io/api","browser.sentry-cdn.com","browser-intake-datadoghq.com","clarity.ms","js.hs-analytics.net","api.hubapi.com","forms.hubspot.com","plausible.io/api","client.crisp.chat","js.driftt.com","r.logrocket.com","app.pendo.io","events.launchdarkly.com","app.launchdarkly.com","grammarly.com","gnar.grammarly.com","capi.grammarly.com","api.languagetool.org","api.languagetoolplus.com","fonts.googleapis.com","fonts.gstatic.com","cdn.cookielaw.org","consent.cookiebot.com","js.stripe.com","api.stripe.com/v1/tokens","google.com/recaptcha","hcaptcha.com","bam.nr-data.net","rec.smartlook.com","o2.mouseflow.com","api.luckyorange.com","static.zdassets.com","ekr.zdassets.com"];function Ct(e){if(e instanceof Error)return e.message;if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}function Mt(e,t){let n=t.map(Ct).join(" "),r=t.find(i=>i instanceof Error),o={level:e,message:n.slice(0,2e3),timestamp:Date.now()};for(r?.stack&&(o.stack=r.stack.slice(0,2e3)),z.push(o);z.length>Ue;)z.shift();}function fe(e){let t=e.url.toLowerCase();for(let n of Y)if(t.includes(n))return;for($.push(e);$.length>He;)$.shift();}function Pn(e={}){if(G||!E())return;G=true,Ue=e.consoleLimit??20,He=e.networkLimit??15;let t=e.ignoreUrls;if(t!==void 0?Y=t.map(n=>n.toLowerCase()):Y=[...Ft],e.console!==false){let n=e.consoleLevels??["error","warn"];for(let r of n)j[r]=console[r],console[r]=(...o)=>{Mt(r,o),j[r]?.apply(console,o);};}if(e.network!==false&&typeof window.fetch=="function"){V=window.fetch;let n=V;window.fetch=async function(o,i){let l=typeof o=="string"?o:o instanceof URL?o.toString():o.url,a=(i?.method??"GET").toUpperCase(),s=Date.now();try{let c=await n.call(window,o,i);return c.ok||fe({url:l.slice(0,500),method:a,status:c.status,statusText:c.statusText,timestamp:s,durationMs:Date.now()-s}),c}catch(c){throw fe({url:l.slice(0,500),method:a,status:0,statusText:c instanceof Error?c.message:"Network error",timestamp:s,durationMs:Date.now()-s}),c}};}if(e.network!==false&&typeof XMLHttpRequest<"u"){X=XMLHttpRequest.prototype.open,Z=XMLHttpRequest.prototype.send;let n=X,r=Z;XMLHttpRequest.prototype.open=function(o,i,...l){return this.__bf_method=o.toUpperCase(),this.__bf_url=String(i),n.apply(this,[o,i,...l])},XMLHttpRequest.prototype.send=function(...o){let i=this.__bf_method||"GET",l=this.__bf_url||"",a=Date.now();return this.addEventListener("loadend",function(){if(this.status>=400||this.status===0){let s={url:l.slice(0,500),method:i,status:this.status,timestamp:a,durationMs:Date.now()-a};this.statusText&&(s.statusText=this.statusText),fe(s);}}),r.apply(this,o)};}}function xn(){if(G){for(let[e,t]of Object.entries(j))console[e]=t;for(let e of Object.keys(j))delete j[e];V&&(window.fetch=V,V=null),X&&(XMLHttpRequest.prototype.open=X,X=null),Z&&(XMLHttpRequest.prototype.send=Z,Z=null),Y=[],G=false;}}function Fn(){return {consoleLogs:[...z],networkErrors:[...$]}}function Cn(){z=[],$=[];}var Lt=[{name:"supabase_service_role_key",pattern:/SUPABASE_SERVICE_ROLE_KEY["'=:\s]+[A-Za-z0-9_.=-]{30,}/},{name:"supabase_db_password",pattern:/SUPABASE_DB_PASSWORD["'=:\s]+[^\s"']{6,}/},{name:"postgres_password",pattern:/POSTGRES_PASSWORD["'=:\s]+[^\s"']{6,}/},{name:"database_url_with_creds",pattern:/(?:postgres|postgresql|mysql|mongodb|redis|amqp):\/\/[^:]+:[^@\s"']+@/},{name:"aws_access_key",pattern:/AKIA[0-9A-Z]{16}/},{name:"aws_secret_key",pattern:/AWS_SECRET_ACCESS_KEY["'=:\s]+[A-Za-z0-9/+=]{30,}/},{name:"aws_session_token",pattern:/AWS_SESSION_TOKEN["'=:\s]+[A-Za-z0-9/+=]{30,}/},{name:"stripe_secret_key",pattern:/sk_live_[a-zA-Z0-9]{10,}/},{name:"stripe_secret_key_test",pattern:/sk_test_[a-zA-Z0-9]{10,}/},{name:"stripe_restricted_key",pattern:/rk_(?:live|test)_[a-zA-Z0-9]{10,}/},{name:"github_pat",pattern:/ghp_[A-Za-z0-9_]{36,}/},{name:"github_oauth",pattern:/gho_[A-Za-z0-9_]{36,}/},{name:"github_user_token",pattern:/ghu_[A-Za-z0-9_]{36,}/},{name:"github_server_token",pattern:/ghs_[A-Za-z0-9_]{36,}/},{name:"github_fine_grained",pattern:/github_pat_[A-Za-z0-9_]{22,}/},{name:"openai_api_key",pattern:/sk-[a-zA-Z0-9]{20,}(?![a-zA-Z0-9_])/},{name:"anthropic_api_key",pattern:/sk-ant-[a-zA-Z0-9\-_]{20,}/},{name:"private_key",pattern:/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/},{name:"sendgrid_api_key",pattern:/SG\.[a-zA-Z0-9_-]{22,}\.[a-zA-Z0-9_-]{22,}/},{name:"twilio_auth_token",pattern:/TWILIO_AUTH_TOKEN["'=:\s]+[a-f0-9]{32}/},{name:"generic_secret_key",pattern:/[A-Z_]{2,}_SECRET_KEY["'=:\s]+[^\s"']{8,}/},{name:"generic_secret",pattern:/[A-Z_]{2,}_SECRET["'=:\s]+[^\s"']{8,}/},{name:"generic_password",pattern:/[A-Z_]{2,}_PASSWORD["'=:\s]+[^\s"']{6,}/},{name:"generic_private_key_var",pattern:/[A-Z_]{2,}_PRIVATE_KEY["'=:\s]+[^\s"']{8,}/}],I=[],pe=0,me=false;function Dt(e){let t=e.slice(0,80);return t.length<=6?"***":t.slice(0,6)+"***"}function Bt(e,t,n,r){if(I.some(l=>l.rule===e&&l.source===t))return;let i={rule:e,source:t,hint:Dt(n),timestamp:Date.now()};r&&(i.location=r),I.push(i);}function W(e,t,n,r){for(let{name:o,pattern:i}of n){let l=i.exec(e);l&&Bt(o,t,l[0],r);}}function It(e){try{let t=window;if(t.__NEXT_DATA__){let n=JSON.stringify(t.__NEXT_DATA__);W(n,"hydration",e,"__NEXT_DATA__");}if(t.__NUXT__){let n=JSON.stringify(t.__NUXT__);W(n,"hydration",e,"__NUXT__");}}catch{}}function Nt(e){try{document.querySelectorAll("script:not([src])").forEach((n,r)=>{let o=n.textContent;o&&o.length>0&&W(o,"scripts",e,`inline-script[${r}]`);});}catch{}}function Ot(e){try{document.querySelectorAll("meta[content]").forEach(n=>{let r=n.getAttribute("content"),o=n.getAttribute("name")||n.getAttribute("property")||"";r&&r.length>10&&W(r,"meta",e,o?`meta[${o}]`:void 0);});}catch{}}function Ut(e){try{document.querySelectorAll("[data-api-key], [data-secret], [data-token], [data-password]").forEach(n=>{let r=n.attributes;for(let o=0;o<r.length;o++){let i=r[o];i.name.startsWith("data-")&&i.value.length>10&&W(i.value,"dom",e,`${n.tagName.toLowerCase()}[${i.name}]`);}});}catch{}}function Dn(e={}){if(me||!E()||(me=true,e.secretScan===false))return;let t=[...Lt,...e.customPatterns??[]],n=e.scanTargets??["hydration","scripts","meta","dom"];setTimeout(()=>{pe=Date.now(),n.includes("hydration")&&It(t),n.includes("scripts")&&Nt(t),n.includes("meta")&&Ot(t),n.includes("dom")&&Ut(t);let r=e.notify??"both";I.length>0&&(r==="console"||r==="both")&&console.warn(`[BlocFeed Security] Found ${I.length} potential secret(s) exposed in client code:`,I.map(o=>`${o.rule} (${o.source}${o.location?`: ${o.location}`:""})`));},100);}function Bn(){return {findings:[...I],scannedAt:pe}}function In(){I=[],pe=0,me=false;}
2
+ exports.a=E;exports.b=te;exports.c=ve;exports.d=Pe;exports.e=xe;exports.f=se;exports.g=Fe;exports.h=Jt;exports.i=en;exports.j=wt;exports.k=ce;exports.l=Rn;exports.m=Pn;exports.n=xn;exports.o=Fn;exports.p=Cn;exports.q=Dn;exports.r=Bn;exports.s=In;
@@ -38,6 +38,8 @@ interface BlocFeedHandle {
38
38
  open: () => void;
39
39
  close: () => void;
40
40
  submit: (message: string) => Promise<SubmitResult>;
41
+ startRecording: () => Promise<void>;
42
+ stopRecording: () => void;
41
43
  isOpen: boolean;
42
44
  }
43
45
  interface BlocFeedStrings {
@@ -59,6 +61,12 @@ interface BlocFeedStrings {
59
61
  categoryFeature?: string;
60
62
  categoryUx?: string;
61
63
  categoryGeneral?: string;
64
+ recordButton?: string;
65
+ stopRecordButton?: string;
66
+ recordingText?: string;
67
+ recordingDeniedText?: string;
68
+ videoPreviewLabel?: string;
69
+ removeVideoButton?: string;
62
70
  }
63
71
  interface ConsoleEntry {
64
72
  level: "error" | "warn" | "log";
@@ -162,7 +170,7 @@ interface CaptureResult {
162
170
  diagnostics: CaptureDiagnostics;
163
171
  }
164
172
  interface BlocFeedError {
165
- kind: "unknown" | "configuration" | "capture_failed" | "api_failed" | "aborted";
173
+ kind: "unknown" | "configuration" | "capture_failed" | "recording_failed" | "api_failed" | "aborted";
166
174
  message: string;
167
175
  detail?: Record<string, unknown>;
168
176
  }
@@ -184,6 +192,33 @@ interface ScreenshotAdapter {
184
192
  captureElement: (element: Element, options: ScreenshotAdapterOptions) => MaybePromise<ImageAsset>;
185
193
  captureFullPage: (options: ScreenshotAdapterOptions) => MaybePromise<ImageAsset>;
186
194
  }
195
+ type VideoMime = "video/webm";
196
+ interface RecordingConfig {
197
+ /** Enable video recording button in the widget. Default: false */
198
+ enabled?: boolean;
199
+ /** Maximum recording duration in milliseconds. Default: 30 000 (30 s) */
200
+ maxDurationMs?: number;
201
+ /** Video MIME type. Default: "video/webm" */
202
+ mime?: VideoMime;
203
+ /** Video bitrate in bits/s. Default: 2 500 000 (2.5 Mbps) */
204
+ videoBitsPerSecond?: number;
205
+ }
206
+ interface VideoAsset {
207
+ mime: VideoMime;
208
+ /** Object URL (blob:) for local preview. Revoked after submission. */
209
+ blobUrl: string;
210
+ /** The raw Blob — held in memory until uploaded. */
211
+ blob: Blob;
212
+ /** Duration of the recording in milliseconds. */
213
+ durationMs: number;
214
+ /** Byte size of the video blob. */
215
+ sizeBytes: number;
216
+ }
217
+ interface VideoIntent {
218
+ mime: string;
219
+ durationMs: number;
220
+ sizeBytes: number;
221
+ }
187
222
  interface CaptureConfig {
188
223
  element?: boolean;
189
224
  fullPage?: boolean;
@@ -242,6 +277,8 @@ interface BlocFeedConfig {
242
277
  diagnostics?: DiagnosticsConfig;
243
278
  /** Client-side secret leak detection. */
244
279
  security?: SecurityConfig;
280
+ /** Video recording configuration. */
281
+ recording?: RecordingConfig;
245
282
  ui?: {
246
283
  /** z-index for the widget overlay/panel. */
247
284
  zIndex?: number;
@@ -293,6 +330,10 @@ interface FeedbackPayload {
293
330
  screenshots?: CaptureResult;
294
331
  /** Lightweight screenshot metadata sent instead of base64 dataUrls. */
295
332
  screenshot_intent?: ScreenshotIntent;
333
+ /** Video recording asset (blob held separately during transport). */
334
+ video?: VideoAsset;
335
+ /** Lightweight video metadata sent instead of the blob. */
336
+ video_intent?: VideoIntent;
296
337
  /** First-class user identity. */
297
338
  user?: BlocFeedUser;
298
339
  metadata: Record<string, unknown>;
@@ -303,6 +344,7 @@ interface FeedbackApiResponse {
303
344
  upload_urls?: {
304
345
  element?: string;
305
346
  fullPage?: string;
347
+ video?: string;
306
348
  };
307
349
  }
308
350
  interface TransportResult {
@@ -314,11 +356,13 @@ interface SubmitResult {
314
356
  ok: boolean;
315
357
  api?: TransportResult;
316
358
  }
317
- type SessionPhase = "idle" | "picking" | "review" | "capturing" | "submitting" | "success" | "error";
359
+ type SessionPhase = "idle" | "picking" | "review" | "recording" | "capturing" | "submitting" | "success" | "error";
318
360
  interface BlocFeedState {
319
361
  phase: SessionPhase;
320
362
  selection?: ElementDescriptor;
321
363
  capture?: CaptureResult;
364
+ video?: VideoAsset;
365
+ recordingElapsedMs?: number;
322
366
  lastSubmit?: SubmitResult;
323
367
  lastError?: BlocFeedError;
324
368
  }
@@ -342,10 +386,13 @@ interface BlocFeedController {
342
386
  capture?: CaptureConfig;
343
387
  category?: FeedbackCategory;
344
388
  }) => Promise<SubmitResult>;
389
+ startRecording: () => Promise<void>;
390
+ stopRecording: () => void;
391
+ removeVideo: () => void;
345
392
  /** Internal: used by UI to access the live element handle. */
346
393
  __unsafeGetSelectedElement: () => Element | null;
347
394
  destroy: () => void;
348
395
  }
349
396
  declare function createBlocFeedController(config: BlocFeedConfig): BlocFeedController;
350
397
 
351
- export { type BlocFeedConfig as B, type CaptureConfig as C, type DiagnosticsConfig as D, type ElementDescriptor as E, type FeedbackCategory as F, type HoverListener as H, type ImageAsset as I, type MaybePromise as M, type NetworkEntry as N, type PickerConfig as P, type Rect as R, type SubmitResult as S, type ThemeConfig as T, type WidgetPosition as W, type BlocFeedHandle as a, type BlocFeedState as b, type BlocFeedController as c, type BlocFeedError as d, type BlocFeedStrings as e, type BlocFeedUser as f, type CaptureDiagnostics as g, type CaptureResult as h, type ConsoleEntry as i, type FeedbackApiResponse as j, type FeedbackPayload as k, type MetadataConfig as l, type MetadataContext as m, type ScreenshotAdapter as n, type ScreenshotAdapterOptions as o, type ScreenshotIntent as p, type ScreenshotMime as q, type SecurityConfig as r, type SecurityFinding as s, type SecuritySnapshot as t, type SessionPhase as u, type TransportConfig as v, type TransportResult as w, type TriggerStyle as x, type StateListener as y, createBlocFeedController as z };
398
+ export { type VideoMime as A, type BlocFeedConfig as B, type CaptureConfig as C, type DiagnosticsConfig as D, type ElementDescriptor as E, type FeedbackCategory as F, type StateListener as G, type HoverListener as H, type ImageAsset as I, createBlocFeedController as J, type MaybePromise as M, type NetworkEntry as N, type PickerConfig as P, type RecordingConfig as R, type SubmitResult as S, type ThemeConfig as T, type VideoAsset as V, type WidgetPosition as W, type BlocFeedHandle as a, type BlocFeedState as b, type BlocFeedController as c, type BlocFeedError as d, type BlocFeedStrings as e, type BlocFeedUser as f, type CaptureDiagnostics as g, type CaptureResult as h, type ConsoleEntry as i, type FeedbackApiResponse as j, type FeedbackPayload as k, type MetadataConfig as l, type MetadataContext as m, type Rect as n, type ScreenshotAdapter as o, type ScreenshotAdapterOptions as p, type ScreenshotIntent as q, type ScreenshotMime as r, type SecurityConfig as s, type SecurityFinding as t, type SecuritySnapshot as u, type SessionPhase as v, type TransportConfig as w, type TransportResult as x, type TriggerStyle as y, type VideoIntent as z };
@@ -38,6 +38,8 @@ interface BlocFeedHandle {
38
38
  open: () => void;
39
39
  close: () => void;
40
40
  submit: (message: string) => Promise<SubmitResult>;
41
+ startRecording: () => Promise<void>;
42
+ stopRecording: () => void;
41
43
  isOpen: boolean;
42
44
  }
43
45
  interface BlocFeedStrings {
@@ -59,6 +61,12 @@ interface BlocFeedStrings {
59
61
  categoryFeature?: string;
60
62
  categoryUx?: string;
61
63
  categoryGeneral?: string;
64
+ recordButton?: string;
65
+ stopRecordButton?: string;
66
+ recordingText?: string;
67
+ recordingDeniedText?: string;
68
+ videoPreviewLabel?: string;
69
+ removeVideoButton?: string;
62
70
  }
63
71
  interface ConsoleEntry {
64
72
  level: "error" | "warn" | "log";
@@ -162,7 +170,7 @@ interface CaptureResult {
162
170
  diagnostics: CaptureDiagnostics;
163
171
  }
164
172
  interface BlocFeedError {
165
- kind: "unknown" | "configuration" | "capture_failed" | "api_failed" | "aborted";
173
+ kind: "unknown" | "configuration" | "capture_failed" | "recording_failed" | "api_failed" | "aborted";
166
174
  message: string;
167
175
  detail?: Record<string, unknown>;
168
176
  }
@@ -184,6 +192,33 @@ interface ScreenshotAdapter {
184
192
  captureElement: (element: Element, options: ScreenshotAdapterOptions) => MaybePromise<ImageAsset>;
185
193
  captureFullPage: (options: ScreenshotAdapterOptions) => MaybePromise<ImageAsset>;
186
194
  }
195
+ type VideoMime = "video/webm";
196
+ interface RecordingConfig {
197
+ /** Enable video recording button in the widget. Default: false */
198
+ enabled?: boolean;
199
+ /** Maximum recording duration in milliseconds. Default: 30 000 (30 s) */
200
+ maxDurationMs?: number;
201
+ /** Video MIME type. Default: "video/webm" */
202
+ mime?: VideoMime;
203
+ /** Video bitrate in bits/s. Default: 2 500 000 (2.5 Mbps) */
204
+ videoBitsPerSecond?: number;
205
+ }
206
+ interface VideoAsset {
207
+ mime: VideoMime;
208
+ /** Object URL (blob:) for local preview. Revoked after submission. */
209
+ blobUrl: string;
210
+ /** The raw Blob — held in memory until uploaded. */
211
+ blob: Blob;
212
+ /** Duration of the recording in milliseconds. */
213
+ durationMs: number;
214
+ /** Byte size of the video blob. */
215
+ sizeBytes: number;
216
+ }
217
+ interface VideoIntent {
218
+ mime: string;
219
+ durationMs: number;
220
+ sizeBytes: number;
221
+ }
187
222
  interface CaptureConfig {
188
223
  element?: boolean;
189
224
  fullPage?: boolean;
@@ -242,6 +277,8 @@ interface BlocFeedConfig {
242
277
  diagnostics?: DiagnosticsConfig;
243
278
  /** Client-side secret leak detection. */
244
279
  security?: SecurityConfig;
280
+ /** Video recording configuration. */
281
+ recording?: RecordingConfig;
245
282
  ui?: {
246
283
  /** z-index for the widget overlay/panel. */
247
284
  zIndex?: number;
@@ -293,6 +330,10 @@ interface FeedbackPayload {
293
330
  screenshots?: CaptureResult;
294
331
  /** Lightweight screenshot metadata sent instead of base64 dataUrls. */
295
332
  screenshot_intent?: ScreenshotIntent;
333
+ /** Video recording asset (blob held separately during transport). */
334
+ video?: VideoAsset;
335
+ /** Lightweight video metadata sent instead of the blob. */
336
+ video_intent?: VideoIntent;
296
337
  /** First-class user identity. */
297
338
  user?: BlocFeedUser;
298
339
  metadata: Record<string, unknown>;
@@ -303,6 +344,7 @@ interface FeedbackApiResponse {
303
344
  upload_urls?: {
304
345
  element?: string;
305
346
  fullPage?: string;
347
+ video?: string;
306
348
  };
307
349
  }
308
350
  interface TransportResult {
@@ -314,11 +356,13 @@ interface SubmitResult {
314
356
  ok: boolean;
315
357
  api?: TransportResult;
316
358
  }
317
- type SessionPhase = "idle" | "picking" | "review" | "capturing" | "submitting" | "success" | "error";
359
+ type SessionPhase = "idle" | "picking" | "review" | "recording" | "capturing" | "submitting" | "success" | "error";
318
360
  interface BlocFeedState {
319
361
  phase: SessionPhase;
320
362
  selection?: ElementDescriptor;
321
363
  capture?: CaptureResult;
364
+ video?: VideoAsset;
365
+ recordingElapsedMs?: number;
322
366
  lastSubmit?: SubmitResult;
323
367
  lastError?: BlocFeedError;
324
368
  }
@@ -342,10 +386,13 @@ interface BlocFeedController {
342
386
  capture?: CaptureConfig;
343
387
  category?: FeedbackCategory;
344
388
  }) => Promise<SubmitResult>;
389
+ startRecording: () => Promise<void>;
390
+ stopRecording: () => void;
391
+ removeVideo: () => void;
345
392
  /** Internal: used by UI to access the live element handle. */
346
393
  __unsafeGetSelectedElement: () => Element | null;
347
394
  destroy: () => void;
348
395
  }
349
396
  declare function createBlocFeedController(config: BlocFeedConfig): BlocFeedController;
350
397
 
351
- export { type BlocFeedConfig as B, type CaptureConfig as C, type DiagnosticsConfig as D, type ElementDescriptor as E, type FeedbackCategory as F, type HoverListener as H, type ImageAsset as I, type MaybePromise as M, type NetworkEntry as N, type PickerConfig as P, type Rect as R, type SubmitResult as S, type ThemeConfig as T, type WidgetPosition as W, type BlocFeedHandle as a, type BlocFeedState as b, type BlocFeedController as c, type BlocFeedError as d, type BlocFeedStrings as e, type BlocFeedUser as f, type CaptureDiagnostics as g, type CaptureResult as h, type ConsoleEntry as i, type FeedbackApiResponse as j, type FeedbackPayload as k, type MetadataConfig as l, type MetadataContext as m, type ScreenshotAdapter as n, type ScreenshotAdapterOptions as o, type ScreenshotIntent as p, type ScreenshotMime as q, type SecurityConfig as r, type SecurityFinding as s, type SecuritySnapshot as t, type SessionPhase as u, type TransportConfig as v, type TransportResult as w, type TriggerStyle as x, type StateListener as y, createBlocFeedController as z };
398
+ export { type VideoMime as A, type BlocFeedConfig as B, type CaptureConfig as C, type DiagnosticsConfig as D, type ElementDescriptor as E, type FeedbackCategory as F, type StateListener as G, type HoverListener as H, type ImageAsset as I, createBlocFeedController as J, type MaybePromise as M, type NetworkEntry as N, type PickerConfig as P, type RecordingConfig as R, type SubmitResult as S, type ThemeConfig as T, type VideoAsset as V, type WidgetPosition as W, type BlocFeedHandle as a, type BlocFeedState as b, type BlocFeedController as c, type BlocFeedError as d, type BlocFeedStrings as e, type BlocFeedUser as f, type CaptureDiagnostics as g, type CaptureResult as h, type ConsoleEntry as i, type FeedbackApiResponse as j, type FeedbackPayload as k, type MetadataConfig as l, type MetadataContext as m, type Rect as n, type ScreenshotAdapter as o, type ScreenshotAdapterOptions as p, type ScreenshotIntent as q, type ScreenshotMime as r, type SecurityConfig as s, type SecurityFinding as t, type SecuritySnapshot as u, type SessionPhase as v, type TransportConfig as w, type TransportResult as x, type TriggerStyle as y, type VideoIntent as z };
package/dist/engine.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var chunkFOZ6KYBJ_cjs=require('./chunk-FOZ6KYBJ.cjs');function c(o){if(o?.aborted)throw new Error("Aborted")}async function P(o){return await new Promise((t,e)=>{let r=new Image;r.onload=()=>t({width:r.naturalWidth,height:r.naturalHeight}),r.onerror=()=>e(new Error("Failed to load generated screenshot")),r.src=o;})}async function l(o,t){let{width:e,height:r}=await P(o);return {dataUrl:o,mime:t,width:e,height:r}}function B(o){return {async captureElement(t,e){if(!chunkFOZ6KYBJ_cjs.a())throw new Error("captureElement can only run in the browser");c(e.signal);let r={scale:e.pixelRatio},n=e.mime==="image/jpeg"?await o.domToJpeg(t,{...r,quality:e.quality??.92}):await o.domToPng(t,r);return c(e.signal),await l(n,e.mime)},async captureFullPage(t){if(!chunkFOZ6KYBJ_cjs.a())throw new Error("captureFullPage can only run in the browser");c(t.signal);let e=document.documentElement,r=Math.max(e.scrollWidth,e.clientWidth),n=Math.max(e.scrollHeight,e.clientHeight),a=Math.min(1,t.maxDimension/Math.max(r,n)),s={width:Math.max(1,Math.round(r*a)),height:Math.max(1,Math.round(n*a)),scale:t.pixelRatio},i=t.mime==="image/jpeg"?await o.domToJpeg(e,{...s,quality:t.quality??.92}):await o.domToPng(e,s);return c(t.signal),await l(i,t.mime)}}}function T(o){let[t,e]=o.split(",",2);if(!t||!e)throw new Error("Invalid data URL");let n=/data:(.*?);base64/.exec(t)?.[1]||"application/octet-stream",a=atob(e),s=new Uint8Array(a.length);for(let i=0;i<a.length;i+=1)s[i]=a.charCodeAt(i);return new Blob([s],{type:n})}Object.defineProperty(exports,"clearDiagnostics",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.n}});Object.defineProperty(exports,"clearQueue",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.h}});Object.defineProperty(exports,"clearSecurityFindings",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.q}});Object.defineProperty(exports,"collectMetadata",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.e}});Object.defineProperty(exports,"createBlocFeedController",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.j}});Object.defineProperty(exports,"createHtmlToImageAdapter",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.c}});Object.defineProperty(exports,"dequeueAll",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.g}});Object.defineProperty(exports,"drainDiagnostics",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.m}});Object.defineProperty(exports,"enqueue",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.f}});Object.defineProperty(exports,"getQueueSize",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.i}});Object.defineProperty(exports,"getSecurityFindings",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.p}});Object.defineProperty(exports,"installDiagnostics",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.k}});Object.defineProperty(exports,"runCapture",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.d}});Object.defineProperty(exports,"runSecretScan",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.o}});Object.defineProperty(exports,"uninstallDiagnostics",{enumerable:true,get:function(){return chunkFOZ6KYBJ_cjs.l}});exports.createModernScreenshotAdapter=B;exports.dataUrlToBlob=T;
1
+ 'use strict';var chunkORVW2RTZ_cjs=require('./chunk-ORVW2RTZ.cjs');function c(o){if(o?.aborted)throw new Error("Aborted")}async function P(o){return await new Promise((t,e)=>{let r=new Image;r.onload=()=>t({width:r.naturalWidth,height:r.naturalHeight}),r.onerror=()=>e(new Error("Failed to load generated screenshot")),r.src=o;})}async function l(o,t){let{width:e,height:r}=await P(o);return {dataUrl:o,mime:t,width:e,height:r}}function B(o){return {async captureElement(t,e){if(!chunkORVW2RTZ_cjs.a())throw new Error("captureElement can only run in the browser");c(e.signal);let r={scale:e.pixelRatio},n=e.mime==="image/jpeg"?await o.domToJpeg(t,{...r,quality:e.quality??.92}):await o.domToPng(t,r);return c(e.signal),await l(n,e.mime)},async captureFullPage(t){if(!chunkORVW2RTZ_cjs.a())throw new Error("captureFullPage can only run in the browser");c(t.signal);let e=document.documentElement,r=Math.max(e.scrollWidth,e.clientWidth),n=Math.max(e.scrollHeight,e.clientHeight),a=Math.min(1,t.maxDimension/Math.max(r,n)),s={width:Math.max(1,Math.round(r*a)),height:Math.max(1,Math.round(n*a)),scale:t.pixelRatio},i=t.mime==="image/jpeg"?await o.domToJpeg(e,{...s,quality:t.quality??.92}):await o.domToPng(e,s);return c(t.signal),await l(i,t.mime)}}}function k(o){let[t,e]=o.split(",",2);if(!t||!e)throw new Error("Invalid data URL");let n=/data:(.*?);base64/.exec(t)?.[1]||"application/octet-stream",a=atob(e),s=new Uint8Array(a.length);for(let i=0;i<a.length;i+=1)s[i]=a.charCodeAt(i);return new Blob([s],{type:n})}Object.defineProperty(exports,"clearDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.p}});Object.defineProperty(exports,"clearQueue",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.h}});Object.defineProperty(exports,"clearSecurityFindings",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.s}});Object.defineProperty(exports,"collectMetadata",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.e}});Object.defineProperty(exports,"createBlocFeedController",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.l}});Object.defineProperty(exports,"createHtmlToImageAdapter",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.c}});Object.defineProperty(exports,"dequeueAll",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.g}});Object.defineProperty(exports,"drainDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.o}});Object.defineProperty(exports,"enqueue",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.f}});Object.defineProperty(exports,"getQueueSize",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.i}});Object.defineProperty(exports,"getSecurityFindings",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.r}});Object.defineProperty(exports,"installDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.m}});Object.defineProperty(exports,"isRecordingSupported",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.j}});Object.defineProperty(exports,"runCapture",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.d}});Object.defineProperty(exports,"runSecretScan",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.q}});Object.defineProperty(exports,"startRecording",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.k}});Object.defineProperty(exports,"uninstallDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.n}});exports.createModernScreenshotAdapter=B;exports.dataUrlToBlob=k;