@unhingged/vizu-core 0.1.7 → 0.1.9

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/dist/vizu.min.js CHANGED
@@ -7,7 +7,7 @@
7
7
  <span class="vz-attachment-icon" aria-hidden="true">\u{1F4C4}</span>
8
8
  <span class="vz-attachment-filename">${d(i)}</span>
9
9
  </a>
10
- `}).join("")}</div>`}function C(o){if(!o||typeof o!="object")return o;let e={...o};return(!Array.isArray(e.fingerprints)||e.fingerprints.length===0)&&e.fingerprint&&(e.fingerprints=[e.fingerprint]),delete e.fingerprint,e.url&&!e.pageUrl&&(e.pageUrl=e.url),(!("status"in e)||!Se(e.status))&&(e.status="open"),Array.isArray(e.replies)||(e.replies=[]),Array.isArray(e.attachments)||(e.attachments=[]),Array.isArray(e.mentions)||(e.mentions=[]),"fingerprintsRefreshedAt"in e||(e.fingerprintsRefreshedAt=null),e.schemaVersion=2,e}function Se(o){return o==="open"||o==="resolved"||o==="wontfix"}function k(o){if(!Array.isArray(o))return[];let e=[];for(let t of o)!t||typeof t!="object"||e.push(C(t));return e}function re(o){if(!Array.isArray(o))return!1;for(let e of o){if(!e||typeof e!="object")continue;let t=e;if(t.schemaVersion!==2||"fingerprint"in t||!Array.isArray(t.replies)||!Array.isArray(t.attachments)||!Array.isArray(t.mentions))return!0}return!1}var Z=o=>`vizu:comments:${o}`,I=class{async load(e){return T(e)}async addComment(e,t){let n=T(e);n.push(t),M(e,n)}async updateComment(e,t,n){let i=T(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],...n,id:i[r].id};return i[r]=s,M(e,i),s}async removeComment(e,t){let n=T(e);M(e,n.filter(i=>i.id!==t))}async setAll(e,t){M(e,t)}async clear(e){typeof localStorage>"u"||localStorage.removeItem(Z(e))}async addReply(e,t,n){let i=T(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],replies:[...i[r].replies??[],n]};return i[r]=s,M(e,i),s}async removeReply(e,t,n){let i=T(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],replies:(i[r].replies??[]).filter(a=>a.id!==n)};return i[r]=s,M(e,i),s}};function T(o){if(typeof localStorage>"u")return[];let e=localStorage.getItem(Z(o));if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?k(t):[]}catch{return[]}}function M(o,e){typeof localStorage>"u"||localStorage.setItem(Z(o),JSON.stringify(e))}var O=class{constructor(){this.store=new Map}async load(e){return[...this.store.get(e)||[]]}async addComment(e,t){let n=this.store.get(e)??[];this.store.set(e,[...n,t])}async updateComment(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],...n,id:i[r].id},a=[...i];return a[r]=s,this.store.set(e,a),s}async removeComment(e,t){let n=this.store.get(e)??[];this.store.set(e,n.filter(i=>i.id!==t))}async setAll(e,t){this.store.set(e,[...t])}async clear(e){this.store.delete(e)}async addReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],replies:[...i[r].replies??[],n]},a=[...i];return a[r]=s,this.store.set(e,a),s}async removeReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],replies:(i[r].replies??[]).filter(l=>l.id!==n)},a=[...i];return a[r]=s,this.store.set(e,a),s}},N=class{async load(){return[]}async addComment(){}async updateComment(){return null}async removeComment(){}async setAll(){}async clear(){}};function G(o){if(!o||typeof o!="object")return!1;let e=o;return typeof e.load=="function"&&typeof e.save=="function"&&typeof e.clear=="function"&&typeof e.addComment!="function"}function se(o){if(!G(o))return o;let e=!1,t=()=>{e||(e=!0,typeof console<"u"&&console.warn("[vizu] StorageAdapter v1 detected. Per-comment ops are emulated via full-array rewrites \u2014 upgrade your adapter to the v2 interface (addComment / updateComment / removeComment / setAll / load / clear) when you can."))};return{async load(n){return t(),o.load(n)},async addComment(n,i){t();let r=await o.load(n);r.push(i),await o.save(n,r)},async updateComment(n,i,r){t();let s=await o.load(n),a=s.findIndex(c=>c.id===i);if(a===-1)return null;let l={...s[a],...r,id:s[a].id};return s[a]=l,await o.save(n,s),l},async removeComment(n,i){t();let r=await o.load(n);await o.save(n,r.filter(s=>s.id!==i))},async setAll(n,i){t(),await o.save(n,i)},async clear(n){await o.clear(n)}}}var Te="https://vizu.unhingged.com",oe=480,ae=640,R=class{constructor(e){this.cachedToken=null;this.pendingAuth=null;this.lastNotifiedTokenId=null;this.accessDenied=!1;this.accessDeniedReason=null;this.workspace=e.workspace,this.apiUrl=(e.apiUrl??Te).replace(/\/$/,""),this.autoSignIn=e.autoSignIn!==!1,this.onAuthChanged=e.onAuthChanged;let t=this.readHashToken();t?(this.cachedToken=t,this.writeStoredToken(t)):this.cachedToken=this.readStoredToken(),this.cachedToken&&!this.isExpired(this.cachedToken)&&this.fireAuthChanged(this.cachedToken)}readHashToken(){if(typeof window>"u")return null;let e=window.location.hash;if(!e||e.length<2)return null;let t=new URLSearchParams(e.slice(1)),n=t.get("vizu_auth");if(!n)return null;try{let i=JSON.parse(atob(n));if(!i.t||!i.e||!i.u||!i.w||i.w!==this.workspace)return null;let r={token:i.t,expiresAt:i.e,userId:i.u,user:typeof i.n=="string"?{id:i.u,name:i.n,avatarUrl:typeof i.a=="string"?i.a:void 0}:null};t.delete("vizu_auth");let s=t.toString(),a=s?`#${s}`:"";try{let l=window.location.pathname+window.location.search+a;window.history.replaceState(null,"",l)}catch{}return r}catch{return null}}async preflightAuth(){await this.resolveToken()}isAccessDenied(){return this.accessDenied}accessDenialReason(){return this.accessDeniedReason}async load(e){let t=[],n=null;do{let i=new URL(this.apiUrl+"/api/comments");i.searchParams.set("workspace",this.workspace),i.searchParams.set("limit","100"),n&&i.searchParams.set("cursor",n);let r=await this.fetchAuthed(i.toString(),{method:"GET"}),s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);let a=Array.isArray(s.comments)?s.comments:[];t.push(...k(a)),n=typeof s.nextCursor=="string"?s.nextCursor:null}while(n);return t}async addComment(e,t){let n=await this.fetchAuthed(this.apiUrl+"/api/comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({workspace:this.workspace,comment:t})}),i=await this.parseJson(n);if(!n.ok)throw x(n.status,i)}async updateComment(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);return C(s.comment)}async removeComment(e,t){let n=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));n.searchParams.set("workspace",this.workspace);let i=await this.fetchAuthed(n.toString(),{method:"DELETE"});if(i.status!==404&&!i.ok){let r=await this.parseJson(i);throw x(i.status,r)}}async setAll(e,t){await this.clear(e);for(let n of t)await this.addComment(e,n)}async clear(e){let t=new URL(this.apiUrl+"/api/comments");t.searchParams.set("workspace",this.workspace),t.searchParams.set("all","true");let n=await this.fetchAuthed(t.toString(),{method:"DELETE"});if(n.status!==404&&!n.ok){let i=await this.parseJson(n);throw x(n.status,i)}}async addReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);return s?.comment?C(s.comment):null}async removeReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies/"+encodeURIComponent(n));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"DELETE"});if(r.status===404)return null;if(!r.ok){let s=await this.parseJson(r);throw x(r.status,s)}return null}async uploadAttachment(e,t){let n=new FormData;n.append("file",t,t.name);let i=new URL(this.apiUrl+"/api/uploads");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",body:n}),s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);if(!s?.url||typeof s.url!="string")throw x(500,{error:"upload_failed",message:"Backend did not return a URL."});return{id:F(),url:s.url,mimeType:t.type||"application/octet-stream",sizeBytes:t.size,uploadedAt:Date.now(),filename:t.name}}getAuthContext(){return this.cachedToken?{userId:this.cachedToken.userId,token:this.cachedToken.token,expiresAt:this.cachedToken.expiresAt}:null}isExpired(e){if(!e)return!0;let t=new Date(e.expiresAt).getTime();return!Number.isFinite(t)||t-Date.now()<3e4}readStoredToken(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.sessionKey());if(!e)return null;try{let t=JSON.parse(e);return this.isExpired(t)?(sessionStorage.removeItem(this.sessionKey()),null):t}catch{return null}}writeStoredToken(e){this.cachedToken=e,typeof sessionStorage<"u"&&sessionStorage.setItem(this.sessionKey(),JSON.stringify(e))}clearStoredToken(){this.cachedToken=null,typeof sessionStorage<"u"&&sessionStorage.removeItem(this.sessionKey())}sessionKey(){return`vizu:cloud-token:v2:${this.workspace}`}async resolveToken(){if(this.cachedToken&&!this.isExpired(this.cachedToken))return this.cachedToken;let e=this.readStoredToken();if(e)return this.cachedToken=e,this.fireAuthChanged(e),e;if(this.accessDenied)throw V("access_denied",`No access to workspace "${this.workspace}" (${this.accessDeniedReason??"no_access"}).`);if(!this.autoSignIn)throw V("auth_required","Sign-in required; autoSignIn is disabled.");return this.pendingAuth||(this.pendingAuth=this.openSignInPopup().then(t=>(this.writeStoredToken(t),this.fireAuthChanged(t),t)).finally(()=>{this.pendingAuth=null})),this.pendingAuth}fireAuthChanged(e){if(this.lastNotifiedTokenId!==e.token){this.lastNotifiedTokenId=e.token;try{this.onAuthChanged?.({userId:e.userId,user:e.user})}catch(t){typeof console<"u"&&console.warn("[vizu/cloud] onAuthChanged callback threw",t)}}}openSignInPopup(){return new Promise((e,t)=>{if(typeof window>"u")return t(V("auth_unavailable","Sign-in requires a browser environment."));let n=new URL(this.apiUrl).origin,i=window.location.origin,r=this.apiUrl+"/connect?workspace="+encodeURIComponent(this.workspace)+"&origin="+encodeURIComponent(i),s=Math.max(0,Math.round((window.screen.width-oe)/2)),a=Math.max(0,Math.round((window.screen.height-ae)/2)),l=window.open(r,"vizu-connect",`width=${oe},height=${ae},left=${s},top=${a},noopener=no,popup=yes`);if(!l)try{let v=window.location.href,f=this.apiUrl+"/connect?workspace="+encodeURIComponent(this.workspace)+"&origin="+encodeURIComponent(i)+"&return_to="+encodeURIComponent(v);window.location.assign(f);return}catch(v){return t(V("popup_blocked","Sign-in popup was blocked and redirect fallback failed: "+(v instanceof Error?v.message:String(v))))}let c=!1,p=v=>{if(v.origin!==n)return;let f=v.data;if(!f)return;if(f.type==="vizu:auth-denied"&&f.workspace===this.workspace){c=!0,$(),this.accessDenied=!0,this.accessDeniedReason=typeof f.reason=="string"?f.reason:"no_access",t(V("access_denied",`No access to workspace "${this.workspace}" (${this.accessDeniedReason}).`));return}if(f.type!=="vizu:auth"||f.workspace!==this.workspace||typeof f.token!="string"||typeof f.expiresAt!="string"||typeof f.userId!="string")return;c=!0,$();let b=f.user,u=b&&typeof b.name=="string"?{id:typeof b.id=="string"?b.id:f.userId,name:b.name,avatarUrl:typeof b.avatarUrl=="string"?b.avatarUrl:void 0}:null;e({token:f.token,expiresAt:f.expiresAt,userId:f.userId,user:u})},m=window.setInterval(()=>{l.closed&&(c||($(),t(V("auth_canceled","Sign-in popup was closed before completing."))))},500);function $(){window.clearInterval(m),window.removeEventListener("message",p)}window.addEventListener("message",p)})}async fetchAuthed(e,t,n=!1){let i=await this.resolveToken(),r=new Headers(t.headers);r.set("authorization",`Bearer ${i.token}`);let s=await fetch(e,{...t,headers:r,credentials:"omit"});return s.status===401&&!n?(this.clearStoredToken(),this.fetchAuthed(e,t,!0)):s}async parseJson(e){try{let t=await e.text();return t?JSON.parse(t):null}catch{return null}}};function V(o,e){let t=new Error(e);return t.code=o,t}function x(o,e){let t=e?.error==="origin_not_allowed"?"origin_not_allowed":e?.error==="not_found"?"workspace_not_found":"http_error",n=new Error(e?.message??`HTTP ${o}`);return n.code=t,n.status=o,n.body=e,n}function le(o){let e=[],t=o,n=0;for(;t&&t!==document.documentElement&&n<8;){let i=t.tagName.toLowerCase();if(t.id){e.unshift("#"+CSS.escape(t.id));break}let r=Array.from(t.classList).filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")).slice(0,2);r.length&&(i+="."+r.map(a=>CSS.escape(a)).join("."));let s=t.parentElement;if(s){let a=Array.from(s.children).filter(l=>l.tagName===t.tagName);if(a.length>1){let l=a.indexOf(t);i+=":nth-of-type("+(l+1)+")"}}e.unshift(i),t=s,n++}return e.join(" > ")}function _(o){let e=o.innerText||o.textContent||"",t=o.parentElement,n=0;return t&&(n=Array.from(t.children).indexOf(o)),{selector:le(o),parentSelector:t?le(t):"",tagName:o.tagName,textSnippet:e.trim().slice(0,80),siblingIndex:n,attributes:{id:o.id||void 0,classList:Array.from(o.classList).filter(i=>!i.startsWith("vz-")&&!i.startsWith("vizu-")),role:o.getAttribute("role")||void 0,ariaLabel:o.getAttribute("aria-label")||void 0,dataKey:o.getAttribute("data-vizu-key")||void 0},ancestorChain:Me(o,4),algorithmVersion:2}}function Me(o,e){let t=[],n=o.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t.length>0?{steps:t}:void 0}function j(o,e=document){if(o.attributes.dataKey){try{let s=e.querySelector(`[data-vizu-key="${CSS.escape(o.attributes.dataKey)}"]`);if(s)return{element:s,confidence:"exact"}}catch{}return{element:null,confidence:"orphaned"}}if(o.attributes.id)try{let s=e.querySelector("#"+CSS.escape(o.attributes.id));if(s)return{element:s,confidence:"exact"}}catch{}let t=[],n=o.attributes.classList;if(n&&n.length>0){let s=Ve(e,o.tagName,n);s?.element&&t.push({el:s.element,rung:"class"})}try{let s=e.querySelector(o.selector);s&&t.push({el:s,rung:"selector"})}catch{}if(o.ancestorChain&&o.ancestorChain.steps.length>0){let s=Re(e,o.tagName,o.ancestorChain.steps);s?.element&&t.push({el:s.element,rung:"chain"})}else try{let s=o.parentSelector?e.querySelector(o.parentSelector):e;if(s){let a=s.children[o.siblingIndex];a&&a.tagName===o.tagName&&t.push({el:a,rung:"chain"})}}catch{}if(o.textSnippet){let s=Pe(e,o.tagName,o.textSnippet);s?.element&&t.push({el:s.element,rung:"text"})}if(t.length===0)return{element:null,confidence:"orphaned"};let i=new Map;for(let s of t){let a=i.get(s.el);a||(a=new Set,i.set(s.el,a)),a.add(s.rung)}let r=null;for(let[s,a]of i)(!r||a.size>r.rungs.size)&&(r={el:s,rungs:a});return r?r.rungs.size>=3?{element:r.el,confidence:"likely"}:r.rungs.size>=2?{element:r.el,confidence:"drifted"}:r.rungs.has("class")||r.rungs.has("chain")?{element:r.el,confidence:"drifted"}:{element:null,confidence:"orphaned"}:{element:null,confidence:"orphaned"}}function Ve(o,e,t){let n=new Set(t.filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")));if(n.size===0)return null;let i=o.querySelectorAll(e.toLowerCase()),r=null,s=0;for(let a of i){let l=new Set(Array.from(a.classList).filter(p=>!p.startsWith("vz-")&&!p.startsWith("vizu-")));if(l.size===0)continue;let c=Ue(n,l);c<.6||(!r||c>r.score?(s=r?.score??0,r={el:a,score:c}):c>s&&(s=c))}return!r||r.score-s<.1?null:{element:r.el,confidence:"likely"}}function Re(o,e,t){let n=o.querySelectorAll(e.toLowerCase()),i=null;for(let r of n){let s=Le(r,t.length+3),a=He(s,t,3);a<2||(!i||a>i.score)&&(i={el:r,score:a})}return i?{element:i.el,confidence:i.score===t.length?"likely":"drifted"}:null}function Le(o,e){let t=[],n=o.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t}function Pe(o,e,t){let n=ce(t);if(!n)return null;let i=o.querySelectorAll(e.toLowerCase()),r=null;for(let s of i){let a=s.innerText||s.textContent||"",l=ce(a.slice(0,160));if(!l)continue;let c=$e(n,l);c<.75||(!r||c>r.score)&&(r={el:s,score:c})}return r?{element:r.el,confidence:"drifted"}:null}function ce(o){return o.toLowerCase().replace(/\s+/g," ").trim()}function $e(o,e){if(o===e)return 1;if(o.length===0||e.length===0)return o.length===e.length?1:0;let t=Math.max(o.length,e.length);return 1-Fe(o,e)/t}function Fe(o,e){if(o.length>e.length){let i=o;o=e,e=i}let t=new Array(o.length+1),n=new Array(o.length+1);for(let i=0;i<=o.length;i++)t[i]=i;for(let i=1;i<=e.length;i++){n[0]=i;for(let r=1;r<=o.length;r++){let s=o.charCodeAt(r-1)===e.charCodeAt(i-1)?0:1;n[r]=Math.min(n[r-1]+1,t[r]+1,t[r-1]+s)}for(let r=0;r<=o.length;r++)t[r]=n[r]}return t[o.length]}function He(o,e,t){let n=0;for(let i=0;i<=t;i++){let r=0;for(let s=0;s<e.length;s++){let a=o[s+i];if(!a)break;a.tag===e[s].tag&&a.nthOfType===e[s].nthOfType&&r++}r>n&&(n=r)}return n}function Ue(o,e){if(o.size===0&&e.size===0)return 1;let t=0;for(let i of o)e.has(i)&&t++;let n=o.size+e.size-t;return n===0?0:t/n}function L(o,e){return j(o,e).element}function h(o){return o.selector+"|"+o.textSnippet}function P(o){let e=o.tagName.toLowerCase();if(o.textSnippet){let t=o.textSnippet.length>24?o.textSnippet.slice(0,24)+"\u2026":o.textSnippet;return e+": "+t}return o.attributes.id?e+"#"+o.attributes.id:o.attributes.classList&&o.attributes.classList.length?e+"."+o.attributes.classList[0]:e}var Ie="[data-vizu-root], [data-vizu-ignore], script, style, link, meta, head",q=class{constructor(e,t,n){this.current=null;this.active=!1;this.paused=!1;this.handleMove=e=>{if(this.paused){this.setCurrent(null),this.overlay.style.display="none";return}let t=document.elementFromPoint(e.clientX,e.clientY);if(!(!t||t===this.current)){if(this.shouldIgnore(t)){this.setCurrent(null),this.overlay.style.display="none";return}this.setCurrent(t),this.updateOverlay()}};this.handleClick=e=>{let t=document.elementFromPoint(e.clientX,e.clientY);t&&(this.shouldIgnore(t)||(e.preventDefault(),e.stopPropagation(),this.onClick(t,e)))};this.handleScroll=()=>{this.current&&this.updateOverlay()};this.root=e,this.extraIgnore=t,this.onClick=n,this.overlay=document.createElement("div"),this.overlay.className="vz-highlight",this.overlay.style.display="none",this.root.appendChild(this.overlay)}setCurrent(e){this.current!==e&&(this.current=e)}start(){this.active||(this.active=!0,document.addEventListener("mousemove",this.handleMove,!0),document.addEventListener("click",this.handleClick,!0),document.addEventListener("scroll",this.handleScroll,!0),window.addEventListener("resize",this.handleScroll))}stop(){this.active&&(this.active=!1,document.removeEventListener("mousemove",this.handleMove,!0),document.removeEventListener("click",this.handleClick,!0),document.removeEventListener("scroll",this.handleScroll,!0),window.removeEventListener("resize",this.handleScroll),this.overlay.style.display="none",this.setCurrent(null))}shouldIgnore(e){if(e===document.documentElement||e===document.body||Y(e,Ie))return!0;for(let t of this.extraIgnore)try{if(Y(e,t))return!0}catch{}return!1}setPaused(e){this.paused=e,e&&(this.setCurrent(null),this.overlay.style.display="none")}isPaused(){return this.paused}updateOverlay(){if(!this.current)return;let e=this.current.getBoundingClientRect();if(e.width===0||e.height===0){this.overlay.style.display="none";return}this.overlay.style.display="block",this.overlay.style.left=e.left+"px",this.overlay.style.top=e.top+"px",this.overlay.style.width=e.width+"px",this.overlay.style.height=e.height+"px"}destroy(){this.stop(),this.overlay.remove()}};function de(o){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(o):o.replace(/["\\]/g,"\\$&")}function Oe(o){let t=(o.replies??[]).map(n=>`
10
+ `}).join("")}</div>`}function C(o){if(!o||typeof o!="object")return o;let e={...o};return(!Array.isArray(e.fingerprints)||e.fingerprints.length===0)&&e.fingerprint&&(e.fingerprints=[e.fingerprint]),delete e.fingerprint,e.url&&!e.pageUrl&&(e.pageUrl=e.url),(!("status"in e)||!Se(e.status))&&(e.status="open"),Array.isArray(e.replies)||(e.replies=[]),Array.isArray(e.attachments)||(e.attachments=[]),Array.isArray(e.mentions)||(e.mentions=[]),"fingerprintsRefreshedAt"in e||(e.fingerprintsRefreshedAt=null),e.schemaVersion=2,e}function Se(o){return o==="open"||o==="resolved"||o==="wontfix"}function k(o){if(!Array.isArray(o))return[];let e=[];for(let t of o)!t||typeof t!="object"||e.push(C(t));return e}function re(o){if(!Array.isArray(o))return!1;for(let e of o){if(!e||typeof e!="object")continue;let t=e;if(t.schemaVersion!==2||"fingerprint"in t||!Array.isArray(t.replies)||!Array.isArray(t.attachments)||!Array.isArray(t.mentions))return!0}return!1}var Z=o=>`vizu:comments:${o}`,I=class{async load(e){return T(e)}async addComment(e,t){let n=T(e);n.push(t),M(e,n)}async updateComment(e,t,n){let i=T(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],...n,id:i[r].id};return i[r]=s,M(e,i),s}async removeComment(e,t){let n=T(e);M(e,n.filter(i=>i.id!==t))}async setAll(e,t){M(e,t)}async clear(e){typeof localStorage>"u"||localStorage.removeItem(Z(e))}async addReply(e,t,n){let i=T(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],replies:[...i[r].replies??[],n]};return i[r]=s,M(e,i),s}async removeReply(e,t,n){let i=T(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],replies:(i[r].replies??[]).filter(a=>a.id!==n)};return i[r]=s,M(e,i),s}};function T(o){if(typeof localStorage>"u")return[];let e=localStorage.getItem(Z(o));if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?k(t):[]}catch{return[]}}function M(o,e){typeof localStorage>"u"||localStorage.setItem(Z(o),JSON.stringify(e))}var O=class{constructor(){this.store=new Map}async load(e){return[...this.store.get(e)||[]]}async addComment(e,t){let n=this.store.get(e)??[];this.store.set(e,[...n,t])}async updateComment(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],...n,id:i[r].id},a=[...i];return a[r]=s,this.store.set(e,a),s}async removeComment(e,t){let n=this.store.get(e)??[];this.store.set(e,n.filter(i=>i.id!==t))}async setAll(e,t){this.store.set(e,[...t])}async clear(e){this.store.delete(e)}async addReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],replies:[...i[r].replies??[],n]},a=[...i];return a[r]=s,this.store.set(e,a),s}async removeReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],replies:(i[r].replies??[]).filter(l=>l.id!==n)},a=[...i];return a[r]=s,this.store.set(e,a),s}},N=class{async load(){return[]}async addComment(){}async updateComment(){return null}async removeComment(){}async setAll(){}async clear(){}};function G(o){if(!o||typeof o!="object")return!1;let e=o;return typeof e.load=="function"&&typeof e.save=="function"&&typeof e.clear=="function"&&typeof e.addComment!="function"}function se(o){if(!G(o))return o;let e=!1,t=()=>{e||(e=!0,typeof console<"u"&&console.warn("[vizu] StorageAdapter v1 detected. Per-comment ops are emulated via full-array rewrites \u2014 upgrade your adapter to the v2 interface (addComment / updateComment / removeComment / setAll / load / clear) when you can."))};return{async load(n){return t(),o.load(n)},async addComment(n,i){t();let r=await o.load(n);r.push(i),await o.save(n,r)},async updateComment(n,i,r){t();let s=await o.load(n),a=s.findIndex(c=>c.id===i);if(a===-1)return null;let l={...s[a],...r,id:s[a].id};return s[a]=l,await o.save(n,s),l},async removeComment(n,i){t();let r=await o.load(n);await o.save(n,r.filter(s=>s.id!==i))},async setAll(n,i){t(),await o.save(n,i)},async clear(n){await o.clear(n)}}}var Te="https://vizu.unhingged.com",oe=480,ae=640,L=class{constructor(e){this.cachedToken=null;this.pendingAuth=null;this.lastNotifiedTokenId=null;this.accessDenied=!1;this.accessDeniedReason=null;this.workspace=e.workspace,this.apiUrl=(e.apiUrl??Te).replace(/\/$/,""),this.autoSignIn=e.autoSignIn!==!1,this.onAuthChanged=e.onAuthChanged;let t=this.readHashToken();t?(this.cachedToken=t,this.writeStoredToken(t)):this.cachedToken=this.readStoredToken(),this.cachedToken&&!this.isExpired(this.cachedToken)&&this.fireAuthChanged(this.cachedToken)}readHashToken(){if(typeof window>"u")return null;let e=window.location.hash;if(!e||e.length<2)return null;let t=new URLSearchParams(e.slice(1)),n=t.get("vizu_auth");if(!n)return null;try{let i=Uint8Array.from(atob(n),p=>p.charCodeAt(0)),r=new TextDecoder("utf-8").decode(i),s=JSON.parse(r);if(!s.t||!s.e||!s.u||!s.w||s.w!==this.workspace)return null;let a={token:s.t,expiresAt:s.e,userId:s.u,user:typeof s.n=="string"?{id:s.u,name:s.n,avatarUrl:typeof s.a=="string"?s.a:void 0}:null};t.delete("vizu_auth");let l=t.toString(),c=l?`#${l}`:"";try{let p=window.location.pathname+window.location.search+c;window.history.replaceState(null,"",p)}catch{}return a}catch{return null}}async preflightAuth(){await this.resolveToken()}isAccessDenied(){return this.accessDenied}accessDenialReason(){return this.accessDeniedReason}async load(e){if(!this.cachedToken||this.isExpired(this.cachedToken)){let i=this.readStoredToken();if(!i||this.isExpired(i))return[];this.cachedToken=i}let t=[],n=null;do{let i=new URL(this.apiUrl+"/api/comments");i.searchParams.set("workspace",this.workspace),i.searchParams.set("limit","100"),n&&i.searchParams.set("cursor",n);let r=await this.fetchAuthed(i.toString(),{method:"GET"}),s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);let a=Array.isArray(s.comments)?s.comments:[];t.push(...k(a)),n=typeof s.nextCursor=="string"?s.nextCursor:null}while(n);return t}async addComment(e,t){let n=await this.fetchAuthed(this.apiUrl+"/api/comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({workspace:this.workspace,comment:t})}),i=await this.parseJson(n);if(!n.ok)throw x(n.status,i)}async updateComment(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);return C(s.comment)}async removeComment(e,t){let n=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));n.searchParams.set("workspace",this.workspace);let i=await this.fetchAuthed(n.toString(),{method:"DELETE"});if(i.status!==404&&!i.ok){let r=await this.parseJson(i);throw x(i.status,r)}}async setAll(e,t){await this.clear(e);for(let n of t)await this.addComment(e,n)}async clear(e){let t=new URL(this.apiUrl+"/api/comments");t.searchParams.set("workspace",this.workspace),t.searchParams.set("all","true");let n=await this.fetchAuthed(t.toString(),{method:"DELETE"});if(n.status!==404&&!n.ok){let i=await this.parseJson(n);throw x(n.status,i)}}async addReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);return s?.comment?C(s.comment):null}async removeReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies/"+encodeURIComponent(n));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"DELETE"});if(r.status===404)return null;if(!r.ok){let s=await this.parseJson(r);throw x(r.status,s)}return null}async uploadAttachment(e,t){let n=new FormData;n.append("file",t,t.name);let i=new URL(this.apiUrl+"/api/uploads");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",body:n}),s=await this.parseJson(r);if(!r.ok)throw x(r.status,s);if(!s?.url||typeof s.url!="string")throw x(500,{error:"upload_failed",message:"Backend did not return a URL."});return{id:F(),url:s.url,mimeType:t.type||"application/octet-stream",sizeBytes:t.size,uploadedAt:Date.now(),filename:t.name}}getAuthContext(){return this.cachedToken?{userId:this.cachedToken.userId,token:this.cachedToken.token,expiresAt:this.cachedToken.expiresAt}:null}isExpired(e){if(!e)return!0;let t=new Date(e.expiresAt).getTime();return!Number.isFinite(t)||t-Date.now()<3e4}readStoredToken(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.sessionKey());if(!e)return null;try{let t=JSON.parse(e);return this.isExpired(t)?(sessionStorage.removeItem(this.sessionKey()),null):t}catch{return null}}writeStoredToken(e){this.cachedToken=e,typeof sessionStorage<"u"&&sessionStorage.setItem(this.sessionKey(),JSON.stringify(e))}clearStoredToken(){this.cachedToken=null,typeof sessionStorage<"u"&&sessionStorage.removeItem(this.sessionKey())}sessionKey(){return`vizu:cloud-token:v2:${this.workspace}`}async resolveToken(){if(this.cachedToken&&!this.isExpired(this.cachedToken))return this.cachedToken;let e=this.readStoredToken();if(e)return this.cachedToken=e,this.fireAuthChanged(e),e;if(this.accessDenied)throw V("access_denied",`No access to workspace "${this.workspace}" (${this.accessDeniedReason??"no_access"}).`);if(!this.autoSignIn)throw V("auth_required","Sign-in required; autoSignIn is disabled.");return this.pendingAuth||(this.pendingAuth=this.openSignInPopup().then(t=>(this.writeStoredToken(t),this.fireAuthChanged(t),t)).finally(()=>{this.pendingAuth=null})),this.pendingAuth}fireAuthChanged(e){if(this.lastNotifiedTokenId!==e.token){this.lastNotifiedTokenId=e.token;try{this.onAuthChanged?.({userId:e.userId,user:e.user})}catch(t){typeof console<"u"&&console.warn("[vizu/cloud] onAuthChanged callback threw",t)}}}openSignInPopup(){return new Promise((e,t)=>{if(typeof window>"u")return t(V("auth_unavailable","Sign-in requires a browser environment."));let n=new URL(this.apiUrl).origin,i=window.location.origin,r=this.apiUrl+"/connect?workspace="+encodeURIComponent(this.workspace)+"&origin="+encodeURIComponent(i),s=Math.max(0,Math.round((window.screen.width-oe)/2)),a=Math.max(0,Math.round((window.screen.height-ae)/2)),l=window.open(r,"vizu-connect",`width=${oe},height=${ae},left=${s},top=${a},noopener=no,popup=yes`);if(!l)try{let v=window.location.href,f=this.apiUrl+"/connect?workspace="+encodeURIComponent(this.workspace)+"&origin="+encodeURIComponent(i)+"&return_to="+encodeURIComponent(v);window.location.assign(f);return}catch(v){return t(V("popup_blocked","Sign-in popup was blocked and redirect fallback failed: "+(v instanceof Error?v.message:String(v))))}let c=!1,p=v=>{if(v.origin!==n)return;let f=v.data;if(!f)return;if(f.type==="vizu:auth-denied"&&f.workspace===this.workspace){c=!0,$(),this.accessDenied=!0,this.accessDeniedReason=typeof f.reason=="string"?f.reason:"no_access",t(V("access_denied",`No access to workspace "${this.workspace}" (${this.accessDeniedReason}).`));return}if(f.type!=="vizu:auth"||f.workspace!==this.workspace||typeof f.token!="string"||typeof f.expiresAt!="string"||typeof f.userId!="string")return;c=!0,$();let b=f.user,u=b&&typeof b.name=="string"?{id:typeof b.id=="string"?b.id:f.userId,name:b.name,avatarUrl:typeof b.avatarUrl=="string"?b.avatarUrl:void 0}:null;e({token:f.token,expiresAt:f.expiresAt,userId:f.userId,user:u})},m=window.setInterval(()=>{l.closed&&(c||($(),t(V("auth_canceled","Sign-in popup was closed before completing."))))},500);function $(){window.clearInterval(m),window.removeEventListener("message",p)}window.addEventListener("message",p)})}async fetchAuthed(e,t,n=!1){let i=await this.resolveToken(),r=new Headers(t.headers);r.set("authorization",`Bearer ${i.token}`);let s=await fetch(e,{...t,headers:r,credentials:"omit"});return s.status===401&&!n?(this.clearStoredToken(),this.fetchAuthed(e,t,!0)):s}async parseJson(e){try{let t=await e.text();return t?JSON.parse(t):null}catch{return null}}};function V(o,e){let t=new Error(e);return t.code=o,t}function x(o,e){let t=e?.error==="origin_not_allowed"?"origin_not_allowed":e?.error==="not_found"?"workspace_not_found":"http_error",n=new Error(e?.message??`HTTP ${o}`);return n.code=t,n.status=o,n.body=e,n}function le(o){let e=[],t=o,n=0;for(;t&&t!==document.documentElement&&n<8;){let i=t.tagName.toLowerCase();if(t.id){e.unshift("#"+CSS.escape(t.id));break}let r=Array.from(t.classList).filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")).slice(0,2);r.length&&(i+="."+r.map(a=>CSS.escape(a)).join("."));let s=t.parentElement;if(s){let a=Array.from(s.children).filter(l=>l.tagName===t.tagName);if(a.length>1){let l=a.indexOf(t);i+=":nth-of-type("+(l+1)+")"}}e.unshift(i),t=s,n++}return e.join(" > ")}function _(o){let e=o.innerText||o.textContent||"",t=o.parentElement,n=0;return t&&(n=Array.from(t.children).indexOf(o)),{selector:le(o),parentSelector:t?le(t):"",tagName:o.tagName,textSnippet:e.trim().slice(0,80),siblingIndex:n,attributes:{id:o.id||void 0,classList:Array.from(o.classList).filter(i=>!i.startsWith("vz-")&&!i.startsWith("vizu-")),role:o.getAttribute("role")||void 0,ariaLabel:o.getAttribute("aria-label")||void 0,dataKey:o.getAttribute("data-vizu-key")||void 0},ancestorChain:Me(o,4),algorithmVersion:2}}function Me(o,e){let t=[],n=o.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t.length>0?{steps:t}:void 0}function j(o,e=document){if(o.attributes.dataKey){try{let s=e.querySelector(`[data-vizu-key="${CSS.escape(o.attributes.dataKey)}"]`);if(s)return{element:s,confidence:"exact"}}catch{}return{element:null,confidence:"orphaned"}}if(o.attributes.id)try{let s=e.querySelector("#"+CSS.escape(o.attributes.id));if(s)return{element:s,confidence:"exact"}}catch{}let t=[],n=o.attributes.classList;if(n&&n.length>0){let s=Ve(e,o.tagName,n);s?.element&&t.push({el:s.element,rung:"class"})}try{let s=e.querySelector(o.selector);s&&t.push({el:s,rung:"selector"})}catch{}if(o.ancestorChain&&o.ancestorChain.steps.length>0){let s=Le(e,o.tagName,o.ancestorChain.steps);s?.element&&t.push({el:s.element,rung:"chain"})}else try{let s=o.parentSelector?e.querySelector(o.parentSelector):e;if(s){let a=s.children[o.siblingIndex];a&&a.tagName===o.tagName&&t.push({el:a,rung:"chain"})}}catch{}if(o.textSnippet){let s=Pe(e,o.tagName,o.textSnippet);s?.element&&t.push({el:s.element,rung:"text"})}if(t.length===0)return{element:null,confidence:"orphaned"};let i=new Map;for(let s of t){let a=i.get(s.el);a||(a=new Set,i.set(s.el,a)),a.add(s.rung)}let r=null;for(let[s,a]of i)(!r||a.size>r.rungs.size)&&(r={el:s,rungs:a});return r?r.rungs.size>=3?{element:r.el,confidence:"likely"}:r.rungs.size>=2?{element:r.el,confidence:"drifted"}:r.rungs.has("class")||r.rungs.has("chain")?{element:r.el,confidence:"drifted"}:{element:null,confidence:"orphaned"}:{element:null,confidence:"orphaned"}}function Ve(o,e,t){let n=new Set(t.filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")));if(n.size===0)return null;let i=o.querySelectorAll(e.toLowerCase()),r=null,s=0;for(let a of i){let l=new Set(Array.from(a.classList).filter(p=>!p.startsWith("vz-")&&!p.startsWith("vizu-")));if(l.size===0)continue;let c=Ue(n,l);c<.6||(!r||c>r.score?(s=r?.score??0,r={el:a,score:c}):c>s&&(s=c))}return!r||r.score-s<.1?null:{element:r.el,confidence:"likely"}}function Le(o,e,t){let n=o.querySelectorAll(e.toLowerCase()),i=null;for(let r of n){let s=Re(r,t.length+3),a=He(s,t,3);a<2||(!i||a>i.score)&&(i={el:r,score:a})}return i?{element:i.el,confidence:i.score===t.length?"likely":"drifted"}:null}function Re(o,e){let t=[],n=o.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t}function Pe(o,e,t){let n=ce(t);if(!n)return null;let i=o.querySelectorAll(e.toLowerCase()),r=null;for(let s of i){let a=s.innerText||s.textContent||"",l=ce(a.slice(0,160));if(!l)continue;let c=$e(n,l);c<.75||(!r||c>r.score)&&(r={el:s,score:c})}return r?{element:r.el,confidence:"drifted"}:null}function ce(o){return o.toLowerCase().replace(/\s+/g," ").trim()}function $e(o,e){if(o===e)return 1;if(o.length===0||e.length===0)return o.length===e.length?1:0;let t=Math.max(o.length,e.length);return 1-Fe(o,e)/t}function Fe(o,e){if(o.length>e.length){let i=o;o=e,e=i}let t=new Array(o.length+1),n=new Array(o.length+1);for(let i=0;i<=o.length;i++)t[i]=i;for(let i=1;i<=e.length;i++){n[0]=i;for(let r=1;r<=o.length;r++){let s=o.charCodeAt(r-1)===e.charCodeAt(i-1)?0:1;n[r]=Math.min(n[r-1]+1,t[r]+1,t[r-1]+s)}for(let r=0;r<=o.length;r++)t[r]=n[r]}return t[o.length]}function He(o,e,t){let n=0;for(let i=0;i<=t;i++){let r=0;for(let s=0;s<e.length;s++){let a=o[s+i];if(!a)break;a.tag===e[s].tag&&a.nthOfType===e[s].nthOfType&&r++}r>n&&(n=r)}return n}function Ue(o,e){if(o.size===0&&e.size===0)return 1;let t=0;for(let i of o)e.has(i)&&t++;let n=o.size+e.size-t;return n===0?0:t/n}function R(o,e){return j(o,e).element}function h(o){return o.selector+"|"+o.textSnippet}function P(o){let e=o.tagName.toLowerCase();if(o.textSnippet){let t=o.textSnippet.length>24?o.textSnippet.slice(0,24)+"\u2026":o.textSnippet;return e+": "+t}return o.attributes.id?e+"#"+o.attributes.id:o.attributes.classList&&o.attributes.classList.length?e+"."+o.attributes.classList[0]:e}var Ie="[data-vizu-root], [data-vizu-ignore], script, style, link, meta, head",q=class{constructor(e,t,n){this.current=null;this.active=!1;this.paused=!1;this.handleMove=e=>{if(this.paused){this.setCurrent(null),this.overlay.style.display="none";return}let t=document.elementFromPoint(e.clientX,e.clientY);if(!(!t||t===this.current)){if(this.shouldIgnore(t)){this.setCurrent(null),this.overlay.style.display="none";return}this.setCurrent(t),this.updateOverlay()}};this.handleClick=e=>{let t=document.elementFromPoint(e.clientX,e.clientY);t&&(this.shouldIgnore(t)||(e.preventDefault(),e.stopPropagation(),this.onClick(t,e)))};this.handleScroll=()=>{this.current&&this.updateOverlay()};this.root=e,this.extraIgnore=t,this.onClick=n,this.overlay=document.createElement("div"),this.overlay.className="vz-highlight",this.overlay.style.display="none",this.root.appendChild(this.overlay)}setCurrent(e){this.current!==e&&(this.current=e)}start(){this.active||(this.active=!0,document.addEventListener("mousemove",this.handleMove,!0),document.addEventListener("click",this.handleClick,!0),document.addEventListener("scroll",this.handleScroll,!0),window.addEventListener("resize",this.handleScroll))}stop(){this.active&&(this.active=!1,document.removeEventListener("mousemove",this.handleMove,!0),document.removeEventListener("click",this.handleClick,!0),document.removeEventListener("scroll",this.handleScroll,!0),window.removeEventListener("resize",this.handleScroll),this.overlay.style.display="none",this.setCurrent(null))}shouldIgnore(e){if(e===document.documentElement||e===document.body||Y(e,Ie))return!0;for(let t of this.extraIgnore)try{if(Y(e,t))return!0}catch{}return!1}setPaused(e){this.paused=e,e&&(this.setCurrent(null),this.overlay.style.display="none")}isPaused(){return this.paused}updateOverlay(){if(!this.current)return;let e=this.current.getBoundingClientRect();if(e.width===0||e.height===0){this.overlay.style.display="none";return}this.overlay.style.display="block",this.overlay.style.left=e.left+"px",this.overlay.style.top=e.top+"px",this.overlay.style.width=e.width+"px",this.overlay.style.height=e.height+"px"}destroy(){this.stop(),this.overlay.remove()}};function de(o){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(o):o.replace(/["\\]/g,"\\$&")}function Oe(o){let t=(o.replies??[]).map(n=>`
11
11
  <div class="vz-reply" data-reply-id="${d(n.id)}">
12
12
  ${n.author?`<div class="vz-comment-author">${z(n.author)} <span class="vz-comment-author-name">${d(n.author.name)}</span></div>`:""}
13
13
  <div class="vz-reply-text">${d(n.text)}</div>
@@ -1089,11 +1089,11 @@
1089
1089
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
1090
1090
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
1091
1091
  }
