backpack-viewer 0.7.5 → 0.7.7

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.
@@ -1,4 +1,4 @@
1
- var Jn=Object.defineProperty;var Kn=(t,e,s)=>e in t?Jn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var At=(t,e,s)=>Kn(t,typeof e!="symbol"?e+"":e,s);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))l(u);new MutationObserver(u=>{for(const r of u)if(r.type==="childList")for(const d of r.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&l(d)}).observe(document,{childList:!0,subtree:!0});function s(u){const r={};return u.integrity&&(r.integrity=u.integrity),u.referrerPolicy&&(r.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?r.credentials="include":u.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function l(u){if(u.ep)return;u.ep=!0;const r=s(u);fetch(u.href,r)}})();const Zn="modulepreload",Qn=function(t){return"/"+t},hn={},eo=function(e,s,l){let u=Promise.resolve();if(s&&s.length>0){let d=function(g){return Promise.all(g.map(i=>Promise.resolve(i).then(c=>({status:"fulfilled",value:c}),c=>({status:"rejected",reason:c}))))};document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),n=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));u=d(s.map(g=>{if(g=Qn(g),g in hn)return;hn[g]=!0;const i=g.endsWith(".css"),c=i?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${g}"]${c}`))return;const T=document.createElement("link");if(T.rel=i?"stylesheet":Zn,i||(T.as="script"),T.crossOrigin="",T.href=g,n&&T.setAttribute("nonce",n),document.head.appendChild(T),i)return new Promise((A,E)=>{T.addEventListener("load",A),T.addEventListener("error",()=>E(new Error(`Unable to preload CSS for ${g}`)))})}))}function r(d){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=d,window.dispatchEvent(o),!o.defaultPrevented)throw d}return u.then(d=>{for(const o of d||[])o.status==="rejected"&&r(o.reason);return e().catch(r)})};async function vt(){const t=await fetch("/api/ontologies");return t.ok?t.json():[]}async function Pt(t){const e=await fetch(`/api/ontologies/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load ontology: ${t}`);return e.json()}async function to(){const t=await fetch("/api/remotes");return t.ok?t.json():[]}async function no(t){const e=await fetch(`/api/remotes/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load remote graph: ${t}`);return e.json()}async function zt(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).ok)throw new Error(`Failed to save ontology: ${t}`)}async function oo(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}/rename`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})})).ok)throw new Error(`Failed to rename ontology: ${t}`)}async function so(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`);return e.ok?e.json():[]}async function fn(t,e,s){const l=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,from:s})});if(!l.ok){const u=await l.json().catch(()=>({}));throw new Error(u.error||"Failed to create branch")}}async function gn(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/switch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to switch branch")}}async function ao(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/${encodeURIComponent(e)}`,{method:"DELETE"});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to delete branch")}}async function co(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`);return e.ok?e.json():[]}async function io(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to create snapshot")}}async function lo(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/rollback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({version:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to rollback")}}async function ro(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`);return e.ok?e.json():[]}async function yn(t,e,s,l,u){const r=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e,description:u,nodeIds:s,edgeIds:l})});if(!r.ok)throw new Error("Failed to save snippet");return(await r.json()).id}async function po(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`);if(!s.ok)throw new Error("Snippet not found");return s.json()}async function uo(t,e){if(!(await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`,{method:"DELETE"})).ok)throw new Error("Failed to delete snippet")}const Cn="bp-dialog-overlay";function nn(){var e;(e=document.querySelector(`.${Cn}`))==null||e.remove();const t=document.createElement("div");return t.className=Cn,document.body.appendChild(t),t}function on(t,e){const s=document.createElement("div");s.className="bp-dialog";const l=document.createElement("h4");return l.className="bp-dialog-title",l.textContent=e,s.appendChild(l),t.appendChild(s),t.addEventListener("click",u=>{u.target===t&&t.remove()}),s}function sn(t,e){const s=document.createElement("div");s.className="bp-dialog-buttons";for(const l of e){const u=document.createElement("button");u.className="bp-dialog-btn",l.accent&&u.classList.add("bp-dialog-btn-accent"),l.danger&&u.classList.add("bp-dialog-btn-danger"),u.textContent=l.label,u.addEventListener("click",l.onClick),s.appendChild(u)}t.appendChild(s)}function jn(t,e){return new Promise(s=>{var d;const l=nn(),u=on(l,t),r=document.createElement("p");r.className="bp-dialog-message",r.textContent=e,u.appendChild(r),sn(u,[{label:"Cancel",onClick:()=>{l.remove(),s(!1)}},{label:"Confirm",accent:!0,onClick:()=>{l.remove(),s(!0)}}]),(d=u.querySelector(".bp-dialog-btn-accent"))==null||d.focus()})}function Dt(t,e,s){return new Promise(l=>{const u=nn(),r=on(u,t),d=document.createElement("input");d.type="text",d.className="bp-dialog-input",d.placeholder=e??"",d.value="",r.appendChild(d);const o=()=>{const n=d.value.trim();u.remove(),l(n||null)};d.addEventListener("keydown",n=>{n.key==="Enter"&&o(),n.key==="Escape"&&(u.remove(),l(null))}),sn(r,[{label:"Cancel",onClick:()=>{u.remove(),l(null)}},{label:"OK",accent:!0,onClick:o}]),d.focus(),d.select()})}function mo(){return new Promise(t=>{const e=nn(),s=on(e,"Add Backpack"),l=document.createElement("p");l.className="bp-dialog-message",l.textContent="Enter the absolute path to a directory that should become a backpack. It will be shown in the sidebar using the last segment of the path as its display name.",s.appendChild(l);const u=document.createElement("label");u.className="bp-dialog-label",u.textContent="Path",s.appendChild(u);const r=document.createElement("div");r.className="bp-dialog-path-row",s.appendChild(r);const d=document.createElement("input");d.type="text",d.className="bp-dialog-input bp-dialog-path-input",d.placeholder="/Users/you/OneDrive/work",r.appendChild(d);const o=document.createElement("button");o.type="button",o.className="bp-dialog-btn bp-dialog-browse-btn",o.textContent="Browse...",r.appendChild(o),typeof window.showDirectoryPicker=="function"||(o.disabled=!0,o.title="Browser doesn't support native folder picker — paste the path manually"),o.addEventListener("click",async E=>{E.preventDefault();try{const F=await window.showDirectoryPicker({mode:"read"});g.textContent=`Picked "${F.name}" — paste the absolute path to it below.`,d.focus()}catch{}});const g=document.createElement("div");g.className="bp-dialog-picker-hint",s.appendChild(g);const i=document.createElement("div");i.className="bp-dialog-activate-row";const c=document.createElement("input");c.type="checkbox",c.id="bp-dialog-activate",c.checked=!0;const T=document.createElement("label");T.htmlFor="bp-dialog-activate",T.textContent="Switch to this backpack after registering",i.appendChild(c),i.appendChild(T),s.appendChild(i),d.addEventListener("dragover",E=>{E.preventDefault(),d.classList.add("bp-dialog-drag-over")}),d.addEventListener("dragleave",()=>{d.classList.remove("bp-dialog-drag-over")}),d.addEventListener("drop",E=>{var V,_,X;E.preventDefault(),d.classList.remove("bp-dialog-drag-over");const F=(V=E.dataTransfer)==null?void 0:V.items;if(!F||F.length===0)return;const W=(X=(_=F[0]).webkitGetAsEntry)==null?void 0:X.call(_);W!=null&&W.isDirectory&&(g.textContent=`Dropped "${W.name}" — paste the absolute path to it below.`)});const A=()=>{const E=d.value.trim();E&&(e.remove(),t({path:E,activate:c.checked}))};d.addEventListener("keydown",E=>{E.key==="Enter"&&A(),E.key==="Escape"&&(e.remove(),t(null))}),sn(s,[{label:"Cancel",onClick:()=>{e.remove(),t(null)}},{label:"Register",accent:!0,onClick:A}]),d.focus()})}function kt(t,e=3e3){const s=document.querySelector(".bp-toast");s&&s.remove();const l=document.createElement("div");l.className="bp-toast",l.textContent=t,document.body.appendChild(l),setTimeout(()=>l.classList.add("bp-toast-visible"),10),setTimeout(()=>{l.classList.remove("bp-toast-visible"),setTimeout(()=>l.remove(),300)},e)}const bn="http://www.w3.org/2000/svg";function at(t,e){const s=document.createElementNS(bn,"svg"),l=t.size??16;s.setAttribute("width",String(l)),s.setAttribute("height",String(l)),s.setAttribute("viewBox",t.viewBox??"0 0 24 24"),s.setAttribute("fill","none"),s.setAttribute("stroke","currentColor"),s.setAttribute("stroke-width",String(t.strokeWidth??2)),t.strokeLinecap&&s.setAttribute("stroke-linecap",t.strokeLinecap),t.strokeLinejoin&&s.setAttribute("stroke-linejoin",t.strokeLinejoin),t.className&&s.setAttribute("class",t.className);for(const u of e){const r=document.createElementNS(bn,u.tag);for(const[d,o]of Object.entries(u.attrs))r.setAttribute(d,String(o));s.appendChild(r)}return s}function ho(t){return Array.from(t.childNodes).map(e=>e.cloneNode(!0))}function fo(t,e){t.replaceChildren(...e)}function vn(t){return t>=1e3?`${(t/1e3).toFixed(1)}k tokens`:`${t} tokens`}function xn(t,e){return t*50+e*25+50}function go(t,e){const s=typeof e=="function"?{onSelect:e}:e,l=document.createElement("h2");l.textContent="Backpack Viewer";const u=document.createElement("input");u.type="text",u.placeholder="Filter...",u.id="filter";const r=document.createElement("ul");r.id="ontology-list";const d=document.createElement("h3");d.className="sidebar-section-heading",d.textContent="REMOTE GRAPHS",d.hidden=!0;const o=document.createElement("ul");o.id="remote-list",o.className="remote-list",o.hidden=!0;const n=document.createElement("div");n.className="sidebar-footer";const g=document.createElement("a");g.href="mailto:support@backpackontology.com",g.textContent="support@backpackontology.com";const i=document.createElement("span");i.textContent="Feedback & support";const c=document.createElement("span");c.className="sidebar-version",c.textContent="v0.7.5",n.append(g,i,c);const T=document.createElement("button");T.className="sidebar-collapse-btn",T.title="Toggle sidebar (Tab)",T.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"11 17 6 12 11 7"}},{tag:"polyline",attrs:{points:"18 17 13 12 18 7"}}]));let A=!1;function E(){A=!A,t.classList.toggle("sidebar-collapsed",A),ye.classList.toggle("hidden",!A)}T.addEventListener("click",E);const F=document.createElement("div");F.className="sidebar-heading-row",F.appendChild(l),F.appendChild(T),t.appendChild(F);const W=document.createElement("div");W.className="sidebar-stale-banner",W.hidden=!0,t.appendChild(W);const V=document.createElement("button");V.className="backpack-picker-pill",V.type="button",V.setAttribute("aria-haspopup","listbox"),V.setAttribute("aria-expanded","false");const _=document.createElement("span");_.className="backpack-picker-dot";const X=document.createElement("span");X.className="backpack-picker-name",X.textContent="...";const Y=document.createElement("span");Y.className="backpack-picker-caret",Y.textContent="▾",V.appendChild(_),V.appendChild(X),V.appendChild(Y);const K=document.createElement("div");K.className="backpack-picker-dropdown",K.hidden=!0,K.setAttribute("role","listbox");const q=document.createElement("div");q.className="backpack-picker-container",q.appendChild(V),q.appendChild(K),t.appendChild(q);let me=!1;function U(){me=!1,K.hidden=!0,V.setAttribute("aria-expanded","false")}function pe(){me=!0,K.hidden=!1,V.setAttribute("aria-expanded","true")}V.addEventListener("click",p=>{p.stopPropagation(),me?U():pe()}),document.addEventListener("click",p=>{q.contains(p.target)||U()});let Ee=[],te=null;function G(){K.replaceChildren();for(const C of Ee){const m=document.createElement("button");m.className="backpack-picker-item",m.type="button",m.setAttribute("role","option"),C.active&&m.classList.add("active");const v=document.createElement("span");v.className="backpack-picker-item-dot",v.style.setProperty("--backpack-color",C.color);const S=document.createElement("span");S.className="backpack-picker-item-name",S.textContent=C.name;const h=document.createElement("span");h.className="backpack-picker-item-path",h.textContent=C.path,m.appendChild(v),m.appendChild(S),m.appendChild(h),m.addEventListener("click",I=>{I.stopPropagation(),U(),!C.active&&s.onBackpackSwitch&&s.onBackpackSwitch(C.name)}),K.appendChild(m)}const p=document.createElement("div");p.className="backpack-picker-divider",K.appendChild(p);const y=document.createElement("button");y.className="backpack-picker-item backpack-picker-add",y.type="button",y.textContent="+ Add new backpack…",y.addEventListener("click",async C=>{if(C.stopPropagation(),U(),!s.onBackpackRegister)return;const m=await mo();m&&s.onBackpackRegister(m.path,m.activate)}),K.appendChild(y)}const ye=document.createElement("button");ye.className="tools-pane-toggle hidden",ye.title="Show sidebar (Tab)",ye.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"13 7 18 12 13 17"}},{tag:"polyline",attrs:{points:"6 7 11 12 6 17"}}])),ye.addEventListener("click",E),t.appendChild(u),t.appendChild(r),t.appendChild(d),t.appendChild(o),t.appendChild(n);let Ce=[],se=[],ge="";return u.addEventListener("input",()=>{const p=u.value.toLowerCase();for(const y of Ce){const C=y.dataset.name??"";y.style.display=C.includes(p)?"":"none"}for(const y of se){const C=y.dataset.name??"";y.style.display=C.includes(p)?"":"none"}}),{setStaleVersionBanner(p,y){W.replaceChildren();const C=document.createElement("div");C.className="sidebar-stale-banner-title",C.textContent=`Viewer ${p} is out of date`;const m=document.createElement("div");m.className="sidebar-stale-banner-subtitle",m.textContent=`Latest is ${y}. Your version is stuck because of an npx cache.`;const v=document.createElement("pre");v.className="sidebar-stale-banner-hint",v.textContent=`npm cache clean --force
1
+ var Jn=Object.defineProperty;var Kn=(t,e,s)=>e in t?Jn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var At=(t,e,s)=>Kn(t,typeof e!="symbol"?e+"":e,s);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))l(u);new MutationObserver(u=>{for(const r of u)if(r.type==="childList")for(const d of r.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&l(d)}).observe(document,{childList:!0,subtree:!0});function s(u){const r={};return u.integrity&&(r.integrity=u.integrity),u.referrerPolicy&&(r.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?r.credentials="include":u.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function l(u){if(u.ep)return;u.ep=!0;const r=s(u);fetch(u.href,r)}})();const Zn="modulepreload",Qn=function(t){return"/"+t},hn={},eo=function(e,s,l){let u=Promise.resolve();if(s&&s.length>0){let d=function(g){return Promise.all(g.map(i=>Promise.resolve(i).then(c=>({status:"fulfilled",value:c}),c=>({status:"rejected",reason:c}))))};document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),n=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));u=d(s.map(g=>{if(g=Qn(g),g in hn)return;hn[g]=!0;const i=g.endsWith(".css"),c=i?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${g}"]${c}`))return;const T=document.createElement("link");if(T.rel=i?"stylesheet":Zn,i||(T.as="script"),T.crossOrigin="",T.href=g,n&&T.setAttribute("nonce",n),document.head.appendChild(T),i)return new Promise((A,E)=>{T.addEventListener("load",A),T.addEventListener("error",()=>E(new Error(`Unable to preload CSS for ${g}`)))})}))}function r(d){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=d,window.dispatchEvent(o),!o.defaultPrevented)throw d}return u.then(d=>{for(const o of d||[])o.status==="rejected"&&r(o.reason);return e().catch(r)})};async function vt(){const t=await fetch("/api/ontologies");return t.ok?t.json():[]}async function Pt(t){const e=await fetch(`/api/ontologies/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load ontology: ${t}`);return e.json()}async function to(){const t=await fetch("/api/remotes");return t.ok?t.json():[]}async function no(t){const e=await fetch(`/api/remotes/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load remote graph: ${t}`);return e.json()}async function zt(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).ok)throw new Error(`Failed to save ontology: ${t}`)}async function oo(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}/rename`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})})).ok)throw new Error(`Failed to rename ontology: ${t}`)}async function so(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`);return e.ok?e.json():[]}async function fn(t,e,s){const l=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,from:s})});if(!l.ok){const u=await l.json().catch(()=>({}));throw new Error(u.error||"Failed to create branch")}}async function gn(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/switch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to switch branch")}}async function ao(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/${encodeURIComponent(e)}`,{method:"DELETE"});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to delete branch")}}async function co(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`);return e.ok?e.json():[]}async function io(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to create snapshot")}}async function lo(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/rollback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({version:e})});if(!s.ok){const l=await s.json().catch(()=>({}));throw new Error(l.error||"Failed to rollback")}}async function ro(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`);return e.ok?e.json():[]}async function yn(t,e,s,l,u){const r=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e,description:u,nodeIds:s,edgeIds:l})});if(!r.ok)throw new Error("Failed to save snippet");return(await r.json()).id}async function po(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`);if(!s.ok)throw new Error("Snippet not found");return s.json()}async function uo(t,e){if(!(await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`,{method:"DELETE"})).ok)throw new Error("Failed to delete snippet")}const Cn="bp-dialog-overlay";function nn(){var e;(e=document.querySelector(`.${Cn}`))==null||e.remove();const t=document.createElement("div");return t.className=Cn,document.body.appendChild(t),t}function on(t,e){const s=document.createElement("div");s.className="bp-dialog";const l=document.createElement("h4");return l.className="bp-dialog-title",l.textContent=e,s.appendChild(l),t.appendChild(s),t.addEventListener("click",u=>{u.target===t&&t.remove()}),s}function sn(t,e){const s=document.createElement("div");s.className="bp-dialog-buttons";for(const l of e){const u=document.createElement("button");u.className="bp-dialog-btn",l.accent&&u.classList.add("bp-dialog-btn-accent"),l.danger&&u.classList.add("bp-dialog-btn-danger"),u.textContent=l.label,u.addEventListener("click",l.onClick),s.appendChild(u)}t.appendChild(s)}function jn(t,e){return new Promise(s=>{var d;const l=nn(),u=on(l,t),r=document.createElement("p");r.className="bp-dialog-message",r.textContent=e,u.appendChild(r),sn(u,[{label:"Cancel",onClick:()=>{l.remove(),s(!1)}},{label:"Confirm",accent:!0,onClick:()=>{l.remove(),s(!0)}}]),(d=u.querySelector(".bp-dialog-btn-accent"))==null||d.focus()})}function Dt(t,e,s){return new Promise(l=>{const u=nn(),r=on(u,t),d=document.createElement("input");d.type="text",d.className="bp-dialog-input",d.placeholder=e??"",d.value="",r.appendChild(d);const o=()=>{const n=d.value.trim();u.remove(),l(n||null)};d.addEventListener("keydown",n=>{n.key==="Enter"&&o(),n.key==="Escape"&&(u.remove(),l(null))}),sn(r,[{label:"Cancel",onClick:()=>{u.remove(),l(null)}},{label:"OK",accent:!0,onClick:o}]),d.focus(),d.select()})}function mo(){return new Promise(t=>{const e=nn(),s=on(e,"Add Backpack"),l=document.createElement("p");l.className="bp-dialog-message",l.textContent="Enter the absolute path to a directory that should become a backpack. It will be shown in the sidebar using the last segment of the path as its display name.",s.appendChild(l);const u=document.createElement("label");u.className="bp-dialog-label",u.textContent="Path",s.appendChild(u);const r=document.createElement("div");r.className="bp-dialog-path-row",s.appendChild(r);const d=document.createElement("input");d.type="text",d.className="bp-dialog-input bp-dialog-path-input",d.placeholder="/Users/you/OneDrive/work",r.appendChild(d);const o=document.createElement("button");o.type="button",o.className="bp-dialog-btn bp-dialog-browse-btn",o.textContent="Browse...",r.appendChild(o),typeof window.showDirectoryPicker=="function"||(o.disabled=!0,o.title="Browser doesn't support native folder picker — paste the path manually"),o.addEventListener("click",async E=>{E.preventDefault();try{const F=await window.showDirectoryPicker({mode:"read"});g.textContent=`Picked "${F.name}" — paste the absolute path to it below.`,d.focus()}catch{}});const g=document.createElement("div");g.className="bp-dialog-picker-hint",s.appendChild(g);const i=document.createElement("div");i.className="bp-dialog-activate-row";const c=document.createElement("input");c.type="checkbox",c.id="bp-dialog-activate",c.checked=!0;const T=document.createElement("label");T.htmlFor="bp-dialog-activate",T.textContent="Switch to this backpack after registering",i.appendChild(c),i.appendChild(T),s.appendChild(i),d.addEventListener("dragover",E=>{E.preventDefault(),d.classList.add("bp-dialog-drag-over")}),d.addEventListener("dragleave",()=>{d.classList.remove("bp-dialog-drag-over")}),d.addEventListener("drop",E=>{var V,_,X;E.preventDefault(),d.classList.remove("bp-dialog-drag-over");const F=(V=E.dataTransfer)==null?void 0:V.items;if(!F||F.length===0)return;const W=(X=(_=F[0]).webkitGetAsEntry)==null?void 0:X.call(_);W!=null&&W.isDirectory&&(g.textContent=`Dropped "${W.name}" — paste the absolute path to it below.`)});const A=()=>{const E=d.value.trim();E&&(e.remove(),t({path:E,activate:c.checked}))};d.addEventListener("keydown",E=>{E.key==="Enter"&&A(),E.key==="Escape"&&(e.remove(),t(null))}),sn(s,[{label:"Cancel",onClick:()=>{e.remove(),t(null)}},{label:"Register",accent:!0,onClick:A}]),d.focus()})}function kt(t,e=3e3){const s=document.querySelector(".bp-toast");s&&s.remove();const l=document.createElement("div");l.className="bp-toast",l.textContent=t,document.body.appendChild(l),setTimeout(()=>l.classList.add("bp-toast-visible"),10),setTimeout(()=>{l.classList.remove("bp-toast-visible"),setTimeout(()=>l.remove(),300)},e)}const bn="http://www.w3.org/2000/svg";function at(t,e){const s=document.createElementNS(bn,"svg"),l=t.size??16;s.setAttribute("width",String(l)),s.setAttribute("height",String(l)),s.setAttribute("viewBox",t.viewBox??"0 0 24 24"),s.setAttribute("fill","none"),s.setAttribute("stroke","currentColor"),s.setAttribute("stroke-width",String(t.strokeWidth??2)),t.strokeLinecap&&s.setAttribute("stroke-linecap",t.strokeLinecap),t.strokeLinejoin&&s.setAttribute("stroke-linejoin",t.strokeLinejoin),t.className&&s.setAttribute("class",t.className);for(const u of e){const r=document.createElementNS(bn,u.tag);for(const[d,o]of Object.entries(u.attrs))r.setAttribute(d,String(o));s.appendChild(r)}return s}function ho(t){return Array.from(t.childNodes).map(e=>e.cloneNode(!0))}function fo(t,e){t.replaceChildren(...e)}function vn(t){return t>=1e3?`${(t/1e3).toFixed(1)}k tokens`:`${t} tokens`}function xn(t,e){return t*50+e*25+50}function go(t,e){const s=typeof e=="function"?{onSelect:e}:e,l=document.createElement("h2");l.textContent="Backpack Viewer";const u=document.createElement("input");u.type="text",u.placeholder="Filter...",u.id="filter";const r=document.createElement("ul");r.id="ontology-list";const d=document.createElement("h3");d.className="sidebar-section-heading",d.textContent="REMOTE GRAPHS",d.hidden=!0;const o=document.createElement("ul");o.id="remote-list",o.className="remote-list",o.hidden=!0;const n=document.createElement("div");n.className="sidebar-footer";const g=document.createElement("a");g.href="mailto:support@backpackontology.com",g.textContent="support@backpackontology.com";const i=document.createElement("span");i.textContent="Feedback & support";const c=document.createElement("span");c.className="sidebar-version",c.textContent="v0.7.7",n.append(g,i,c);const T=document.createElement("button");T.className="sidebar-collapse-btn",T.title="Toggle sidebar (Tab)",T.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"11 17 6 12 11 7"}},{tag:"polyline",attrs:{points:"18 17 13 12 18 7"}}]));let A=!1;function E(){A=!A,t.classList.toggle("sidebar-collapsed",A),ye.classList.toggle("hidden",!A)}T.addEventListener("click",E);const F=document.createElement("div");F.className="sidebar-heading-row",F.appendChild(l),F.appendChild(T),t.appendChild(F);const W=document.createElement("div");W.className="sidebar-stale-banner",W.hidden=!0,t.appendChild(W);const V=document.createElement("button");V.className="backpack-picker-pill",V.type="button",V.setAttribute("aria-haspopup","listbox"),V.setAttribute("aria-expanded","false");const _=document.createElement("span");_.className="backpack-picker-dot";const X=document.createElement("span");X.className="backpack-picker-name",X.textContent="...";const Y=document.createElement("span");Y.className="backpack-picker-caret",Y.textContent="▾",V.appendChild(_),V.appendChild(X),V.appendChild(Y);const K=document.createElement("div");K.className="backpack-picker-dropdown",K.hidden=!0,K.setAttribute("role","listbox");const q=document.createElement("div");q.className="backpack-picker-container",q.appendChild(V),q.appendChild(K),t.appendChild(q);let me=!1;function U(){me=!1,K.hidden=!0,V.setAttribute("aria-expanded","false")}function pe(){me=!0,K.hidden=!1,V.setAttribute("aria-expanded","true")}V.addEventListener("click",p=>{p.stopPropagation(),me?U():pe()}),document.addEventListener("click",p=>{q.contains(p.target)||U()});let Ee=[],te=null;function G(){K.replaceChildren();for(const C of Ee){const m=document.createElement("button");m.className="backpack-picker-item",m.type="button",m.setAttribute("role","option"),C.active&&m.classList.add("active");const v=document.createElement("span");v.className="backpack-picker-item-dot",v.style.setProperty("--backpack-color",C.color);const S=document.createElement("span");S.className="backpack-picker-item-name",S.textContent=C.name;const h=document.createElement("span");h.className="backpack-picker-item-path",h.textContent=C.path,m.appendChild(v),m.appendChild(S),m.appendChild(h),m.addEventListener("click",I=>{I.stopPropagation(),U(),!C.active&&s.onBackpackSwitch&&s.onBackpackSwitch(C.name)}),K.appendChild(m)}const p=document.createElement("div");p.className="backpack-picker-divider",K.appendChild(p);const y=document.createElement("button");y.className="backpack-picker-item backpack-picker-add",y.type="button",y.textContent="+ Add new backpack…",y.addEventListener("click",async C=>{if(C.stopPropagation(),U(),!s.onBackpackRegister)return;const m=await mo();m&&s.onBackpackRegister(m.path,m.activate)}),K.appendChild(y)}const ye=document.createElement("button");ye.className="tools-pane-toggle hidden",ye.title="Show sidebar (Tab)",ye.appendChild(at({size:14},[{tag:"polyline",attrs:{points:"13 7 18 12 13 17"}},{tag:"polyline",attrs:{points:"6 7 11 12 6 17"}}])),ye.addEventListener("click",E),t.appendChild(u),t.appendChild(r),t.appendChild(d),t.appendChild(o),t.appendChild(n);let Ce=[],se=[],ge="";return u.addEventListener("input",()=>{const p=u.value.toLowerCase();for(const y of Ce){const C=y.dataset.name??"";y.style.display=C.includes(p)?"":"none"}for(const y of se){const C=y.dataset.name??"";y.style.display=C.includes(p)?"":"none"}}),{setStaleVersionBanner(p,y){W.replaceChildren();const C=document.createElement("div");C.className="sidebar-stale-banner-title",C.textContent=`Viewer ${p} is out of date`;const m=document.createElement("div");m.className="sidebar-stale-banner-subtitle",m.textContent=`Latest is ${y}. Your version is stuck because of an npx cache.`;const v=document.createElement("pre");v.className="sidebar-stale-banner-hint",v.textContent=`npm cache clean --force
2
2
  npx backpack-viewer@latest`,W.appendChild(C),W.appendChild(m),W.appendChild(v),W.hidden=!1},setBackpacks(p){Ee=p.slice();const y=p.find(C=>C.active)??null;te=y,y&&(X.textContent=y.name,_.style.setProperty("--backpack-color",y.color),t.style.setProperty("--backpack-color",y.color)),G()},setActiveBackpack(p){te=p,Ee=Ee.map(y=>({...y,active:y.name===p.name})),Ee.some(y=>y.name===p.name)||Ee.push({...p,active:!0}),X.textContent=p.name,_.style.setProperty("--backpack-color",p.color),t.style.setProperty("--backpack-color",p.color),G()},getActiveBackpack(){return te},setSummaries(p){r.replaceChildren();const y=fetch("/api/locks").then(C=>C.json()).catch(()=>({}));Ce=p.map(C=>{const m=document.createElement("li");m.className="ontology-item",m.dataset.name=C.name;const v=document.createElement("span");v.className="name",v.textContent=C.name;const S=document.createElement("span");S.className="stats";const h=xn(C.nodeCount,C.edgeCount);S.textContent=`${C.nodeCount} nodes, ${C.edgeCount} edges · ~${vn(h)}`;const I=document.createElement("span");I.className="sidebar-branch",I.dataset.graph=C.name;const w=document.createElement("span");if(w.className="sidebar-lock-badge",w.dataset.graph=C.name,y.then(N=>{if(!w.isConnected)return;const L=N[C.name];L&&typeof L=="object"&&L.author&&(w.textContent=`editing: ${L.author}`,w.title=`Last activity: ${L.lastActivity??""}`,w.classList.add("active"))}),m.appendChild(v),m.appendChild(S),m.appendChild(w),m.appendChild(I),s.onRename){const N=document.createElement("button");N.className="sidebar-edit-btn",N.textContent="✎",N.title="Rename";const L=s.onRename;N.addEventListener("click",b=>{b.stopPropagation();const M=document.createElement("input");M.type="text",M.className="sidebar-rename-input",M.value=C.name,v.textContent="",v.appendChild(M),N.style.display="none",M.focus(),M.select();const $=()=>{const Q=M.value.trim();Q&&Q!==C.name?L(C.name,Q):(v.textContent=C.name,N.style.display="")};M.addEventListener("blur",$),M.addEventListener("keydown",Q=>{Q.key==="Enter"&&M.blur(),Q.key==="Escape"&&(M.value=C.name,M.blur())})}),m.appendChild(N)}return m.addEventListener("click",()=>s.onSelect(C.name)),r.appendChild(m),m}),ge&&this.setActive(ge)},setActive(p){ge=p;for(const y of Ce)y.classList.toggle("active",y.dataset.name===p);for(const y of se)y.classList.toggle("active",y.dataset.name===p)},setRemotes(p){o.replaceChildren(),se=p.map(C=>{const m=document.createElement("li");m.className="ontology-item ontology-item-remote",m.dataset.name=C.name;const v=document.createElement("div");v.className="remote-name-row";const S=document.createElement("span");S.className="name",S.textContent=C.name;const h=document.createElement("span");h.className="remote-badge",h.textContent=C.pinned?"remote · pinned":"remote",h.title=`Source: ${C.source??C.url}`,v.appendChild(S),v.appendChild(h);const I=document.createElement("span");I.className="stats";const w=xn(C.nodeCount,C.edgeCount);I.textContent=`${C.nodeCount} nodes, ${C.edgeCount} edges · ~${vn(w)}`;const N=document.createElement("span");return N.className="remote-source",N.textContent=C.source??new URL(C.url).hostname,N.title=C.url,m.appendChild(v),m.appendChild(I),m.appendChild(N),m.addEventListener("click",()=>s.onSelect(C.name)),o.appendChild(m),m});const y=p.length>0;d.hidden=!y,o.hidden=!y,ge&&this.setActive(ge)},setActiveBranch(p,y,C){const m=r.querySelectorAll(`.sidebar-branch[data-graph="${p}"]`);for(const v of m){v.textContent=`/ ${y}`,v.title="Click to switch branch",v.style.cursor="pointer";const S=v.cloneNode(!0);v.replaceWith(S),S.addEventListener("click",h=>{h.stopPropagation(),be(p,S,C??[])})}},setSnippets(p,y){var v;const C=Ce.find(S=>S.dataset.name===p);if(!C||((v=C.querySelector(".sidebar-snippets"))==null||v.remove(),y.length===0))return;const m=document.createElement("div");m.className="sidebar-snippets";for(const S of y){const h=document.createElement("div");h.className="sidebar-snippet";const I=document.createElement("span");I.className="sidebar-snippet-label",I.textContent=`◆ ${S.label}`,I.title=`${S.nodeCount} nodes — click to load`;const w=document.createElement("button");w.className="sidebar-snippet-delete",w.textContent="×",w.title="Delete snippet",w.addEventListener("click",N=>{var L;N.stopPropagation(),(L=s.onSnippetDelete)==null||L.call(s,p,S.id)}),h.appendChild(I),h.appendChild(w),h.addEventListener("click",N=>{var L;N.stopPropagation(),(L=s.onSnippetLoad)==null||L.call(s,p,S.id)}),m.appendChild(h)}C.appendChild(m)},toggle:E,expandBtn:ye};function be(p,y,C){const m=t.querySelector(".branch-picker");m&&m.remove();const v=document.createElement("div");v.className="branch-picker";for(const h of C){const I=document.createElement("div");I.className="branch-picker-item",h.active&&I.classList.add("branch-picker-active");const w=document.createElement("span");if(w.textContent=h.name,I.appendChild(w),!h.active&&s.onBranchDelete){const N=document.createElement("button");N.className="branch-picker-delete",N.textContent="×",N.title=`Delete ${h.name}`,N.addEventListener("click",L=>{L.stopPropagation(),jn("Delete branch",`Delete branch "${h.name}"?`).then(b=>{b&&(s.onBranchDelete(p,h.name),v.remove())})}),I.appendChild(N)}h.active||I.addEventListener("click",()=>{var N;(N=s.onBranchSwitch)==null||N.call(s,p,h.name),v.remove()}),v.appendChild(I)}if(s.onBranchCreate){const h=document.createElement("div");h.className="branch-picker-item branch-picker-create",h.textContent="+ New branch",h.addEventListener("click",()=>{Dt("New branch","Branch name").then(I=>{I&&(s.onBranchCreate(p,I),v.remove())})}),v.appendChild(h)}y.after(v);const S=h=>{v.contains(h.target)||(v.remove(),document.removeEventListener("click",S))};setTimeout(()=>document.addEventListener("click",S),0)}}function Zt(t,e,s,l){return{x0:t,y0:e,x1:s,y1:l,cx:0,cy:0,mass:0,children:[null,null,null,null],body:null}}function En(t,e,s){const l=(t.x0+t.x1)/2,u=(t.y0+t.y1)/2;return(e<l?0:1)+(s<u?0:2)}function wn(t,e){const s=(t.x0+t.x1)/2,l=(t.y0+t.y1)/2;switch(e){case 0:return[t.x0,t.y0,s,l];case 1:return[s,t.y0,t.x1,l];case 2:return[t.x0,l,s,t.y1];default:return[s,l,t.x1,t.y1]}}function Qt(t,e){if(t.mass===0&&t.body===null){t.body=e,t.cx=e.x,t.cy=e.y,t.mass=1;return}if(t.body!==null){const u=t.body;t.body=null,u.x===e.x&&u.y===e.y&&(e.x+=(Math.random()-.5)*.1,e.y+=(Math.random()-.5)*.1);const r=En(t,u.x,u.y);if(t.children[r]===null){const[d,o,n,g]=wn(t,r);t.children[r]=Zt(d,o,n,g)}Qt(t.children[r],u)}const s=En(t,e.x,e.y);if(t.children[s]===null){const[u,r,d,o]=wn(t,s);t.children[s]=Zt(u,r,d,o)}Qt(t.children[s],e);const l=t.mass+1;t.cx=(t.cx*t.mass+e.x)/l,t.cy=(t.cy*t.mass+e.y)/l,t.mass=l}function yo(t){if(t.length===0)return null;let e=1/0,s=1/0,l=-1/0,u=-1/0;for(const i of t)i.x<e&&(e=i.x),i.y<s&&(s=i.y),i.x>l&&(l=i.x),i.y>u&&(u=i.y);const r=Math.max(l-e,u-s)*.1+50,d=(e+l)/2,o=(s+u)/2,n=Math.max(l-e,u-s)/2+r,g=Zt(d-n,o-n,d+n,o+n);for(const i of t)Qt(g,i);return g}function Co(t,e,s,l,u,r){zn(t,e,s,l,u,r)}function zn(t,e,s,l,u,r){if(t.mass===0)return;const d=t.cx-e.x,o=t.cy-e.y,n=d*d+o*o;if(t.body!==null){if(t.body!==e){let i=Math.sqrt(n);i<r&&(i=r);const c=l*u/(i*i),T=d/i*c,A=o/i*c;e.vx-=T,e.vy-=A}return}const g=t.x1-t.x0;if(g*g/n<s*s){let i=Math.sqrt(n);i<r&&(i=r);const c=l*t.mass*u/(i*i),T=d/i*c,A=o/i*c;e.vx-=T,e.vy-=A;return}for(let i=0;i<4;i++)t.children[i]!==null&&zn(t.children[i],e,s,l,u,r)}const _n={clusterStrength:.08,spacing:1.5},kn=6e3,bo=12e3,vo=.004,Hn=140,Yn=350,Sn=.9,Nn=.01,xt=30,_t=50;let Ze={..._n};function lt(t){t.clusterStrength!==void 0&&(Ze.clusterStrength=t.clusterStrength),t.spacing!==void 0&&(Ze.spacing=t.spacing)}function wt(){return{...Ze}}function xo(t){if(t<=30)return{..._n};const e=Math.log2(t/30);return{clusterStrength:Math.min(.5,.08+.06*e),spacing:Math.min(15,1.5+1.2*e)}}function Eo(t,e){for(const s of Object.values(t))if(typeof s=="string")return s;return e}function Ln(t,e,s){const l=new Set(e);let u=new Set(e);for(let r=0;r<s;r++){const d=new Set;for(const o of t.edges)u.has(o.sourceId)&&!l.has(o.targetId)&&d.add(o.targetId),u.has(o.targetId)&&!l.has(o.sourceId)&&d.add(o.sourceId);for(const o of d)l.add(o);if(u=d,d.size===0)break}return{nodes:t.nodes.filter(r=>l.has(r.id)),edges:t.edges.filter(r=>l.has(r.sourceId)&&l.has(r.targetId)),metadata:t.metadata}}function Ht(t){const e=new Map,s=[...new Set(t.nodes.map(n=>n.type))],l=Math.sqrt(s.length)*Yn*.6*Math.max(1,Ze.spacing),u=new Map,r=new Map;for(const n of t.nodes)r.set(n.type,(r.get(n.type)??0)+1);const d=t.nodes.map(n=>{const g=s.indexOf(n.type),i=2*Math.PI*g/Math.max(s.length,1),c=Math.cos(i)*l,T=Math.sin(i)*l,A=u.get(n.type)??0;u.set(n.type,A+1);const E=r.get(n.type)??1,F=2*Math.PI*A/E,W=Hn*.6,V={id:n.id,x:c+Math.cos(F)*W,y:T+Math.sin(F)*W,vx:0,vy:0,label:Eo(n.properties,n.id),type:n.type};return e.set(n.id,V),V}),o=t.edges.map(n=>({sourceId:n.sourceId,targetId:n.targetId,type:n.type}));return{nodes:d,edges:o,nodeMap:e}}const wo=.7,ko=80;function So(t,e){const{nodes:s,edges:l,nodeMap:u}=t,r=bo*Ze.spacing;if(s.length>=ko){const o=yo(s);if(o)for(const g of s)Co(o,g,wo,r,e,xt);const n=r-kn;if(n>0){const g=new Map;for(const i of s){let c=g.get(i.type);c||(c=[],g.set(i.type,c)),c.push(i)}for(const i of g.values())for(let c=0;c<i.length;c++)for(let T=c+1;T<i.length;T++){const A=i[c],E=i[T];let F=E.x-A.x,W=E.y-A.y,V=Math.sqrt(F*F+W*W);V<xt&&(V=xt);const _=n*e/(V*V),X=F/V*_,Y=W/V*_;A.vx+=X,A.vy+=Y,E.vx-=X,E.vy-=Y}}}else for(let o=0;o<s.length;o++)for(let n=o+1;n<s.length;n++){const g=s[o],i=s[n];let c=i.x-g.x,T=i.y-g.y,A=Math.sqrt(c*c+T*T);A<xt&&(A=xt);const F=(g.type===i.type?kn:r)*e/(A*A),W=c/A*F,V=T/A*F;g.vx-=W,g.vy-=V,i.vx+=W,i.vy+=V}for(const o of l){const n=u.get(o.sourceId),g=u.get(o.targetId);if(!n||!g)continue;const i=g.x-n.x,c=g.y-n.y,T=Math.sqrt(i*i+c*c);if(T===0)continue;const A=n.type===g.type?Hn*Ze.spacing:Yn*Ze.spacing,E=vo*(T-A)*e,F=i/T*E,W=c/T*E;n.vx+=F,n.vy+=W,g.vx-=F,g.vy-=W}for(const o of s)o.vx-=o.x*Nn*e,o.vy-=o.y*Nn*e;const d=new Map;for(const o of s){const n=d.get(o.type)??{x:0,y:0,count:0};n.x+=o.x,n.y+=o.y,n.count++,d.set(o.type,n)}for(const o of d.values())o.x/=o.count,o.y/=o.count;for(const o of s){const n=d.get(o.type);o.vx+=(n.x-o.x)*Ze.clusterStrength*e,o.vy+=(n.y-o.y)*Ze.clusterStrength*e}for(const o of s){if(o.pinned){o.vx=0,o.vy=0;continue}o.vx*=Sn,o.vy*=Sn;const n=Math.sqrt(o.vx*o.vx+o.vy*o.vy);n>_t&&(o.vx=o.vx/n*_t,o.vy=o.vy/n*_t),o.x+=o.vx,o.y+=o.vy}return e*.995}const In=["#d4a27f","#c17856","#b07a5e","#d4956b","#a67c5a","#cc9e7c","#c4866a","#cb8e6c","#b8956e","#a88a70","#d9b08c","#c4a882","#e8b898","#b5927a","#a8886e","#d1a990"],Mn=new Map;function Ae(t){const e=Mn.get(t);if(e)return e;let s=0;for(let u=0;u<t.length;u++)s=(s<<5)-s+t.charCodeAt(u)|0;const l=In[Math.abs(s)%In.length];return Mn.set(t,l),l}class No{constructor(e){At(this,"cells",new Map);At(this,"cellSize");At(this,"invCell");this.cellSize=e,this.invCell=1/e}key(e,s){const l=e+32768|0,u=s+32768|0;return l*73856093^u*19349663}clear(){this.cells.clear()}insert(e){const s=Math.floor(e.x*this.invCell),l=Math.floor(e.y*this.invCell),u=this.key(s,l),r=this.cells.get(u);r?r.push(e):this.cells.set(u,[e])}rebuild(e){this.cells.clear();for(const s of e)this.insert(s)}query(e,s,l){const u=l*l,r=Math.floor((e-l)*this.invCell),d=Math.floor((e+l)*this.invCell),o=Math.floor((s-l)*this.invCell),n=Math.floor((s+l)*this.invCell);let g=null,i=u;for(let c=r;c<=d;c++)for(let T=o;T<=n;T++){const A=this.cells.get(this.key(c,T));if(A)for(const E of A){const F=E.x-e,W=E.y-s,V=F*F+W*W;V<=i&&(i=V,g=E)}}return g}}const pt=new Map,Lo=2e3;function Io(t,e,s){return`${t}|${e}|${s}`}const Mo=new OffscreenCanvas(1,1),Tn=Mo.getContext("2d");function To(t,e,s){Tn.font=e;const l=Tn.measureText(t),u=Math.ceil(l.width)+2,r=Math.ceil(l.actualBoundingBoxAscent+l.actualBoundingBoxDescent)+4,d=new OffscreenCanvas(u,r),o=d.getContext("2d");return o.font=e,o.fillStyle=s,o.textAlign="left",o.textBaseline="top",o.fillText(t,1,1),{canvas:d,width:u,height:r}}function An(t,e,s,l,u,r,d){const o=Io(e,u,r);let n=pt.get(o);if(!n){if(pt.size>=Lo){const c=pt.keys().next().value;c!==void 0&&pt.delete(c)}n=To(e,u,r),pt.set(o,n)}const g=s-n.width/2,i=d==="top"?l:l-n.height;t.drawImage(n.canvas,g,i)}function Ao(){pt.clear()}function we(t){return getComputedStyle(document.documentElement).getPropertyValue(t).trim()}const Ue=20,Yt=.001,Po={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15,dotNodes:.1,hullsOnly:.05},Ro={zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300};function Rt(t,e,s,l,u,r=100){const d=(t-s.x)*s.scale,o=(e-s.y)*s.scale;return d>=-r&&d<=l+r&&o>=-r&&o<=u+r}function Bo(t,e,s,l){const u={...Po,...(l==null?void 0:l.lod)??{}},r={...Ro,...(l==null?void 0:l.navigation)??{}},d={pulseSpeed:.02,...(l==null?void 0:l.walk)??{}},o=t.querySelector("canvas"),n=o.getContext("2d"),g=window.devicePixelRatio||1;let i={x:0,y:0,scale:1},c=null,T=1,A=0,E=new Set,F=null,W=!0,V=!0,_=!0,X=!0,Y="idle",K=[],q=0,me=0,U=null,pe=new Set;const Ee=5;let te=null,G=null,ye=1,Ce=null,se=null,ge=null,be=!1,p=[],y=0,C=0;const m=400,v=new No(Ue*2);let S=0;function h(){ce(),S||(S=requestAnimationFrame(()=>{S=0,Xe()}))}const I=150;let w=null,N=!1;function L(){if(!w)try{w=new Worker(new URL("/assets/layout-worker-4xak23M6.js",import.meta.url),{type:"module"}),w.onmessage=b,w.onerror=()=>{N=!1,w=null,j()}}catch{return N=!1,null}return w}function b(f){const k=f.data;if(k.type==="tick"&&c){const B=k.positions,D=c.nodes;for(let H=0;H<D.length;H++)D[H].x=B[H*4],D[H].y=B[H*4+1],D[H].vx=B[H*4+2],D[H].vy=B[H*4+3];T=k.alpha,v.rebuild(D),Xe()}k.type==="settled"&&(T=0,be&&p.length>0&&!a&&(a=requestAnimationFrame(x)))}let M=null,$=null,Q=!0;function ce(){Q=!0}let re=null,ue=null;const ve=r.panAnimationMs;function $e(){o.width=o.clientWidth*g,o.height=o.clientHeight*g,ce(),h()}const Qe=new ResizeObserver($e);Qe.observe(t),$e();function Re(f,k){return[f/i.scale+i.x,k/i.scale+i.y]}function et(f,k){if(!c)return null;const[B,D]=Re(f,k);return v.query(B,D,Ue)}function ct(){if(!U)return;n.save();const f=Math.min(U.x1,U.x2),k=Math.max(U.x1,U.x2),B=Math.min(U.y1,U.y2),D=Math.max(U.y1,U.y2);n.strokeStyle=we("--accent")||"#d4a27f",n.fillStyle=we("--accent")||"#d4a27f",n.globalAlpha=.12,n.fillRect(f,B,k-f,D-B),n.globalAlpha=.8,n.lineWidth=1/Math.max(i.scale,.5),n.setLineDash([6/Math.max(i.scale,.5),4/Math.max(i.scale,.5)]),n.strokeRect(f,B,k-f,D-B),n.setLineDash([]),n.restore()}function Ot(){if(!c)return;y+=d.pulseSpeed;const f=new Set(p);n.save(),n.setTransform(g,0,0,g,0,0),M&&(n.clearRect(0,0,o.clientWidth,o.clientHeight),n.drawImage(M,0,0,o.clientWidth,o.clientHeight)),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale);const k=we("--canvas-walk-edge")||"#1a1a1a",B=[];for(const z of c.edges){if(!f.has(z.sourceId)||!f.has(z.targetId)||z.sourceId===z.targetId)continue;const O=c.nodeMap.get(z.sourceId),J=c.nodeMap.get(z.targetId);!O||!J||B.push(O.x,O.y,J.x,J.y)}if(B.length>0){n.beginPath();for(let z=0;z<B.length;z+=4)n.moveTo(B[z],B[z+1]),n.lineTo(B[z+2],B[z+3]);n.strokeStyle=k,n.lineWidth=3,n.globalAlpha=.5+.5*Math.sin(y),n.stroke(),n.globalAlpha=1}const D=i.scale<u.smallNodes?Ue*.5:Ue,H=we("--accent")||"#d4a27f";for(const z of p){const O=c.nodeMap.get(z);if(!O||!Rt(O.x,O.y,i,o.clientWidth,o.clientHeight))continue;const J=z===p[p.length-1],Z=.5+.5*Math.sin(y);n.strokeStyle=H,n.lineWidth=J?3:2,n.globalAlpha=J?.5+.5*Z:.3+.4*Z,n.beginPath(),n.arc(O.x,O.y,D+(J?6:4),0,Math.PI*2),n.stroke()}n.globalAlpha=1,ct(),n.restore(),X&&c.nodes.length>1&&Wt(),n.restore()}function Xe(){var ln;if(!c){n.clearRect(0,0,o.width,o.height);return}if(!Q&&M&&be&&p.length>0&&T<Yt){Ot();return}const f=T<Yt&&be&&p.length>0;be&&p.length>0&&(y+=d.pulseSpeed);const k=be&&!f?new Set(p):null,B=we("--canvas-edge"),D=we("--canvas-edge-highlight"),H=we("--canvas-edge-dim"),z=we("--canvas-edge-label"),O=we("--canvas-edge-label-highlight"),J=we("--canvas-edge-label-dim"),Z=we("--canvas-arrow"),le=we("--canvas-arrow-highlight"),fe=we("--canvas-node-label"),ke=we("--canvas-node-label-dim"),Se=we("--canvas-type-badge"),Te=we("--canvas-type-badge-dim"),Be=we("--canvas-selection-border"),je=we("--canvas-node-border");if(n.save(),n.setTransform(g,0,0,g,0,0),n.clearRect(0,0,o.clientWidth,o.clientHeight),n.save(),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),_&&i.scale>=u.smallNodes){const ee=new Map;for(const Pe of c.nodes){if(F!==null&&!F.has(Pe.id))continue;const Oe=ee.get(Pe.type)??[];Oe.push(Pe),ee.set(Pe.type,Oe)}for(const[Pe,Oe]of ee){if(Oe.length<2)continue;const st=Ae(Pe),nt=Ue*2.5;let He=1/0,qe=1/0,Fe=-1/0,Ke=-1/0;for(const We of Oe)We.x<He&&(He=We.x),We.y<qe&&(qe=We.y),We.x>Fe&&(Fe=We.x),We.y>Ke&&(Ke=We.y);n.beginPath();const oe=(Fe-He)/2+nt,Ie=(Ke-qe)/2+nt,Ne=(He+Fe)/2,ze=(qe+Ke)/2;n.ellipse(Ne,ze,oe,Ie,0,0,Math.PI*2),n.fillStyle=st,n.globalAlpha=.05,n.fill(),n.strokeStyle=st,n.globalAlpha=.12,n.lineWidth=1,n.setLineDash([4,4]),n.stroke(),n.setLineDash([]),n.globalAlpha=1}}let Ye=null;if(E.size>0){Ye=new Set;for(const ee of c.edges)E.has(ee.sourceId)&&Ye.add(ee.targetId),E.has(ee.targetId)&&Ye.add(ee.sourceId)}const tt=we("--accent")||"#d4a27f",_e=we("--canvas-walk-edge")||"#1a1a1a",it=i.scale>=u.hideArrows,Mt=V&&i.scale>=u.hideEdgeLabels;if(W){const ee=[],Pe=[],Oe=[],st=[],nt=[],He=[];for(const oe of c.edges){const Ie=c.nodeMap.get(oe.sourceId),Ne=c.nodeMap.get(oe.targetId);if(!Ie||!Ne||!Rt(Ie.x,Ie.y,i,o.clientWidth,o.clientHeight,200)&&!Rt(Ne.x,Ne.y,i,o.clientWidth,o.clientHeight,200))continue;const ze=F===null||F.has(oe.sourceId),We=F===null||F.has(oe.targetId),rn=ze&&We;if(F!==null&&!ze&&!We)continue;const jt=E.size>0&&(E.has(oe.sourceId)||E.has(oe.targetId))||F!==null&&rn,dn=F!==null&&!rn,pn=k!==null&&k.has(oe.sourceId)&&k.has(oe.targetId),un=ge?te==null?void 0:te.edges.find(Tt=>Tt.sourceId===oe.sourceId&&Tt.targetId===oe.targetId||Tt.targetId===oe.sourceId&&Tt.sourceId===oe.targetId):null,mn=!!(ge&&un&&ge.edgeIds.has(un.id));if(oe.sourceId===oe.targetId){St(Ie,oe.type,jt,B,D,z,O);continue}(mn?nt:pn?st:jt?Pe:dn?Oe:ee).push(Ie.x,Ie.y,Ne.x,Ne.y),(it||Mt)&&He.push({sx:Ie.x,sy:Ie.y,tx:Ne.x,ty:Ne.y,type:oe.type,highlighted:jt,edgeDimmed:dn,isPathEdge:mn,isWalkEdge:pn})}const qe=it?1.5:1,Ke=[{lines:ee,color:B,width:qe,alpha:1},{lines:Oe,color:H,width:qe,alpha:1},{lines:Pe,color:D,width:it?2.5:1,alpha:1},{lines:nt,color:tt,width:3,alpha:1},{lines:st,color:_e,width:3,alpha:.5+.5*Math.sin(y)}];for(const oe of Ke)if(oe.lines.length!==0){n.beginPath();for(let Ie=0;Ie<oe.lines.length;Ie+=4)n.moveTo(oe.lines[Ie],oe.lines[Ie+1]),n.lineTo(oe.lines[Ie+2],oe.lines[Ie+3]);n.strokeStyle=oe.color,n.lineWidth=oe.width,n.globalAlpha=oe.alpha,n.stroke()}n.globalAlpha=1;for(const oe of He)if(it&&ut(oe.sx,oe.sy,oe.tx,oe.ty,oe.highlighted||oe.isPathEdge,Z,le),Mt){const Ie=(oe.sx+oe.tx)/2,Ne=(oe.sy+oe.ty)/2;n.fillStyle=oe.highlighted?O:oe.edgeDimmed?J:z,n.font="9px system-ui, sans-serif",n.textAlign="center",n.textBaseline="bottom",n.fillText(oe.type,Ie,Ne-4)}}const Ut=performance.now()-C,Le=Math.min(1,Ut/m),Ve=1-(1-Le)*(1-Le),Je=Le<1,cn=i.scale<u.hullsOnly,Vn=!cn&&i.scale<u.dotNodes;if(!cn)for(const ee of c.nodes){if(!Rt(ee.x,ee.y,i,o.clientWidth,o.clientHeight))continue;const Pe=Ae(ee.type);if(Vn){const Ne=F!==null&&!F.has(ee.id);n.fillStyle=Pe;const ze=Ne?.1:.8;n.globalAlpha=Je?ze*Ve:ze,n.fillRect(ee.x-2,ee.y-2,4,4);continue}const Oe=E.has(ee.id),st=Ye!==null&&Ye.has(ee.id),nt=F!==null&&!F.has(ee.id),He=nt||E.size>0&&!Oe&&!st,qe=i.scale<u.smallNodes?Ue*.5:Ue,Fe=Je?qe*Ve:qe;if(k!=null&&k.has(ee.id)){const Ne=p[p.length-1]===ee.id,ze=.5+.5*Math.sin(y),We=we("--accent")||"#d4a27f";n.save(),n.strokeStyle=We,n.lineWidth=Ne?3:2,n.globalAlpha=Ne?.5+.5*ze:.3+.4*ze,n.beginPath(),n.arc(ee.x,ee.y,Fe+(Ne?6:4),0,Math.PI*2),n.stroke(),n.restore()}Oe&&(n.save(),n.shadowColor=Pe,n.shadowBlur=20,n.beginPath(),n.arc(ee.x,ee.y,Fe+3,0,Math.PI*2),n.fillStyle=Pe,n.globalAlpha=.3,n.fill(),n.restore()),n.beginPath(),n.arc(ee.x,ee.y,Fe,0,Math.PI*2),n.fillStyle=Pe;const Ke=nt?.1:He?.3:1;n.globalAlpha=Je?Ke*Ve:Ke,n.fill(),n.strokeStyle=Oe?Be:je,n.lineWidth=Oe?3:1.5,n.stroke(),n.globalAlpha=1,ee.pinned&&(n.save(),n.strokeStyle=je,n.globalAlpha=.55,n.lineWidth=1,n.setLineDash([3,3]),n.beginPath(),n.arc(ee.x,ee.y,Fe+4,0,Math.PI*2),n.stroke(),n.setLineDash([]),n.restore()),ge&&ge.nodeIds.has(ee.id)&&!Oe&&(n.save(),n.shadowColor=we("--accent")||"#d4a27f",n.shadowBlur=15,n.beginPath(),n.arc(ee.x,ee.y,Fe+2,0,Math.PI*2),n.strokeStyle=we("--accent")||"#d4a27f",n.globalAlpha=.5,n.lineWidth=2,n.stroke(),n.restore());const oe=te==null?void 0:te.nodes.find(Ne=>Ne.id===ee.id);if(((ln=oe==null?void 0:oe.properties)==null?void 0:ln._starred)===!0&&(n.fillStyle="#ffd700",n.font="10px system-ui, sans-serif",n.textAlign="left",n.textBaseline="bottom",n.fillText("★",ee.x+Fe-2,ee.y-Fe+2)),i.scale>=u.hideLabels){const Ne=ee.label.length>24?ee.label.slice(0,22)+"...":ee.label,ze=He?ke:fe;An(n,Ne,ee.x,ee.y+Fe+4,"11px system-ui, sans-serif",ze,"top")}if(i.scale>=u.hideBadges){const Ne=He?Te:Se;An(n,ee.type,ee.x,ee.y-Fe-3,"9px system-ui, sans-serif",Ne,"bottom")}n.globalAlpha=1}if(n.restore(),n.restore(),f){const ee=o.width,Pe=o.height;(!M||M.width!==ee||M.height!==Pe)&&(M=new OffscreenCanvas(ee,Pe),$=M.getContext("2d")),$&&($.clearRect(0,0,ee,Pe),$.drawImage(o,0,0),Q=!1),Ot();return}X&&c.nodes.length>1&&Wt(),U&&(n.save(),n.setTransform(g,0,0,g,0,0),n.translate(-i.x*i.scale,-i.y*i.scale),n.scale(i.scale,i.scale),ct(),n.restore())}function Wt(){if(!c)return;const f=140,k=100,B=8,D=o.clientWidth-f-16,H=o.clientHeight-k-16;let z=1/0,O=1/0,J=-1/0,Z=-1/0;for(const Le of c.nodes)Le.x<z&&(z=Le.x),Le.y<O&&(O=Le.y),Le.x>J&&(J=Le.x),Le.y>Z&&(Z=Le.y);const le=J-z||1,fe=Z-O||1,ke=Math.min((f-B*2)/le,(k-B*2)/fe),Se=D+B+(f-B*2-le*ke)/2,Te=H+B+(k-B*2-fe*ke)/2;n.save(),n.setTransform(g,0,0,g,0,0),n.fillStyle=we("--bg-surface")||"#1a1a1a",n.globalAlpha=.85,n.beginPath(),n.roundRect(D,H,f,k,8),n.fill(),n.strokeStyle=we("--border")||"#2a2a2a",n.globalAlpha=1,n.lineWidth=1,n.stroke(),n.globalAlpha=.15,n.strokeStyle=we("--canvas-edge")||"#555",n.lineWidth=.5;for(const Le of c.edges){const Ve=c.nodeMap.get(Le.sourceId),Je=c.nodeMap.get(Le.targetId);!Ve||!Je||Le.sourceId===Le.targetId||(n.beginPath(),n.moveTo(Se+(Ve.x-z)*ke,Te+(Ve.y-O)*ke),n.lineTo(Se+(Je.x-z)*ke,Te+(Je.y-O)*ke),n.stroke())}n.globalAlpha=.8;for(const Le of c.nodes){const Ve=Se+(Le.x-z)*ke,Je=Te+(Le.y-O)*ke;n.beginPath(),n.arc(Ve,Je,2,0,Math.PI*2),n.fillStyle=Ae(Le.type),n.fill()}const Be=i.x,je=i.y,Ye=i.x+o.clientWidth/i.scale,tt=i.y+o.clientHeight/i.scale,_e=Se+(Be-z)*ke,it=Te+(je-O)*ke,Mt=(Ye-Be)*ke,Ut=(tt-je)*ke;n.globalAlpha=.3,n.strokeStyle=we("--accent")||"#d4a27f",n.lineWidth=1.5,n.strokeRect(Math.max(D,Math.min(_e,D+f)),Math.max(H,Math.min(it,H+k)),Math.min(Mt,f),Math.min(Ut,k)),n.globalAlpha=1,n.restore()}function ut(f,k,B,D,H,z,O){const J=Math.atan2(D-k,B-f),Z=B-Math.cos(J)*Ue,le=D-Math.sin(J)*Ue,fe=8;n.beginPath(),n.moveTo(Z,le),n.lineTo(Z-fe*Math.cos(J-.4),le-fe*Math.sin(J-.4)),n.lineTo(Z-fe*Math.cos(J+.4),le-fe*Math.sin(J+.4)),n.closePath(),n.fillStyle=H?O:z,n.fill()}function St(f,k,B,D,H,z,O){const J=f.x+Ue+15,Z=f.y-Ue-15;n.beginPath(),n.arc(J,Z,15,0,Math.PI*2),n.strokeStyle=B?H:D,n.lineWidth=B?2.5:1.5,n.stroke(),V&&(n.fillStyle=B?O:z,n.font="9px system-ui, sans-serif",n.textAlign="center",n.fillText(k,J,Z-18))}function mt(){if(!re||!ue)return;const f=performance.now()-ue.time,k=Math.min(f/ve,1),B=1-Math.pow(1-k,3);i.x=ue.x+(re.x-ue.x)*B,i.y=ue.y+(re.y-ue.y)*B,ce(),Xe(),k<1?requestAnimationFrame(mt):(re=null,ue=null)}let a=0;function x(){if(!be||p.length===0){a=0;return}Xe(),a=requestAnimationFrame(x)}function R(){if(!c||c.nodes.length===0)return;let f=1/0,k=1/0,B=-1/0,D=-1/0;for(const le of c.nodes)le.x<f&&(f=le.x),le.y<k&&(k=le.y),le.x>B&&(B=le.x),le.y>D&&(D=le.y);const H=Ue*4,z=B-f+H*2,O=D-k+H*2,J=o.clientWidth/Math.max(z,1),Z=o.clientHeight/Math.max(O,1);i.scale=Math.min(J,Z,2),i.x=(f+B)/2-o.clientWidth/(2*i.scale),i.y=(k+D)/2-o.clientHeight/(2*i.scale),h()}function j(){if(!c||T<Yt){A=0,be&&p.length>0&&!a&&(a=requestAnimationFrame(x));return}T=So(c,T),v.rebuild(c.nodes),Xe(),A=requestAnimationFrame(j)}let ne=!1,de=0,ie=0,he=0,Me=0;o.addEventListener("mousedown",f=>{Y="pending",ne=!1,de=f.clientX,ie=f.clientY,he=f.clientX,Me=f.clientY;const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,H=et(B,D);if(H&&!be){if(K=[],E.has(H.id)&&E.size>1)for(const J of E){const Z=c==null?void 0:c.nodeMap.get(J);Z&&K.push({node:Z,startX:Z.x,startY:Z.y})}else K.push({node:H,startX:H.x,startY:H.y});const[z,O]=Re(B,D);q=z,me=O}else if(!H&&f.shiftKey){const[z,O]=Re(B,D);U={x1:z,y1:O,x2:z,y2:O}}}),o.addEventListener("mousemove",f=>{if(Y==="idle")return;const k=f.clientX-de,B=f.clientY-ie,D=Math.abs(f.clientX-he),H=Math.abs(f.clientY-Me);if(Y==="pending"&&(D>Ee||H>Ee)&&(ne=!0,K.length>0?(Y="nodeDrag",N&&w&&w.postMessage({type:"stop"})):U?Y="rubberBand":Y="pan"),Y==="nodeDrag"){const z=o.getBoundingClientRect(),O=f.clientX-z.left,J=f.clientY-z.top,[Z,le]=Re(O,J),fe=Z-q,ke=le-me;for(const Se of K)Se.node.x=Se.startX+fe,Se.node.y=Se.startY+ke,Se.node.vx=0,Se.node.vy=0,Se.node.pinned=!0,pe.add(Se.node.id);v.rebuild((c==null?void 0:c.nodes)??[]),h()}else if(Y==="rubberBand"&&U){const z=o.getBoundingClientRect(),O=f.clientX-z.left,J=f.clientY-z.top,[Z,le]=Re(O,J);U.x2=Z,U.y2=le,h()}else Y==="pan"&&(i.x-=k/i.scale,i.y-=B/i.scale,h());de=f.clientX,ie=f.clientY}),o.addEventListener("mouseup",f=>{const k=Y==="nodeDrag",B=Y==="rubberBand";if(K.map(Z=>Z.node.id),k){if(N&&w&&c){const Z=K.map(le=>({id:le.node.id,x:le.node.x,y:le.node.y}));w.postMessage({type:"pin",updates:Z}),w.postMessage({type:"resume",alpha:.5})}else T=Math.max(T,.5),A||j();Y="idle",K=[],h();return}if(B&&U&&c){const Z=Math.min(U.x1,U.x2),le=Math.max(U.x1,U.x2),fe=Math.min(U.y1,U.y2),ke=Math.max(U.y1,U.y2);f.shiftKey||E.clear();for(const Te of c.nodes)Te.x>=Z&&Te.x<=le&&Te.y>=fe&&Te.y<=ke&&E.add(Te.id);const Se=[...E];e==null||e(Se.length>0?Se:null),U=null,Y="idle",h();return}if(Y==="pan"){Y="idle";return}if(Y="idle",U=null,ne)return;const D=o.getBoundingClientRect(),H=f.clientX-D.left,z=f.clientY-D.top,O=et(H,z),J=f.ctrlKey||f.metaKey||f.shiftKey;if(be&&G&&O&&c){const Z=p.length>0?p[p.length-1]:G[0],le=new Set([Z]),fe=[{id:Z,path:[Z]}];let ke=null;for(;fe.length>0;){const{id:je,path:Ye}=fe.shift();if(je===O.id){ke=Ye;break}for(const tt of c.edges){let _e=null;tt.sourceId===je?_e=tt.targetId:tt.targetId===je&&(_e=tt.sourceId),_e&&!le.has(_e)&&(le.add(_e),fe.push({id:_e,path:[...Ye,_e]}))}}if(!ke)return;for(const je of ke.slice(1))p.includes(je)||p.push(je);G=[O.id];const Se=Math.max(1,ye);ye=Se;const Te=Ln(te,[O.id],Se);cancelAnimationFrame(A),w&&w.postMessage({type:"stop"}),c=Ht(Te),v.rebuild(c.nodes),T=1,E=new Set([O.id]),F=null,i={x:0,y:0,scale:1},N=Te.nodes.length>=I;const Be=N?L():null;Be?Be.postMessage({type:"start",data:Te}):(N=!1,j()),setTimeout(()=>{c&&R()},300),s==null||s({seedNodeIds:[O.id],hops:Se,totalNodes:Te.nodes.length}),e==null||e([O.id]);return}if(O){J?E.has(O.id)?E.delete(O.id):E.add(O.id):E.size===1&&E.has(O.id)?E.clear():(E.clear(),E.add(O.id));const Z=[...E];e==null||e(Z.length>0?Z:null)}else E.clear(),e==null||e(null);h()}),o.addEventListener("mouseleave",()=>{if(Y==="nodeDrag")if(N&&w&&K.length>0){const f=K.map(k=>({id:k.node.id,x:k.node.x,y:k.node.y}));w.postMessage({type:"pin",updates:f}),w.postMessage({type:"resume",alpha:.5})}else T=Math.max(T,.5),A||j();Y==="rubberBand"&&(U=null,h()),Y="idle",K=[]}),o.addEventListener("wheel",f=>{f.preventDefault();const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,[H,z]=Re(B,D),O=f.ctrlKey?1-f.deltaY*.01:f.deltaY>0?.9:1.1;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*O)),i.x=H-B/i.scale,i.y=z-D/i.scale,h()},{passive:!1});let xe=[],Ge=0,Nt=1,ht=0,Lt=0,ft=!1;o.addEventListener("touchstart",f=>{f.preventDefault(),xe=Array.from(f.touches),xe.length===2?(Ge=an(xe[0],xe[1]),Nt=i.scale):xe.length===1&&(de=xe[0].clientX,ie=xe[0].clientY,ht=xe[0].clientX,Lt=xe[0].clientY,ft=!1)},{passive:!1}),o.addEventListener("touchmove",f=>{f.preventDefault();const k=Array.from(f.touches);if(k.length===2&&xe.length===2){const D=an(k[0],k[1])/Ge;i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,Nt*D)),h()}else if(k.length===1){const B=k[0].clientX-de,D=k[0].clientY-ie;(Math.abs(k[0].clientX-ht)>10||Math.abs(k[0].clientY-Lt)>10)&&(ft=!0),i.x-=B/i.scale,i.y-=D/i.scale,de=k[0].clientX,ie=k[0].clientY,h()}xe=k},{passive:!1}),o.addEventListener("touchend",f=>{if(f.preventDefault(),ft||f.changedTouches.length!==1)return;const k=f.changedTouches[0],B=o.getBoundingClientRect(),D=k.clientX-B.left,H=k.clientY-B.top,z=et(D,H);if(z){E.size===1&&E.has(z.id)?E.clear():(E.clear(),E.add(z.id));const O=[...E];e==null||e(O.length>0?O:null)}else E.clear(),e==null||e(null);h()},{passive:!1}),o.addEventListener("gesturestart",f=>f.preventDefault()),o.addEventListener("gesturechange",f=>f.preventDefault());function an(f,k){const B=f.clientX-k.clientX,D=f.clientY-k.clientY;return Math.sqrt(B*B+D*D)}const gt=document.createElement("div");gt.className="zoom-controls";const yt=document.createElement("button");yt.className="zoom-btn",yt.textContent="+",yt.title="Zoom in",yt.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[B,D]=Re(f,k);i.scale=Math.min(r.zoomMax,i.scale*r.zoomFactor),i.x=B-f/i.scale,i.y=D-k/i.scale,h()});const Ct=document.createElement("button");Ct.className="zoom-btn",Ct.textContent="−",Ct.title="Zoom out",Ct.addEventListener("click",()=>{const f=o.clientWidth/2,k=o.clientHeight/2,[B,D]=Re(f,k);i.scale=Math.max(r.zoomMin,i.scale/r.zoomFactor),i.x=B-f/i.scale,i.y=D-k/i.scale,h()});const bt=document.createElement("button");bt.className="zoom-btn",bt.textContent="○",bt.title="Reset zoom",bt.addEventListener("click",()=>{if(c){if(i={x:0,y:0,scale:1},c.nodes.length>0){let f=1/0,k=1/0,B=-1/0,D=-1/0;for(const O of c.nodes)O.x<f&&(f=O.x),O.y<k&&(k=O.y),O.x>B&&(B=O.x),O.y>D&&(D=O.y);const H=(f+B)/2,z=(k+D)/2;i.x=H-o.clientWidth/2,i.y=z-o.clientHeight/2}h()}}),gt.appendChild(yt),gt.appendChild(bt),gt.appendChild(Ct),t.appendChild(gt);const De=document.createElement("div");De.className="node-tooltip",De.style.display="none",t.appendChild(De);let It=null,ot=null;return o.addEventListener("mousemove",f=>{if(Y!=="idle"&&Y!=="pending"){De.style.display!=="none"&&(De.style.display="none",It=null);return}const k=o.getBoundingClientRect(),B=f.clientX-k.left,D=f.clientY-k.top,H=et(B,D),z=(H==null?void 0:H.id)??null;z!==It?(It=z,De.style.display="none",ot&&clearTimeout(ot),ot=null,z&&H&&(ot=setTimeout(()=>{if(!c||!te)return;const O=c.edges.filter(J=>J.sourceId===z||J.targetId===z).length;De.textContent=`${H.label} · ${H.type} · ${O} edge${O!==1?"s":""}`,De.style.left=`${f.clientX-k.left+12}px`,De.style.top=`${f.clientY-k.top-8}px`,De.style.display="block"},200))):z&&De.style.display==="block"&&(De.style.left=`${f.clientX-k.left+12}px`,De.style.top=`${f.clientY-k.top-8}px`)}),o.addEventListener("mouseleave",()=>{De.style.display="none",It=null,ot&&clearTimeout(ot),ot=null}),{loadGraph(f){if(cancelAnimationFrame(A),w&&w.postMessage({type:"stop"}),Ao(),te=f,G=null,Ce=null,se=null,C=performance.now(),c=Ht(f),v.rebuild(c.nodes),T=1,E=new Set,F=null,pe.clear(),Y="idle",K=[],U=null,i={x:0,y:0,scale:1},c.nodes.length>0){let B=1/0,D=1/0,H=-1/0,z=-1/0;for(const fe of c.nodes)fe.x<B&&(B=fe.x),fe.y<D&&(D=fe.y),fe.x>H&&(H=fe.x),fe.y>z&&(z=fe.y);const O=(B+H)/2,J=(D+z)/2,Z=o.clientWidth,le=o.clientHeight;i.x=O-Z/2,i.y=J-le/2}N=f.nodes.length>=I;const k=N?L():null;k?k.postMessage({type:"start",data:f}):(N=!1,j())},setFilteredNodeIds(f){F=f,h()},releaseAllPins(){if(!c)return!1;let f=!1;for(const k of c.nodes)k.pinned&&(f=!0,k.pinned=!1);return pe.clear(),Y="idle",K=[],U=null,f&&(N&&w?w.postMessage({type:"unpin",ids:"all"}):(T=Math.max(T,.5),A||j()),h()),f},hasPinnedNodes(){if(!c)return!1;for(const f of c.nodes)if(f.pinned)return!0;return!1},clearSelection(){E.size!==0&&(E.clear(),e==null||e(null),h())},getSelectedNodeIds(){return[...E]},panToNode(f){this.panToNodes([f])},panToNodes(f){if(!c||f.length===0)return;const k=f.map(H=>c.nodeMap.get(H)).filter(Boolean);if(k.length===0)return;E=new Set(f),e==null||e(f);const B=o.clientWidth,D=o.clientHeight;if(k.length===1)ue={x:i.x,y:i.y,time:performance.now()},re={x:k[0].x-B/(2*i.scale),y:k[0].y-D/(2*i.scale)};else{let H=1/0,z=1/0,O=-1/0,J=-1/0;for(const Be of k)Be.x<H&&(H=Be.x),Be.y<z&&(z=Be.y),Be.x>O&&(O=Be.x),Be.y>J&&(J=Be.y);const Z=Ue*4,le=O-H+Z*2,fe=J-z+Z*2,ke=Math.min(B/le,D/fe,i.scale);i.scale=ke;const Se=(H+O)/2,Te=(z+J)/2;ue={x:i.x,y:i.y,time:performance.now()},re={x:Se-B/(2*i.scale),y:Te-D/(2*i.scale)}}mt()},setEdges(f){W=f,h()},setEdgeLabels(f){V=f,h()},setTypeHulls(f){_=f,h()},setMinimap(f){X=f,h()},centerView(){R()},panBy(f,k){i.x+=f/i.scale,i.y+=k/i.scale,h()},zoomBy(f){const k=o.clientWidth/2,B=o.clientHeight/2,[D,H]=Re(k,B);i.scale=Math.max(r.zoomMin,Math.min(r.zoomMax,i.scale*f)),i.x=D-k/i.scale,i.y=H-B/i.scale,h()},reheat(){N&&w?w.postMessage({type:"params",params:wt()}):(T=.5,cancelAnimationFrame(A),j())},exportImage(f){if(!c)return"";const k=o.width,B=o.height;if(f==="png"){const O=document.createElement("canvas");O.width=k,O.height=B;const J=O.getContext("2d");return J.fillStyle=we("--bg")||"#141414",J.fillRect(0,0,k,B),J.drawImage(o,0,0),Gn(J,k,B),O.toDataURL("image/png")}const D=o.toDataURL("image/png"),H=Math.max(16,Math.round(k/80)),z=`<svg xmlns="http://www.w3.org/2000/svg" width="${k}" height="${B}">
3
3
  <image href="${D}" width="${k}" height="${B}"/>
4
4
  <text x="${k-20}" y="${B-16}" text-anchor="end" font-family="system-ui, sans-serif" font-size="${H}" fill="#ffffff" opacity="0.4">backpackontology.com</text>
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Backpack Viewer</title>
7
- <script type="module" crossorigin src="/assets/index-Cf-ZlsIA.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-D5fMGKMe.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-BbX2AsyK.css">
9
9
  </head>
10
10
  <body>
@@ -18,7 +18,8 @@ function N(e) {
18
18
  const n = document.createElement("div");
19
19
  n.className = "share-panel-body", m ? (m.element.replaceChildren(), m.element.appendChild(n), m.setTitle(`Share "${t}"`), m.setVisible(!0), m.bringToFront()) : (n.textContent = "Loading...", m = e.mountPanel(n, {
20
20
  title: `Share "${t}"`,
21
- defaultPosition: { left: window.innerWidth - 420, top: 80 },
21
+ defaultPosition: { left: Math.max(100, (window.innerWidth - 380) / 2), top: Math.max(80, (window.innerHeight - 400) / 2) },
22
+ persistKey: "share-v2",
22
23
  showFullscreenButton: !1,
23
24
  onClose: () => {
24
25
  m = null;
@@ -27,7 +28,7 @@ function N(e) {
27
28
  }
28
29
  async function w(e, t) {
29
30
  const n = await e.settings.get("relay_token");
30
- t.replaceChildren(), n ? v(e, t, n) : A(e, t);
31
+ t.replaceChildren(), n ? T(e, t, n) : A(e, t);
31
32
  }
32
33
  function A(e, t) {
33
34
  const n = document.createElement("div");
@@ -36,7 +37,7 @@ function A(e, t) {
36
37
  <p>Encrypt your graph and get a shareable link. Recipients open it in their browser — no install needed. Your data stays encrypted on our servers.</p>
37
38
  `;
38
39
  const a = document.createElement("button");
39
- a.className = "share-cta-btn", a.textContent = "Sign in to share", a.addEventListener("click", () => T(e, t)), n.appendChild(a);
40
+ a.className = "share-cta-btn", a.textContent = "Sign in to share", a.addEventListener("click", () => v(e, t)), n.appendChild(a);
40
41
  const o = document.createElement("button");
41
42
  o.className = "share-token-link", o.textContent = "Or paste an API token", o.addEventListener("click", () => P(e, t)), n.appendChild(o);
42
43
  const i = document.createElement("p");
@@ -59,7 +60,7 @@ function P(e, t) {
59
60
  const l = document.createElement("button");
60
61
  l.className = "share-btn-secondary", l.textContent = "Back", l.addEventListener("click", () => w(e, t)), i.appendChild(l), n.appendChild(i), t.replaceChildren(n);
61
62
  }
62
- async function T(e, t) {
63
+ async function v(e, t) {
63
64
  try {
64
65
  const a = await (await fetch(x)).json(), i = await (await fetch(a.registration_endpoint, { method: "POST" })).json(), d = B(), l = await $(d), c = window.location.origin + "/oauth/callback", r = crypto.randomUUID(), s = new URL(a.authorization_endpoint);
65
66
  s.searchParams.set("client_id", i.client_id), s.searchParams.set("redirect_uri", c), s.searchParams.set("response_type", "code"), s.searchParams.set("code_challenge", l), s.searchParams.set("code_challenge_method", "S256"), s.searchParams.set("state", r), s.searchParams.has("scope") || s.searchParams.set("scope", "openid email profile offline_access"), sessionStorage.setItem("share_oauth_state", r);
@@ -87,7 +88,7 @@ async function T(e, t) {
87
88
  a.className = "share-error", a.textContent = `Auth failed: ${n.message}`, t.appendChild(a);
88
89
  }
89
90
  }
90
- function v(e, t, n) {
91
+ function T(e, t, n) {
91
92
  const a = document.createElement("div");
92
93
  a.className = "share-form";
93
94
  const o = document.createElement("label");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backpack-viewer",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "description": "Web-based graph visualizer for backpack-ontology — Canvas 2D, force-directed layout, live reload",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Noah Irzinger",