1092
- `;function pe(){if(typeof document>"u"||document.getElementById("vizu-styles"))return;let o=document.createElement("style");o.id="vizu-styles",o.textContent=qe,(document.head||document.documentElement).appendChild(o)}function me(o){let e=o.toLowerCase().split("+").map(n=>n.trim());return{key:e.pop()||"",mod:e.includes("mod")||e.includes("cmdorctrl"),shift:e.includes("shift"),alt:e.includes("alt")||e.includes("option"),ctrl:e.includes("ctrl")||e.includes("control")}}function ue(o,e){let t=typeof navigator<"u"&&/Mac|iPhone|iPad/.test(navigator.platform);if(o.key.toLowerCase()!==e.key)return!1;if(e.mod){if(!(t?o.metaKey:o.ctrlKey))return!1}else if(e.ctrl&&!o.ctrlKey)return!1;return!(e.shift!==o.shiftKey||e.alt!==o.altKey)}var W=class{constructor(){this.listeners=new Map}on(e,t){let n=this.listeners.get(e);return n||(n=new Set,this.listeners.set(e,n)),n.add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){let n=this.listeners.get(e);if(n)for(let i of[...n])try{i(t)}catch(r){console.error("[vizu] event handler error for",e,r)}}clear(){this.listeners.clear()}};var Q={shortcut:"mod+shift+e",namespace:"default",accent:"#FF6647"};function Be(o,e,t,n){return e?(o&&typeof console<"u"&&console.warn("[vizu] Both `cloud` and `storage` set; `cloud` wins. Drop `storage` to silence this."),new R({workspace:e.workspace,apiUrl:e.apiUrl,autoSignIn:e.autoSignIn,onAuthChanged:n})):o?o==="local"?new I:o==="memory"?new O:o==="none"?new N:G(o)?se(o):o:t==="local"?new I:new O}var A=class{constructor(e={},t="memory"){this.root=null;this.highlighter=null;this.popover=null;this.pill=null;this.sidebar=null;this.markers=new Map;this.outlines=new Map;this.activeAnchorOutlines=new Map;this.spotlights=new Set;this.comments=[];this.resolvedConfidence=new Map;this.selfHealedThisSession=new Set;this.actions=[];this.user=null;this.enabled=!1;this.rafScheduled=!1;this.bus=new W;this.picking=null;this.pickingBanner=null;this.multiSelectMode=!1;this.pendingFingerprints=[];this.pendingTargets=[];this.unsubscribeStorage=null;this.onKeyDown=e=>{if(this.picking&&e.key==="Escape"){e.preventDefault(),this.cancelPicking();return}if(this.pendingFingerprints.length>0&&e.key==="Escape"&&!this.popover?.isOpen()){e.preventDefault(),this.clearSelection();return}if(ue(e,this.parsedShortcut)){e.preventDefault();let t=this.enabled;this.toggle(),!t&&this.enabled&&this.storage instanceof R&&this.storage.preflightAuth().catch(n=>{n?.code==="auth_canceled"||n?.code==="popup_blocked"||typeof console<"u"&&console.warn("[vizu] preflight auth failed:",n)})}};this.scheduleReposition=()=>{this.rafScheduled||(this.rafScheduled=!0,requestAnimationFrame(()=>{this.rafScheduled=!1;for(let[,e]of this.outlines)e.target&&this.positionOutline(e.outline,e.target);for(let[,e]of this.markers)e.target&&this.positionMarker(e.marker,e.target);for(let[,e]of this.activeAnchorOutlines){let t=L(e.fp);t&&this.positionOutline(e.el,t)}for(let e of this.spotlights)e.target&&this.positionOutline(e.el,e.target);this.popover?.reposition()}))};this.opts={...e},this.opts.shortcut=e.shortcut??Q.shortcut,this.opts.namespace=e.namespace??Q.namespace,this.opts.accent=e.accent??Q.accent,this.parsedShortcut=me(this.opts.shortcut),this.storage=Be(e.storage,e.cloud,t,n=>{n.user&&this.setUser(n.user)}),this.user=e.user??null,e.actions&&(this.actions=[...e.actions]),e.onCommentAdded&&this.bus.on("comment:added",n=>e.onCommentAdded(n.comment)),e.onCommentRemoved&&this.bus.on("comment:removed",n=>e.onCommentRemoved(n.id)),typeof window<"u"&&(window.addEventListener("keydown",this.onKeyDown),this.loadComments().then(()=>this.subscribeStorage()),e.startEnabled&&this.deferred(()=>this.enable()))}on(e,t){return this.bus.on(e,t)}off(e,t){this.bus.off(e,t)}setUser(e){this.user=e,this.popover?.setUser(e),this.pill?.setUser(e),this.bus.emit("user:changed",{user:e})}getUser(){return this.user}requireUserOrAuth(){return!(this.storage instanceof R)||this.user?!0:(this.storage.isAccessDenied()||this.storage.preflightAuth().catch(()=>{}),!1)}enable(){this.enabled||(this.enabled=!0,this.bus.emit("enabled",{}),this.deferred(()=>this.mount()))}disable(){this.enabled&&(this.enabled=!1,this.unmount(),this.bus.emit("disabled",{}))}toggle(){this.enabled?this.disable():this.enable()}isEnabled(){return this.enabled}destroy(){this.disable(),typeof window<"u"&&window.removeEventListener("keydown",this.onKeyDown),this.unsubscribeStorage?.(),this.unsubscribeStorage=null,this.selfHealedThisSession.clear(),this.bus.clear()}addAction(e){let t=this.actions.findIndex(n=>n.id===e.id);t>=0?this.actions[t]=e:this.actions.push(e),this.pill?.setActions(this.actions)}removeAction(e){this.actions=this.actions.filter(t=>t.id!==e),this.pill?.setActions(this.actions)}getActions(){return[...this.actions]}invokeAction(e){let t=this.actions.find(i=>i.id===e);if(!t)return;let n=this.actionContext();this.bus.emit("action:invoked",{id:e}),t.onClick(n)}getComments(){return[...this.comments]}async setComments(e,t){this.comments=k(e),t?.persist!==!1&&await this.storage.setAll(this.opts.namespace,this.comments),this.bus.emit("comments:set",{comments:this.getComments()}),this.refreshUi()}async updateComment(e,t){let n=this.comments.findIndex(c=>c.id===e);if(n===-1)return null;let{id:i,schemaVersion:r,...s}=t,a={...this.comments[n],...s};this.comments[n]=a;let l=await this.storage.updateComment(this.opts.namespace,e,s);return this.bus.emit("comment:updated",{comment:l??a}),this.refreshUi(),a}getAuthContext(){return this.storage.getAuthContext?.()??null}async selfHealComment(e,t){this.selfHealedThisSession.add(e.id);let n=[],i=!1;for(let a of e.fingerprints||[]){let l=t.get(h(a));if(l?.target){let c=_(l.target);n.push(c),!i&&h(c)!==h(a)&&(i=!0)}else n.push(a)}if(!i)return;let r={fingerprints:n,fingerprintsRefreshedAt:Date.now()},s=this.comments.findIndex(a=>a.id===e.id);s!==-1&&(this.comments[s]={...this.comments[s],...r});try{await this.storage.updateComment(this.opts.namespace,e.id,r)}catch(a){typeof console<"u"&&console.warn("[vizu] self-heal write failed for",e.id,a)}}getCommentConfidence(e){return this.resolvedConfidence.get(e)}getResolvedConfidence(){return new Map(this.resolvedConfidence)}canUploadAttachments(){return typeof this.storage.uploadAttachment=="function"}async uploadAttachment(e){if(!this.storage.uploadAttachment)throw new Error("[vizu] active storage adapter does not support uploadAttachment; only the CloudStorageAdapter does in v1");return this.storage.uploadAttachment(this.opts.namespace,e)}async addReply(e,t,n){if(!this.requireUserOrAuth())return null;let i=this.comments.findIndex(a=>a.id===e);if(i===-1)return null;let r={id:F(),text:t.trim(),createdAt:Date.now(),author:this.user??void 0,authorId:this.user?.id,mentions:n&&n.length?n:void 0};if(!r.text)return null;let s={...this.comments[i],replies:[...this.comments[i].replies??[],r]};if(this.comments[i]=s,this.storage.addReply?await this.storage.addReply(this.opts.namespace,e,r):await this.storage.updateComment(this.opts.namespace,e,{replies:s.replies}),this.bus.emit("comment:updated",{comment:s}),this.refreshUi(),this.popover?.isOpen()){let a=this.popover.getAnchors();a[0]&&this.popover.update(this.commentsForElement(a[0]))}return s}async removeReply(e,t){let n=this.comments.findIndex(s=>s.id===e);if(n===-1)return null;let i=(this.comments[n].replies??[]).filter(s=>s.id!==t);if(i.length===(this.comments[n].replies??[]).length)return null;let r={...this.comments[n],replies:i};if(this.comments[n]=r,this.storage.removeReply?await this.storage.removeReply(this.opts.namespace,e,t):await this.storage.updateComment(this.opts.namespace,e,{replies:i}),this.bus.emit("comment:updated",{comment:r}),this.refreshUi(),this.popover?.isOpen()){let s=this.popover.getAnchors();s[0]&&this.popover.update(this.commentsForElement(s[0]))}return r}async clearAll(){let e=this.comments;this.comments=[],await this.storage.clear(this.opts.namespace),this.bus.emit("comments:cleared",{previous:e}),this.refreshUi(),this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1)}toggleMultiSelectMode(){this.requireUserOrAuth()&&(this.multiSelectMode=!this.multiSelectMode,this.multiSelectMode||this.clearSelection(),this.pill?.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length))}clearSelection(){this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.clearActiveAnchorOutlines(),this.pill?.setMultiSelectState(!1,0)}commitSelection(){if(this.pendingFingerprints.length===0)return;let e=[...this.pendingTargets],t=[...this.pendingFingerprints];this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.pill?.setMultiSelectState(!1,0),(e.find(i=>!!i)??L(t[0]))&&this.openPopoverFor(e.filter(Boolean),t)}getSelection(){return[...this.pendingFingerprints]}async loadComments(){let e=await this.storage.load(this.opts.namespace);this.comments=k(e),re(e)&&this.storage.setAll(this.opts.namespace,this.comments).catch(()=>{}),this.bus.emit("comments:loaded",{comments:this.getComments()}),this.enabled&&this.refreshUi()}subscribeStorage(){this.unsubscribeStorage||this.storage.subscribe&&(this.unsubscribeStorage=this.storage.subscribe(this.opts.namespace,e=>{if(e.type==="added"){let t=C(e.comment);this.comments.some(n=>n.id===t.id)||(this.comments.push(t),this.bus.emit("comment:added",{comment:t}),this.refreshUi())}else if(e.type==="updated"){let t=this.comments.findIndex(i=>i.id===e.comment.id),n=C(e.comment);t>=0&&(this.comments[t]=n,this.bus.emit("comment:updated",{comment:n}),this.refreshUi())}else if(e.type==="removed"){let t=this.comments.findIndex(n=>n.id===e.id);if(t>=0){let[n]=this.comments.splice(t,1);this.bus.emit("comment:removed",{id:e.id,comment:n}),this.refreshUi()}}else if(e.type==="cleared"){let t=this.comments;this.comments=[],this.bus.emit("comments:cleared",{previous:t}),this.refreshUi()}}))}deferred(e){typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e,{once:!0}):e())}mount(){this.root||(pe(),this.root=document.createElement("div"),this.root.setAttribute("data-vizu-root",""),this.root.style.setProperty("--vz-accent",this.opts.accent),document.body.appendChild(this.root),this.popover=new B(this.root,{onAdd:(e,t,n,i,r)=>{this.addCommentFromPopover(e,t,n,i,r)},onUploadAttachment:e=>this.uploadAttachment(e),canUploadAttachments:()=>this.canUploadAttachments(),onDelete:e=>{this.removeComment(e)},onAddReply:(e,t)=>{this.addReply(e,t)},onDeleteReply:(e,t)=>{this.removeReply(e,t)},onClose:()=>this.closePopover(),onStartReferencePick:(e,t)=>this.startPicking(e,t),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onAnchorsChanged:e=>this.syncActiveAnchorOutlines(e)}),this.popover.setUser(this.user),this.sidebar=new J(this.root,{onJumpTo:e=>this.jumpToFingerprint(e),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onDelete:e=>{this.removeComment(e)},onUpdateStatus:(e,t)=>{this.updateComment(e,{status:t})},onClose:()=>this.closeSidebar()}),this.pill=new K(this.root,{onToggleSidebar:()=>this.toggleSidebar(),onDisable:()=>this.disable(),onAction:e=>this.invokeAction(e),onToggleMultiSelect:()=>this.toggleMultiSelectMode(),onCommitSelection:()=>this.commitSelection(),onClearSelection:()=>this.clearSelection()}),this.pill.setActions(this.actions),this.pill.setUser(this.user),this.pill.setComments(this.comments),this.pill.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length),this.pill.show(),this.highlighter=new q(this.root,this.opts.ignoreSelectors??[],(e,t)=>this.onElementClick(e,t)),this.highlighter.start(),this.renderAllMarkers(),window.addEventListener("scroll",this.scheduleReposition,!0),window.addEventListener("resize",this.scheduleReposition),this.bus.emit("mounted",{}))}unmount(){window.removeEventListener("scroll",this.scheduleReposition,!0),window.removeEventListener("resize",this.scheduleReposition),this.highlighter?.destroy(),this.popover?.destroy(),this.pill?.destroy(),this.sidebar?.destroy(),this.root?.remove(),this.root=null,this.highlighter=null,this.popover=null,this.pill=null,this.sidebar=null,this.markers.clear(),this.outlines.clear(),this.activeAnchorOutlines.clear();for(let e of this.spotlights)e.el.remove();this.spotlights.clear(),this.pendingFingerprints=[],this.pendingTargets=[],this.bus.emit("unmounted",{})}onElementClick(e,t){if(this.picking){let r=_(e),s=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),s.onSelect(r);return}if(!this.requireUserOrAuth())return;let n=_(e);if(this.popover?.isOpen()&&t.shiftKey){this.popover.addAnchor(n,e);return}if(!this.popover?.isOpen()&&(this.multiSelectMode||t.shiftKey)){this.addToSelection(n,e);return}this.bus.emit("element:selected",{target:e,fingerprint:n});let i=this.commentsForElement(n);this.openPopoverFor([e],[n],i)}openPopoverFor(e,t,n){if(!this.popover)return;let i=n??this.commentsForElement(t[0]);this.popover.open(e,t,i),this.syncActiveAnchorOutlines(t),this.highlighter?.setPaused(!0)}closePopover(){this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1),this.bus.emit("element:deselected",{})}addToSelection(e,t){let n=h(e);this.pendingFingerprints.some(i=>h(i)===n)?(this.pendingFingerprints=this.pendingFingerprints.filter(i=>h(i)!==n),this.pendingTargets=this.pendingTargets.filter(i=>i!==t)):(this.pendingFingerprints.push(e),this.pendingTargets.push(t)),this.syncActiveAnchorOutlines(this.pendingFingerprints),this.pill?.setMultiSelectState(!0,this.pendingFingerprints.length),this.pendingFingerprints.length>0?this.multiSelectMode=!0:this.multiSelectMode=!1}commentsForElement(e){let t=h(e);return this.comments.filter(n=>(n.fingerprints||[]).some(i=>h(i)===t))}async addCommentFromPopover(e,t,n,i,r){if(!this.requireUserOrAuth()||t.length===0)return;let s=typeof location<"u"?location.href:void 0,a={id:F(),schemaVersion:2,fingerprints:t,text:e,createdAt:Date.now(),pageVersion:this.opts.pageVersion,pageUrl:s,author:this.user??void 0,authorId:this.user?.id,references:n&&Object.keys(n).length?n:void 0,status:"open",replies:[],attachments:r??[],mentions:i??[]};this.comments.push(a),await this.storage.addComment(this.opts.namespace,a),this.bus.emit("comment:added",{comment:a}),this.popover?.update(this.commentsForElement(t[0])),this.refreshUi()}async removeComment(e){let t=this.comments.find(n=>n.id===e);if(t){if(this.comments=this.comments.filter(n=>n.id!==e),await this.storage.removeComment(this.opts.namespace,e),this.bus.emit("comment:removed",{id:e,comment:t}),this.popover?.isOpen()){let n=this.popover.getAnchors();n[0]&&this.popover.update(this.commentsForElement(n[0]))}this.refreshUi()}}refreshUi(){this.pill?.setComments(this.comments),this.renderAllMarkers(),this.sidebar?.update(this.comments,this.resolvedConfidence)}toggleSidebar(){if(!this.sidebar)return;this.sidebar.isOpen()||this.renderAllMarkers(),this.sidebar.toggle(this.comments,this.resolvedConfidence);let e=this.sidebar.isOpen();this.pill?.setSidebarOpen(e),this.bus.emit(e?"sidebar:opened":"sidebar:closed",{})}closeSidebar(){this.sidebar?.close(),this.pill?.setSidebarOpen(!1),this.bus.emit("sidebar:closed",{})}startPicking(e,t){this.picking&&this.picking.onCancel(),this.picking={onSelect:e,onCancel:t},this.highlighter?.setPaused(!1),this.showPickingBanner()}cancelPicking(){if(!this.picking)return;let e=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),e.onCancel()}showPickingBanner(){this.root&&(this.pickingBanner=document.createElement("div"),this.pickingBanner.className="vz-picking-banner",this.pickingBanner.innerHTML=`
1092
+ `;function pe(){if(typeof document>"u"||document.getElementById("vizu-styles"))return;let o=document.createElement("style");o.id="vizu-styles",o.textContent=qe,(document.head||document.documentElement).appendChild(o)}function me(o){let e=o.toLowerCase().split("+").map(n=>n.trim());return{key:e.pop()||"",mod:e.includes("mod")||e.includes("cmdorctrl"),shift:e.includes("shift"),alt:e.includes("alt")||e.includes("option"),ctrl:e.includes("ctrl")||e.includes("control")}}function ue(o,e){let t=typeof navigator<"u"&&/Mac|iPhone|iPad/.test(navigator.platform);if(o.key.toLowerCase()!==e.key)return!1;if(e.mod){if(!(t?o.metaKey:o.ctrlKey))return!1}else if(e.ctrl&&!o.ctrlKey)return!1;return!(e.shift!==o.shiftKey||e.alt!==o.altKey)}var W=class{constructor(){this.listeners=new Map}on(e,t){let n=this.listeners.get(e);return n||(n=new Set,this.listeners.set(e,n)),n.add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){let n=this.listeners.get(e);if(n)for(let i of[...n])try{i(t)}catch(r){console.error("[vizu] event handler error for",e,r)}}clear(){this.listeners.clear()}};var Q={shortcut:"mod+shift+e",namespace:"default",accent:"#FF6647"};function Be(o,e,t,n){return e?(o&&typeof console<"u"&&console.warn("[vizu] Both `cloud` and `storage` set; `cloud` wins. Drop `storage` to silence this."),new L({workspace:e.workspace,apiUrl:e.apiUrl,autoSignIn:e.autoSignIn,onAuthChanged:n})):o?o==="local"?new I:o==="memory"?new O:o==="none"?new N:G(o)?se(o):o:t==="local"?new I:new O}var A=class{constructor(e={},t="memory"){this.root=null;this.highlighter=null;this.popover=null;this.pill=null;this.sidebar=null;this.markers=new Map;this.outlines=new Map;this.activeAnchorOutlines=new Map;this.spotlights=new Set;this.comments=[];this.resolvedConfidence=new Map;this.selfHealedThisSession=new Set;this.actions=[];this.user=null;this.hasLoadedComments=!1;this.enabled=!1;this.rafScheduled=!1;this.bus=new W;this.picking=null;this.pickingBanner=null;this.multiSelectMode=!1;this.pendingFingerprints=[];this.pendingTargets=[];this.unsubscribeStorage=null;this.onKeyDown=e=>{if(this.picking&&e.key==="Escape"){e.preventDefault(),this.cancelPicking();return}if(this.pendingFingerprints.length>0&&e.key==="Escape"&&!this.popover?.isOpen()){e.preventDefault(),this.clearSelection();return}if(ue(e,this.parsedShortcut)){e.preventDefault();let t=this.enabled;this.toggle(),!t&&this.enabled&&this.storage instanceof L&&this.storage.preflightAuth().catch(n=>{n?.code==="auth_canceled"||n?.code==="popup_blocked"||typeof console<"u"&&console.warn("[vizu] preflight auth failed:",n)})}};this.scheduleReposition=()=>{this.rafScheduled||(this.rafScheduled=!0,requestAnimationFrame(()=>{this.rafScheduled=!1;for(let[,e]of this.outlines)e.target&&this.positionOutline(e.outline,e.target);for(let[,e]of this.markers)e.target&&this.positionMarker(e.marker,e.target);for(let[,e]of this.activeAnchorOutlines){let t=R(e.fp);t&&this.positionOutline(e.el,t)}for(let e of this.spotlights)e.target&&this.positionOutline(e.el,e.target);this.popover?.reposition()}))};this.opts={...e},this.opts.shortcut=e.shortcut??Q.shortcut,this.opts.namespace=e.namespace??Q.namespace,this.opts.accent=e.accent??Q.accent,this.parsedShortcut=me(this.opts.shortcut),this.user=e.user??null,this.storage=Be(e.storage,e.cloud,t,n=>{n.user&&this.setUser(n.user),this.hasLoadedComments&&this.loadComments()}),e.actions&&(this.actions=[...e.actions]),e.onCommentAdded&&this.bus.on("comment:added",n=>e.onCommentAdded(n.comment)),e.onCommentRemoved&&this.bus.on("comment:removed",n=>e.onCommentRemoved(n.id)),typeof window<"u"&&(window.addEventListener("keydown",this.onKeyDown),this.loadComments().catch(()=>{}).finally(()=>{this.hasLoadedComments=!0,this.subscribeStorage()}),e.startEnabled&&this.deferred(()=>this.enable()))}on(e,t){return this.bus.on(e,t)}off(e,t){this.bus.off(e,t)}setUser(e){this.user=e,this.popover?.setUser(e),this.pill?.setUser(e),this.bus.emit("user:changed",{user:e})}getUser(){return this.user}requireUserOrAuth(){return!(this.storage instanceof L)||this.user?!0:(this.storage.isAccessDenied()||this.storage.preflightAuth().catch(()=>{}),!1)}enable(){this.enabled||(this.enabled=!0,this.bus.emit("enabled",{}),this.deferred(()=>this.mount()))}disable(){this.enabled&&(this.enabled=!1,this.unmount(),this.bus.emit("disabled",{}))}toggle(){this.enabled?this.disable():this.enable()}isEnabled(){return this.enabled}destroy(){this.disable(),typeof window<"u"&&window.removeEventListener("keydown",this.onKeyDown),this.unsubscribeStorage?.(),this.unsubscribeStorage=null,this.selfHealedThisSession.clear(),this.bus.clear()}addAction(e){let t=this.actions.findIndex(n=>n.id===e.id);t>=0?this.actions[t]=e:this.actions.push(e),this.pill?.setActions(this.actions)}removeAction(e){this.actions=this.actions.filter(t=>t.id!==e),this.pill?.setActions(this.actions)}getActions(){return[...this.actions]}invokeAction(e){let t=this.actions.find(i=>i.id===e);if(!t)return;let n=this.actionContext();this.bus.emit("action:invoked",{id:e}),t.onClick(n)}getComments(){return[...this.comments]}async setComments(e,t){this.comments=k(e),t?.persist!==!1&&await this.storage.setAll(this.opts.namespace,this.comments),this.bus.emit("comments:set",{comments:this.getComments()}),this.refreshUi()}async updateComment(e,t){let n=this.comments.findIndex(c=>c.id===e);if(n===-1)return null;let{id:i,schemaVersion:r,...s}=t,a={...this.comments[n],...s};this.comments[n]=a;let l=await this.storage.updateComment(this.opts.namespace,e,s);return this.bus.emit("comment:updated",{comment:l??a}),this.refreshUi(),a}getAuthContext(){return this.storage.getAuthContext?.()??null}async selfHealComment(e,t){this.selfHealedThisSession.add(e.id);let n=[],i=!1;for(let a of e.fingerprints||[]){let l=t.get(h(a));if(l?.target){let c=_(l.target);n.push(c),!i&&h(c)!==h(a)&&(i=!0)}else n.push(a)}if(!i)return;let r={fingerprints:n,fingerprintsRefreshedAt:Date.now()},s=this.comments.findIndex(a=>a.id===e.id);s!==-1&&(this.comments[s]={...this.comments[s],...r});try{await this.storage.updateComment(this.opts.namespace,e.id,r)}catch(a){typeof console<"u"&&console.warn("[vizu] self-heal write failed for",e.id,a)}}getCommentConfidence(e){return this.resolvedConfidence.get(e)}getResolvedConfidence(){return new Map(this.resolvedConfidence)}canUploadAttachments(){return typeof this.storage.uploadAttachment=="function"}async uploadAttachment(e){if(!this.storage.uploadAttachment)throw new Error("[vizu] active storage adapter does not support uploadAttachment; only the CloudStorageAdapter does in v1");return this.storage.uploadAttachment(this.opts.namespace,e)}async addReply(e,t,n){if(!this.requireUserOrAuth())return null;let i=this.comments.findIndex(a=>a.id===e);if(i===-1)return null;let r={id:F(),text:t.trim(),createdAt:Date.now(),author:this.user??void 0,authorId:this.user?.id,mentions:n&&n.length?n:void 0};if(!r.text)return null;let s={...this.comments[i],replies:[...this.comments[i].replies??[],r]};if(this.comments[i]=s,this.storage.addReply?await this.storage.addReply(this.opts.namespace,e,r):await this.storage.updateComment(this.opts.namespace,e,{replies:s.replies}),this.bus.emit("comment:updated",{comment:s}),this.refreshUi(),this.popover?.isOpen()){let a=this.popover.getAnchors();a[0]&&this.popover.update(this.commentsForElement(a[0]))}return s}async removeReply(e,t){let n=this.comments.findIndex(s=>s.id===e);if(n===-1)return null;let i=(this.comments[n].replies??[]).filter(s=>s.id!==t);if(i.length===(this.comments[n].replies??[]).length)return null;let r={...this.comments[n],replies:i};if(this.comments[n]=r,this.storage.removeReply?await this.storage.removeReply(this.opts.namespace,e,t):await this.storage.updateComment(this.opts.namespace,e,{replies:i}),this.bus.emit("comment:updated",{comment:r}),this.refreshUi(),this.popover?.isOpen()){let s=this.popover.getAnchors();s[0]&&this.popover.update(this.commentsForElement(s[0]))}return r}async clearAll(){let e=this.comments;this.comments=[],await this.storage.clear(this.opts.namespace),this.bus.emit("comments:cleared",{previous:e}),this.refreshUi(),this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1)}toggleMultiSelectMode(){this.requireUserOrAuth()&&(this.multiSelectMode=!this.multiSelectMode,this.multiSelectMode||this.clearSelection(),this.pill?.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length))}clearSelection(){this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.clearActiveAnchorOutlines(),this.pill?.setMultiSelectState(!1,0)}commitSelection(){if(this.pendingFingerprints.length===0)return;let e=[...this.pendingTargets],t=[...this.pendingFingerprints];this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.pill?.setMultiSelectState(!1,0),(e.find(i=>!!i)??R(t[0]))&&this.openPopoverFor(e.filter(Boolean),t)}getSelection(){return[...this.pendingFingerprints]}async loadComments(){let e=await this.storage.load(this.opts.namespace);this.comments=k(e),re(e)&&this.storage.setAll(this.opts.namespace,this.comments).catch(()=>{}),this.bus.emit("comments:loaded",{comments:this.getComments()}),this.enabled&&this.refreshUi()}subscribeStorage(){this.unsubscribeStorage||this.storage.subscribe&&(this.unsubscribeStorage=this.storage.subscribe(this.opts.namespace,e=>{if(e.type==="added"){let t=C(e.comment);this.comments.some(n=>n.id===t.id)||(this.comments.push(t),this.bus.emit("comment:added",{comment:t}),this.refreshUi())}else if(e.type==="updated"){let t=this.comments.findIndex(i=>i.id===e.comment.id),n=C(e.comment);t>=0&&(this.comments[t]=n,this.bus.emit("comment:updated",{comment:n}),this.refreshUi())}else if(e.type==="removed"){let t=this.comments.findIndex(n=>n.id===e.id);if(t>=0){let[n]=this.comments.splice(t,1);this.bus.emit("comment:removed",{id:e.id,comment:n}),this.refreshUi()}}else if(e.type==="cleared"){let t=this.comments;this.comments=[],this.bus.emit("comments:cleared",{previous:t}),this.refreshUi()}}))}deferred(e){typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e,{once:!0}):e())}mount(){this.root||(pe(),this.root=document.createElement("div"),this.root.setAttribute("data-vizu-root",""),this.root.style.setProperty("--vz-accent",this.opts.accent),document.body.appendChild(this.root),this.popover=new B(this.root,{onAdd:(e,t,n,i,r)=>{this.addCommentFromPopover(e,t,n,i,r)},onUploadAttachment:e=>this.uploadAttachment(e),canUploadAttachments:()=>this.canUploadAttachments(),onDelete:e=>{this.removeComment(e)},onAddReply:(e,t)=>{this.addReply(e,t)},onDeleteReply:(e,t)=>{this.removeReply(e,t)},onClose:()=>this.closePopover(),onStartReferencePick:(e,t)=>this.startPicking(e,t),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onAnchorsChanged:e=>this.syncActiveAnchorOutlines(e)}),this.popover.setUser(this.user),this.sidebar=new J(this.root,{onJumpTo:e=>this.jumpToFingerprint(e),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onDelete:e=>{this.removeComment(e)},onUpdateStatus:(e,t)=>{this.updateComment(e,{status:t})},onClose:()=>this.closeSidebar()}),this.pill=new K(this.root,{onToggleSidebar:()=>this.toggleSidebar(),onDisable:()=>this.disable(),onAction:e=>this.invokeAction(e),onToggleMultiSelect:()=>this.toggleMultiSelectMode(),onCommitSelection:()=>this.commitSelection(),onClearSelection:()=>this.clearSelection()}),this.pill.setActions(this.actions),this.pill.setUser(this.user),this.pill.setComments(this.comments),this.pill.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length),this.pill.show(),this.highlighter=new q(this.root,this.opts.ignoreSelectors??[],(e,t)=>this.onElementClick(e,t)),this.highlighter.start(),this.renderAllMarkers(),window.addEventListener("scroll",this.scheduleReposition,!0),window.addEventListener("resize",this.scheduleReposition),this.bus.emit("mounted",{}))}unmount(){window.removeEventListener("scroll",this.scheduleReposition,!0),window.removeEventListener("resize",this.scheduleReposition),this.highlighter?.destroy(),this.popover?.destroy(),this.pill?.destroy(),this.sidebar?.destroy(),this.root?.remove(),this.root=null,this.highlighter=null,this.popover=null,this.pill=null,this.sidebar=null,this.markers.clear(),this.outlines.clear(),this.activeAnchorOutlines.clear();for(let e of this.spotlights)e.el.remove();this.spotlights.clear(),this.pendingFingerprints=[],this.pendingTargets=[],this.bus.emit("unmounted",{})}onElementClick(e,t){if(this.picking){let r=_(e),s=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),s.onSelect(r);return}if(!this.requireUserOrAuth())return;let n=_(e);if(this.popover?.isOpen()&&t.shiftKey){this.popover.addAnchor(n,e);return}if(!this.popover?.isOpen()&&(this.multiSelectMode||t.shiftKey)){this.addToSelection(n,e);return}this.bus.emit("element:selected",{target:e,fingerprint:n});let i=this.commentsForElement(n);this.openPopoverFor([e],[n],i)}openPopoverFor(e,t,n){if(!this.popover)return;let i=n??this.commentsForElement(t[0]);this.popover.open(e,t,i),this.syncActiveAnchorOutlines(t),this.highlighter?.setPaused(!0)}closePopover(){this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1),this.bus.emit("element:deselected",{})}addToSelection(e,t){let n=h(e);this.pendingFingerprints.some(i=>h(i)===n)?(this.pendingFingerprints=this.pendingFingerprints.filter(i=>h(i)!==n),this.pendingTargets=this.pendingTargets.filter(i=>i!==t)):(this.pendingFingerprints.push(e),this.pendingTargets.push(t)),this.syncActiveAnchorOutlines(this.pendingFingerprints),this.pill?.setMultiSelectState(!0,this.pendingFingerprints.length),this.pendingFingerprints.length>0?this.multiSelectMode=!0:this.multiSelectMode=!1}commentsForElement(e){let t=h(e);return this.comments.filter(n=>(n.fingerprints||[]).some(i=>h(i)===t))}async addCommentFromPopover(e,t,n,i,r){if(!this.requireUserOrAuth()||t.length===0)return;let s=typeof location<"u"?location.href:void 0,a={id:F(),schemaVersion:2,fingerprints:t,text:e,createdAt:Date.now(),pageVersion:this.opts.pageVersion,pageUrl:s,author:this.user??void 0,authorId:this.user?.id,references:n&&Object.keys(n).length?n:void 0,status:"open",replies:[],attachments:r??[],mentions:i??[]};this.comments.push(a),await this.storage.addComment(this.opts.namespace,a),this.bus.emit("comment:added",{comment:a}),this.popover?.update(this.commentsForElement(t[0])),this.refreshUi()}async removeComment(e){let t=this.comments.find(n=>n.id===e);if(t){if(this.comments=this.comments.filter(n=>n.id!==e),await this.storage.removeComment(this.opts.namespace,e),this.bus.emit("comment:removed",{id:e,comment:t}),this.popover?.isOpen()){let n=this.popover.getAnchors();n[0]&&this.popover.update(this.commentsForElement(n[0]))}this.refreshUi()}}refreshUi(){this.pill?.setComments(this.comments),this.renderAllMarkers(),this.sidebar?.update(this.comments,this.resolvedConfidence)}toggleSidebar(){if(!this.sidebar)return;this.sidebar.isOpen()||this.renderAllMarkers(),this.sidebar.toggle(this.comments,this.resolvedConfidence);let e=this.sidebar.isOpen();this.pill?.setSidebarOpen(e),this.bus.emit(e?"sidebar:opened":"sidebar:closed",{})}closeSidebar(){this.sidebar?.close(),this.pill?.setSidebarOpen(!1),this.bus.emit("sidebar:closed",{})}startPicking(e,t){this.picking&&this.picking.onCancel(),this.picking={onSelect:e,onCancel:t},this.highlighter?.setPaused(!1),this.showPickingBanner()}cancelPicking(){if(!this.picking)return;let e=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),e.onCancel()}showPickingBanner(){this.root&&(this.pickingBanner=document.createElement("div"),this.pickingBanner.className="vz-picking-banner",this.pickingBanner.innerHTML=`
1093
1093
  <span>Click any element to reference</span>
1094
1094
  <span class="vz-picking-banner-hint">or press <span class="vz-picking-banner-kbd">Esc</span></span>
1095
1095
  <button class="vz-picking-banner-cancel" data-vz="cancel-pick">Cancel</button>
1096
- `,this.pickingBanner.addEventListener("click",e=>{e.target.closest('[data-vz="cancel-pick"]')&&this.cancelPicking()}),this.root.appendChild(this.pickingBanner))}hidePickingBanner(){this.pickingBanner?.remove(),this.pickingBanner=null}jumpToReference(e,t){let i=this.comments.find(r=>r.id===e)?.references?.[t];i&&this.jumpToFingerprint(i)}jumpToFingerprint(e){let t=L(e);if(!t){this.pill?.toast("Element not found on this page");return}if(t.scrollIntoView({behavior:"smooth",block:"center"}),this.root){let r=document.createElement("div");r.className="vz-jump-spotlight",this.root.appendChild(r),this.positionOutline(r,t);let s={el:r,target:t};this.spotlights.add(s),setTimeout(()=>{r.remove(),this.spotlights.delete(s)},1800)}let n=h(e),i=this.outlines.get(n)?.outline;i&&setTimeout(()=>{i.classList.remove("is-pulsing"),i.offsetWidth,i.classList.add("is-pulsing"),setTimeout(()=>i.classList.remove("is-pulsing"),1500)},250)}renderAllMarkers(){if(!this.root)return;for(let{marker:r}of this.markers.values())r.remove();for(let{outline:r}of this.outlines.values())r.remove();this.markers.clear(),this.outlines.clear();let e=new Map,t=new Map,n=r=>r==="exact"?3:r==="likely"?2:r==="drifted"?1:0,i=(r,s)=>r===void 0||n(s)>n(r)?s:r;for(let r of this.comments)for(let s of r.fingerprints||[]){let a=h(s),l=e.get(a);if(!l){let c=j(s);l={fp:s,target:c.element,confidence:c.confidence,commentIds:[]},e.set(a,l)}l.commentIds.push(r.id),t.set(r.id,i(t.get(r.id),l.confidence))}this.resolvedConfidence.clear();for(let r of this.comments){let s=t.get(r.id)??"orphaned";this.resolvedConfidence.set(r.id,s);let a=(r.fingerprints||[])[0],l=a?e.get(h(a))?.target??null:null;this.bus.emit("anchor:resolved",{comment:r,confidence:s,element:l})}for(let r of this.comments)this.selfHealedThisSession.has(r.id)||this.resolvedConfidence.get(r.id)==="drifted"&&this.selfHealComment(r,e);for(let[r,s]of e){if(s.confidence==="orphaned"||!s.target)continue;let a=document.createElement("div");a.className="vz-comment-outline",s.confidence==="drifted"&&a.classList.add("vz-comment-outline-drifted"),this.root.appendChild(a),this.outlines.set(r,{outline:a,target:s.target,fp:s.fp});let l=document.createElement("button");l.className="vz-marker",s.confidence==="drifted"&&l.classList.add("vz-marker-drifted"),l.setAttribute("data-element-key",r),l.setAttribute("data-confidence",s.confidence);let c=s.commentIds.length;if(c>1)l.textContent=String(c),l.title=c+" comments";else{l.textContent="";let p=this.comments.find(m=>m.id===s.commentIds[0]);l.title=p?.author?"Comment by "+p.author.name:"Comment"}l.addEventListener("click",p=>{if(p.preventDefault(),p.stopPropagation(),s.target){let m=this.commentsForElement(s.fp);this.openPopoverFor([s.target],[s.fp],m)}}),l.addEventListener("mouseenter",()=>this.pulseRelatedElements(s.commentIds,r)),this.root.appendChild(l),this.markers.set(r,{marker:l,target:s.target,fp:s.fp,commentIds:s.commentIds}),s.target?(this.positionMarker(l,s.target),this.positionOutline(a,s.target)):(l.style.display="none",a.style.display="none")}}pulseRelatedElements(e,t){let n=new Set;for(let i of e){let r=this.comments.find(a=>a.id===i);if(!r)continue;let s=r.fingerprints||[];if(!(s.length<=1))for(let a of s){let l=h(a);l!==t&&n.add(l)}}for(let i of n){let r=this.outlines.get(i)?.outline;r&&(r.classList.remove("is-pulsing"),r.offsetWidth,r.classList.add("is-pulsing"),setTimeout(()=>r.classList.remove("is-pulsing"),900))}}positionOutline(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.left+"px",e.style.top=n.top+"px",e.style.width=n.width+"px",e.style.height=n.height+"px"}positionMarker(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.right+"px",e.style.top=n.top+"px"}syncActiveAnchorOutlines(e){if(!this.root)return;let t=new Set(e.map(n=>h(n)));for(let[n,i]of this.activeAnchorOutlines)t.has(n)||(i.el.remove(),this.activeAnchorOutlines.delete(n));for(let n of e){let i=h(n);if(this.activeAnchorOutlines.has(i))continue;let r=document.createElement("div");r.className="vz-comment-outline is-selected-pending",this.root.appendChild(r);let s=L(n);s?this.positionOutline(r,s):r.style.display="none",this.activeAnchorOutlines.set(i,{el:r,fp:n})}}clearActiveAnchorOutlines(){for(let e of this.activeAnchorOutlines.values())e.el.remove();this.activeAnchorOutlines.clear()}actionContext(){return{comments:this.getComments(),pageHtml:this.snapshotHtml(),pageUrl:typeof location<"u"?location.href:void 0,pageVersion:this.opts.pageVersion,user:this.user??void 0,timestamp:Date.now(),copyToClipboard:e=>this.copyToClipboard(e),toast:e=>this.pill?.toast(e)}}snapshotHtml(){let e=document.documentElement.cloneNode(!0);for(let n of e.querySelectorAll("[data-vizu-root], #vizu-styles"))n.remove();return`<!DOCTYPE html>
1096
+ `,this.pickingBanner.addEventListener("click",e=>{e.target.closest('[data-vz="cancel-pick"]')&&this.cancelPicking()}),this.root.appendChild(this.pickingBanner))}hidePickingBanner(){this.pickingBanner?.remove(),this.pickingBanner=null}jumpToReference(e,t){let i=this.comments.find(r=>r.id===e)?.references?.[t];i&&this.jumpToFingerprint(i)}jumpToFingerprint(e){let t=R(e);if(!t){this.pill?.toast("Element not found on this page");return}if(t.scrollIntoView({behavior:"smooth",block:"center"}),this.root){let r=document.createElement("div");r.className="vz-jump-spotlight",this.root.appendChild(r),this.positionOutline(r,t);let s={el:r,target:t};this.spotlights.add(s),setTimeout(()=>{r.remove(),this.spotlights.delete(s)},1800)}let n=h(e),i=this.outlines.get(n)?.outline;i&&setTimeout(()=>{i.classList.remove("is-pulsing"),i.offsetWidth,i.classList.add("is-pulsing"),setTimeout(()=>i.classList.remove("is-pulsing"),1500)},250)}renderAllMarkers(){if(!this.root)return;for(let{marker:r}of this.markers.values())r.remove();for(let{outline:r}of this.outlines.values())r.remove();this.markers.clear(),this.outlines.clear();let e=new Map,t=new Map,n=r=>r==="exact"?3:r==="likely"?2:r==="drifted"?1:0,i=(r,s)=>r===void 0||n(s)>n(r)?s:r;for(let r of this.comments)for(let s of r.fingerprints||[]){let a=h(s),l=e.get(a);if(!l){let c=j(s);l={fp:s,target:c.element,confidence:c.confidence,commentIds:[]},e.set(a,l)}l.commentIds.push(r.id),t.set(r.id,i(t.get(r.id),l.confidence))}this.resolvedConfidence.clear();for(let r of this.comments){let s=t.get(r.id)??"orphaned";this.resolvedConfidence.set(r.id,s);let a=(r.fingerprints||[])[0],l=a?e.get(h(a))?.target??null:null;this.bus.emit("anchor:resolved",{comment:r,confidence:s,element:l})}for(let r of this.comments)this.selfHealedThisSession.has(r.id)||this.resolvedConfidence.get(r.id)==="drifted"&&this.selfHealComment(r,e);for(let[r,s]of e){if(s.confidence==="orphaned"||!s.target)continue;let a=document.createElement("div");a.className="vz-comment-outline",s.confidence==="drifted"&&a.classList.add("vz-comment-outline-drifted"),this.root.appendChild(a),this.outlines.set(r,{outline:a,target:s.target,fp:s.fp});let l=document.createElement("button");l.className="vz-marker",s.confidence==="drifted"&&l.classList.add("vz-marker-drifted"),l.setAttribute("data-element-key",r),l.setAttribute("data-confidence",s.confidence);let c=s.commentIds.length;if(c>1)l.textContent=String(c),l.title=c+" comments";else{l.textContent="";let p=this.comments.find(m=>m.id===s.commentIds[0]);l.title=p?.author?"Comment by "+p.author.name:"Comment"}l.addEventListener("click",p=>{if(p.preventDefault(),p.stopPropagation(),s.target){let m=this.commentsForElement(s.fp);this.openPopoverFor([s.target],[s.fp],m)}}),l.addEventListener("mouseenter",()=>this.pulseRelatedElements(s.commentIds,r)),this.root.appendChild(l),this.markers.set(r,{marker:l,target:s.target,fp:s.fp,commentIds:s.commentIds}),s.target?(this.positionMarker(l,s.target),this.positionOutline(a,s.target)):(l.style.display="none",a.style.display="none")}}pulseRelatedElements(e,t){let n=new Set;for(let i of e){let r=this.comments.find(a=>a.id===i);if(!r)continue;let s=r.fingerprints||[];if(!(s.length<=1))for(let a of s){let l=h(a);l!==t&&n.add(l)}}for(let i of n){let r=this.outlines.get(i)?.outline;r&&(r.classList.remove("is-pulsing"),r.offsetWidth,r.classList.add("is-pulsing"),setTimeout(()=>r.classList.remove("is-pulsing"),900))}}positionOutline(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.left+"px",e.style.top=n.top+"px",e.style.width=n.width+"px",e.style.height=n.height+"px"}positionMarker(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.right+"px",e.style.top=n.top+"px"}syncActiveAnchorOutlines(e){if(!this.root)return;let t=new Set(e.map(n=>h(n)));for(let[n,i]of this.activeAnchorOutlines)t.has(n)||(i.el.remove(),this.activeAnchorOutlines.delete(n));for(let n of e){let i=h(n);if(this.activeAnchorOutlines.has(i))continue;let r=document.createElement("div");r.className="vz-comment-outline is-selected-pending",this.root.appendChild(r);let s=R(n);s?this.positionOutline(r,s):r.style.display="none",this.activeAnchorOutlines.set(i,{el:r,fp:n})}}clearActiveAnchorOutlines(){for(let e of this.activeAnchorOutlines.values())e.el.remove();this.activeAnchorOutlines.clear()}actionContext(){return{comments:this.getComments(),pageHtml:this.snapshotHtml(),pageUrl:typeof location<"u"?location.href:void 0,pageVersion:this.opts.pageVersion,user:this.user??void 0,timestamp:Date.now(),copyToClipboard:e=>this.copyToClipboard(e),toast:e=>this.pill?.toast(e)}}snapshotHtml(){let e=document.documentElement.cloneNode(!0);for(let n of e.querySelectorAll("[data-vizu-root], #vizu-styles"))n.remove();return`<!DOCTYPE html>
1097
1097
  <html`+document.documentElement.getAttributeNames().map(n=>` ${n}="${(document.documentElement.getAttribute(n)||"").replace(/"/g,"&quot;")}"`).join("")+`>
1098
1098
  `+e.innerHTML+`
1099
1099
  </html>`}copyToClipboard(e){navigator.clipboard?.writeText?navigator.clipboard.writeText(e).catch(()=>he(e)):he(e)}};function he(o){let e=document.createElement("textarea");e.value=o,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{document.execCommand("copy")}catch{}e.remove()}function Ke(){if(typeof document>"u")return null;let o=document.currentScript;if(o)return o;let e=Array.from(document.scripts);return e.find(t=>t.dataset&&t.dataset.vizuAuto!==void 0)||e.find(t=>t.src&&/vizu(\.min)?\.js/.test(t.src))||null}function Je(){if(typeof window>"u"||window.__vizu)return;let e=Ke()?.dataset||{},t=e.storage&&["local","memory","none"].includes(e.storage)?e.storage:"local",n=e.userName?{id:e.userId,name:e.userName,avatarUrl:e.userAvatar,email:e.userEmail}:void 0,i={shortcut:e.shortcut||"mod+shift+e",namespace:e.namespace||"default",pageVersion:e.version,accent:e.accent,startEnabled:e.startEnabled==="true"||e.startEnabled===""||e.startEnabled==="1",ignoreSelectors:e.ignore?e.ignore.split(",").map(s=>s.trim()).filter(Boolean):[],storage:t,user:n},r=new A(i,"local");window.__vizu=r,window.Vizu=A}Je();return Ce(We);})();