convex-mcp-visual 1.0.8 → 1.0.10

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.
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <meta name="theme-color" content="#faf8f5">
7
7
  <title>Realtime Dashboard - Convex MCP Apps</title>
8
- <script type="module" crossorigin src="../../assets/realtime-dashboard-BPA99DZn.js"></script>
8
+ <script type="module" crossorigin src="../../assets/realtime-dashboard-BKgb9FSM.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="../../assets/modulepreload-polyfill-B5Qt9EMX.js">
10
10
  <link rel="stylesheet" crossorigin href="../../assets/style-BTxSpbLq.css">
11
11
  </head>
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <meta name="theme-color" content="#faf8f5">
7
7
  <title>Schema Browser - Convex MCP Apps</title>
8
- <script type="module" crossorigin src="../../assets/schema-browser-BEcF8hRP.js"></script>
8
+ <script type="module" crossorigin src="../../assets/schema-browser-DIJDjZTI.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="../../assets/modulepreload-polyfill-B5Qt9EMX.js">
10
10
  <link rel="stylesheet" crossorigin href="../../assets/style-BTxSpbLq.css">
11
11
  </head>
@@ -1,4 +1,4 @@
1
- var h=Object.defineProperty;var m=(o,e,t)=>e in o?h(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var d=(o,e,t)=>m(o,typeof e!="symbol"?e+"":e,t);import"./modulepreload-polyfill-B5Qt9EMX.js";class p{constructor(){d(this,"config",null);d(this,"refreshTimer",null);d(this,"isConnected",!0);d(this,"currentTheme","light");this.init()}init(){var e;if(this.initTheme(),window.__CONVEX_CONFIG__)this.config=window.__CONVEX_CONFIG__;else{const s=new URLSearchParams(window.location.search).get("config");if(s)try{this.config=JSON.parse(decodeURIComponent(s))}catch(r){console.error("Failed to parse config:",r)}}this.isConnected=!!((e=this.config)!=null&&e.deploymentUrl),this.render(),this.startAutoRefresh()}initTheme(){const e=localStorage.getItem("convex-dashboard-theme");e?this.currentTheme=e:window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches&&(this.currentTheme="light"),this.applyTheme()}applyTheme(){document.documentElement.setAttribute("data-theme",this.currentTheme),localStorage.setItem("convex-dashboard-theme",this.currentTheme)}toggleTheme(){this.currentTheme=this.currentTheme==="light"?"dark":"light",this.applyTheme();const e=document.getElementById("themeIcon");e&&(e.textContent=this.currentTheme==="light"?"":"")}render(){var r;const e=document.getElementById("app");if(!e)return;const t=((r=this.config)==null?void 0:r.deploymentUrl)||"Not connected";e.innerHTML=`
1
+ var h=Object.defineProperty;var m=(o,e,t)=>e in o?h(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var d=(o,e,t)=>m(o,typeof e!="symbol"?e+"":e,t);import"./modulepreload-polyfill-B5Qt9EMX.js";class v{constructor(){d(this,"config",null);d(this,"refreshTimer",null);d(this,"isConnected",!0);d(this,"currentTheme","light");this.init()}init(){var e;if(this.initTheme(),window.__CONVEX_CONFIG__)this.config=window.__CONVEX_CONFIG__;else{const s=new URLSearchParams(window.location.search).get("config");if(s)try{this.config=JSON.parse(decodeURIComponent(s))}catch(r){console.error("Failed to parse config:",r)}}this.isConnected=!!((e=this.config)!=null&&e.deploymentUrl),this.render(),this.startAutoRefresh()}initTheme(){const e=localStorage.getItem("convex-dashboard-theme");e?this.currentTheme=e:window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches&&(this.currentTheme="light"),this.applyTheme()}applyTheme(){document.documentElement.setAttribute("data-theme",this.currentTheme),localStorage.setItem("convex-dashboard-theme",this.currentTheme)}toggleTheme(){this.currentTheme=this.currentTheme==="light"?"dark":"light",this.applyTheme();const e=document.getElementById("themeIcon");e&&(e.innerHTML=this.currentTheme==="light"?'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>':'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>')}render(){var r;const e=document.getElementById("app");if(!e)return;const t=((r=this.config)==null?void 0:r.deploymentUrl)||"Not connected";e.innerHTML=`
2
2
  <div class="header">
3
3
  <h1>
4
4
  <span class="status-dot ${this.isConnected?"":"disconnected"}" id="statusDot"></span>
@@ -8,7 +8,7 @@ var h=Object.defineProperty;var m=(o,e,t)=>e in o?h(o,e,{enumerable:!0,configura
8
8
  <span class="deployment-url">${t}</span>
9
9
  <span class="last-update" id="lastUpdate"></span>
10
10
  <button class="theme-toggle-btn" id="themeToggle" title="Toggle dark mode">
11
- <span id="themeIcon">${this.currentTheme==="light"?"":""}</span>
11
+ <span id="themeIcon">${this.currentTheme==="light"?'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>':'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>'}</span>
12
12
  </button>
13
13
  </div>
14
14
  </div>
@@ -35,17 +35,17 @@ var h=Object.defineProperty;var m=(o,e,t)=>e in o?h(o,e,{enumerable:!0,configura
35
35
  </div>
36
36
  <div class="metric-source">${r.table} / ${r.aggregation}${r.field?`(${r.field})`:""}</div>
37
37
  </div>
38
- `).join("")}getMetricIcon(e){return{count:"#",sum:"Σ",avg:"x̄",min:"↓",max:"↑"}[e]||"#"}formatNumber(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":Number.isInteger(e)?e.toLocaleString():e.toFixed(2)}renderCharts(){var i,n;const e=document.getElementById("chartsGrid");if(!e)return;const t=((i=this.config)==null?void 0:i.charts)||[],s=((n=this.config)==null?void 0:n.allDocuments)||{},r=this.renderActivityTable(s);if(t.length===0){e.innerHTML=`
38
+ `).join("")}getMetricIcon(e){return{count:"#",sum:"Σ",avg:"x̄",min:"↓",max:"↑"}[e]||"#"}formatNumber(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":Number.isInteger(e)?e.toLocaleString():e.toFixed(2)}renderCharts(){var i,a;const e=document.getElementById("chartsGrid");if(!e)return;const t=((i=this.config)==null?void 0:i.charts)||[],s=((a=this.config)==null?void 0:a.allDocuments)||{},r=this.renderActivityTable(s);if(t.length===0){e.innerHTML=`
39
39
  ${this.renderTablesOverview()}
40
40
  ${r}
41
- `;return}e.innerHTML=t.map((a,c)=>{const l=s[a.table]||[];return`
41
+ `;return}e.innerHTML=t.map((n,c)=>{const l=s[n.table]||[];return`
42
42
  <div class="chart-card">
43
43
  <div class="chart-header">
44
- <span class="chart-title">${a.title}</span>
44
+ <span class="chart-title">${n.title}</span>
45
45
  <span class="chart-subtitle">${l.length} documents</span>
46
46
  </div>
47
47
  <div class="chart-container" id="chart-${c}">
48
- ${this.renderChartContent(a,l)}
48
+ ${this.renderChartContent(n,l)}
49
49
  </div>
50
50
  </div>
51
51
  `}).join("")+r}renderTablesOverview(){var s;const e=((s=this.config)==null?void 0:s.tables)||[];if(e.length===0)return"";const t=Math.max(...e.map(r=>r.documentCount),1);return`
@@ -63,7 +63,7 @@ var h=Object.defineProperty;var m=(o,e,t)=>e in o?h(o,e,{enumerable:!0,configura
63
63
  </div>
64
64
  </div>
65
65
  </div>
66
- `}renderChartContent(e,t){switch(e.type){case"bar":return this.renderBarChart(t,e);case"line":return this.renderLineChart(t,e);case"pie":return this.renderPieChart(t,e);case"table":return this.renderDataTable(t);default:return`<div class="empty-state">Unknown chart type: ${e.type}</div>`}}renderBarChart(e,t){if(e.length===0)return'<div class="empty-state">No data available</div>';let s=[];if(t.groupBy){const i=new Map;for(const n of e){const a=String(n[t.groupBy]||"Unknown");i.set(a,(i.get(a)||0)+1)}s=Array.from(i.entries()).map(([n,a])=>({label:n,value:a})).sort((n,a)=>a.value-n.value).slice(0,7)}else{const i=new Map;for(const n of e){const a=new Date(n._creationTime).toLocaleDateString();i.set(a,(i.get(a)||0)+1)}s=Array.from(i.entries()).map(([n,a])=>({label:n,value:a})).slice(-7)}const r=Math.max(...s.map(i=>i.value),1);return`
66
+ `}renderChartContent(e,t){switch(e.type){case"bar":return this.renderBarChart(t,e);case"line":return this.renderLineChart(t,e);case"pie":return this.renderPieChart(t,e);case"table":return this.renderDataTable(t);default:return`<div class="empty-state">Unknown chart type: ${e.type}</div>`}}renderBarChart(e,t){if(e.length===0)return'<div class="empty-state">No data available</div>';let s=[];if(t.groupBy){const i=new Map;for(const a of e){const n=String(a[t.groupBy]||"Unknown");i.set(n,(i.get(n)||0)+1)}s=Array.from(i.entries()).map(([a,n])=>({label:a,value:n})).sort((a,n)=>n.value-a.value).slice(0,7)}else{const i=new Map;for(const a of e){const n=new Date(a._creationTime).toLocaleDateString();i.set(n,(i.get(n)||0)+1)}s=Array.from(i.entries()).map(([a,n])=>({label:a,value:n})).slice(-7)}const r=Math.max(...s.map(i=>i.value),1);return`
67
67
  <div class="bar-chart">
68
68
  ${s.map(i=>`
69
69
  <div class="bar" style="height: ${i.value/r*100}%" data-value="${i.value}">
@@ -71,13 +71,13 @@ var h=Object.defineProperty;var m=(o,e,t)=>e in o?h(o,e,{enumerable:!0,configura
71
71
  </div>
72
72
  `).join("")}
73
73
  </div>
74
- `}renderLineChart(e,t){return e.length===0?'<div class="empty-state">No data available</div>':this.renderBarChart(e,t)}renderPieChart(e,t){if(e.length===0||!t.groupBy)return'<div class="empty-state">No data or groupBy field specified</div>';const s=new Map;for(const a of e){const c=String(a[t.groupBy]||"Unknown");s.set(c,(s.get(c)||0)+1)}const r=e.length,i=Array.from(s.entries()).map(([a,c])=>({label:a,count:c,percent:(c/r*100).toFixed(1)})).sort((a,c)=>c.count-a.count).slice(0,5),n=["#e94560","#0f3460","#16213e","#1a1a2e","#4caf50"];return`
74
+ `}renderLineChart(e,t){return e.length===0?'<div class="empty-state">No data available</div>':this.renderBarChart(e,t)}renderPieChart(e,t){if(e.length===0||!t.groupBy)return'<div class="empty-state">No data or groupBy field specified</div>';const s=new Map;for(const n of e){const c=String(n[t.groupBy]||"Unknown");s.set(c,(s.get(c)||0)+1)}const r=e.length,i=Array.from(s.entries()).map(([n,c])=>({label:n,count:c,percent:(c/r*100).toFixed(1)})).sort((n,c)=>c.count-n.count).slice(0,5),a=["#e94560","#0f3460","#16213e","#1a1a2e","#4caf50"];return`
75
75
  <div class="pie-legend">
76
- ${i.map((a,c)=>`
76
+ ${i.map((n,c)=>`
77
77
  <div class="pie-item">
78
- <span class="pie-color" style="background: ${n[c%n.length]}"></span>
79
- <span class="pie-label">${a.label}</span>
80
- <span class="pie-value">${a.percent}%</span>
78
+ <span class="pie-color" style="background: ${a[c%a.length]}"></span>
79
+ <span class="pie-label">${n.label}</span>
80
+ <span class="pie-value">${n.percent}%</span>
81
81
  </div>
82
82
  `).join("")}
83
83
  </div>
@@ -137,4 +137,4 @@ var h=Object.defineProperty;var m=(o,e,t)=>e in o?h(o,e,{enumerable:!0,configura
137
137
  </div>
138
138
  </div>
139
139
  </div>
140
- `}formatValue(e){if(e==null)return'<span style="color: var(--text-secondary)">null</span>';if(typeof e=="object"){const t=JSON.stringify(e);return t.length>30?t.slice(0,30)+"...":t}return typeof e=="string"&&e.length>30?e.slice(0,30)+"...":String(e)}formatTimeAgo(e){if(!e)return"Unknown";const s=Date.now()-e,r=Math.floor(s/6e4),i=Math.floor(s/36e5),n=Math.floor(s/864e5);return r<1?"Just now":r<60?`${r}m ago`:i<24?`${i}h ago`:`${n}d ago`}updateTimestamp(){const e=document.getElementById("lastUpdate");e&&(e.textContent="Updated: "+new Date().toLocaleTimeString())}startAutoRefresh(){var t;const e=(((t=this.config)==null?void 0:t.refreshInterval)||5)*1e3;this.refreshTimer=window.setInterval(()=>{this.updateTimestamp()},e)}stopAutoRefresh(){this.refreshTimer&&(clearInterval(this.refreshTimer),this.refreshTimer=null)}destroy(){this.stopAutoRefresh()}}const u=new p;window.addEventListener("beforeunload",()=>{u.destroy()});
140
+ `}formatValue(e){if(e==null)return'<span style="color: var(--text-secondary)">null</span>';if(typeof e=="object"){const t=JSON.stringify(e);return t.length>30?t.slice(0,30)+"...":t}return typeof e=="string"&&e.length>30?e.slice(0,30)+"...":String(e)}formatTimeAgo(e){if(!e)return"Unknown";const s=Date.now()-e,r=Math.floor(s/6e4),i=Math.floor(s/36e5),a=Math.floor(s/864e5);return r<1?"Just now":r<60?`${r}m ago`:i<24?`${i}h ago`:`${a}d ago`}updateTimestamp(){const e=document.getElementById("lastUpdate");e&&(e.textContent="Updated: "+new Date().toLocaleTimeString())}startAutoRefresh(){var t;const e=(((t=this.config)==null?void 0:t.refreshInterval)||5)*1e3;this.refreshTimer=window.setInterval(()=>{this.updateTimestamp()},e)}stopAutoRefresh(){this.refreshTimer&&(clearInterval(this.refreshTimer),this.refreshTimer=null)}destroy(){this.stopAutoRefresh()}}const p=new v;window.addEventListener("beforeunload",()=>{p.destroy()});
@@ -68,7 +68,12 @@ var V=Object.defineProperty;var X=(x,e,t)=>e in x?V(x,e,{enumerable:!0,configura
68
68
  </div>
69
69
  `}renderListViewContent(){var o,s,a,r;if(!this.selectedTable)return`
70
70
  <div class="empty-state" style="height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;">
71
- <div class="empty-icon">📋</div>
71
+ <div class="empty-icon">
72
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
73
+ <rect x="3" y="3" width="18" height="18" rx="2"/>
74
+ <path d="M3 9h18M9 3v18"/>
75
+ </svg>
76
+ </div>
72
77
  <h2>Select a Table</h2>
73
78
  <p>Choose a table from the sidebar to view its schema and documents.</p>
74
79
  </div>
@@ -122,7 +127,12 @@ var V=Object.defineProperty;var X=(x,e,t)=>e in x?V(x,e,{enumerable:!0,configura
122
127
  </div>
123
128
  `}renderDocumentsTable(e){const t=(this.currentPage-1)*this.pageSize,i=t+this.pageSize,n=e.slice(t,i);if(n.length===0)return`
124
129
  <div class="documents-empty">
125
- <div class="documents-empty-icon">📄</div>
130
+ <div class="documents-empty-icon">
131
+ <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
132
+ <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
133
+ <path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"/>
134
+ </svg>
135
+ </div>
126
136
  <h3>No Documents</h3>
127
137
  <p>This table doesn't have any documents yet.</p>
128
138
  </div>
@@ -452,16 +462,19 @@ var V=Object.defineProperty;var X=(x,e,t)=>e in x?V(x,e,{enumerable:!0,configura
452
462
  <button class="btn btn-primary" id="filterApply">Apply</button>
453
463
  </div>
454
464
  </div>
455
- `:""}generateSchemaCode(){var n,o,s;const e=((n=this.config)==null?void 0:n.tables)||[],t=((o=this.config)==null?void 0:o.allDocuments)||{},i={};for(const a of e){const r={};if(a.inferredFields)for(const l of a.inferredFields)r[l.name]=l.type+(l.optional?"?":"");i[a.name]={fields:r,documentCount:a.documentCount,sample:((s=t[a.name])==null?void 0:s[0])||null}}return this.syntaxHighlight(JSON.stringify(i,null,2))}syntaxHighlight(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?)/g,t=>{let i="json-string";return/:$/.test(t)&&(i="json-key"),`<span class="${i}">${t}</span>`}).replace(/\b(true|false)\b/g,'<span class="json-boolean">$1</span>').replace(/\b(null)\b/g,'<span class="json-null">$1</span>').replace(/\b(-?\d+\.?\d*)\b/g,'<span class="json-number">$1</span>')}initGraphView(){if(this.canvas=document.getElementById("graphCanvas"),!this.canvas)return;this.dpr=window.devicePixelRatio||1;const e=this.canvas.parentElement;if(e){const t=e.clientWidth,i=e.clientHeight;this.canvas.width=t*this.dpr,this.canvas.height=i*this.dpr,this.canvas.style.width=t+"px",this.canvas.style.height=i+"px"}this.ctx=this.canvas.getContext("2d"),this.ctx&&(this.ctx.scale(this.dpr,this.dpr),this.calculateGraphLayout(),this.setupGraphEvents(),this.drawGraph(),this.savePositionState(),window.addEventListener("resize",()=>{if(this.canvas&&this.canvas.parentElement&&this.ctx){const t=this.canvas.parentElement.clientWidth,i=this.canvas.parentElement.clientHeight;this.dpr=window.devicePixelRatio||1,this.canvas.width=t*this.dpr,this.canvas.height=i*this.dpr,this.canvas.style.width=t+"px",this.canvas.style.height=i+"px",this.ctx.scale(this.dpr,this.dpr),this.drawGraph()}}))}calculateGraphLayout(){var a,r;const e=((a=this.config)==null?void 0:a.tables)||[];(r=this.config)!=null&&r.allDocuments,this.graphNodes=[],this.graphEdges=[];const t=220,i=160,n=80,o=60,s=Math.ceil(Math.sqrt(e.length));e.forEach((l,d)=>{const h=d%s,c=Math.floor(d/s);this.graphNodes.push({id:l.name,x:100+h*(t+n),y:100+c*(i+o),width:t,height:i,table:l})});for(const l of this.graphNodes){const d=l.table.inferredFields||[];for(const h of d){const c=h.type.match(/Id<["'](\w+)["']>/);if(c){const u=c[1],g=this.graphNodes.find(b=>b.id===u);if(g&&g.id!==l.id){this.graphEdges.push({from:l.id,to:g.id,fromField:h.name,toField:"_id",inferred:!1});continue}}const p=h.name.toLowerCase();for(const u of this.graphNodes){if(u.id===l.id)continue;const g=u.id.toLowerCase(),b=g.endsWith("s")?g.slice(0,-1):g;(p===g+"id"||p===b+"id"||p===b+"_id"||p===g+"_id")&&(this.graphEdges.some(w=>w.from===l.id&&w.to===u.id&&w.fromField===h.name)||this.graphEdges.push({from:l.id,to:u.id,fromField:h.name,toField:"_id",inferred:!0}))}}}if(this.canvas&&this.graphNodes.length>0){const l=Math.min(...this.graphNodes.map(f=>f.x)),d=Math.max(...this.graphNodes.map(f=>f.x+f.width)),h=Math.min(...this.graphNodes.map(f=>f.y)),c=Math.max(...this.graphNodes.map(f=>f.y+f.height)),p=d-l,u=c-h,g=this.canvas.width/this.dpr,b=this.canvas.height/this.dpr;this.panX=(g-p)/2-l,this.panY=(b-u)/2-h}}setupGraphEvents(){var i,n,o,s;if(!this.canvas)return;let e=0,t=0;this.canvas.addEventListener("mousedown",a=>{const r=this.canvas.getBoundingClientRect(),l=(a.clientX-r.left-this.panX)/this.zoom,d=(a.clientY-r.top-this.panY)/this.zoom;this.selectedNode=this.graphNodes.find(h=>l>=h.x&&l<=h.x+h.width&&d>=h.y&&d<=h.y+h.height)||null,this.selectedNode&&(this.selectTable(this.selectedNode.id),this.updateCodePanel()),this.isDragging=!0,e=a.clientX,t=a.clientY,this.dragStartX=a.clientX,this.dragStartY=a.clientY}),this.canvas.addEventListener("mousemove",a=>{const r=this.canvas.getBoundingClientRect(),l=(a.clientX-r.left-this.panX)/this.zoom,d=(a.clientY-r.top-this.panY)/this.zoom,h=this.graphNodes.find(c=>c.visible!==!1&&l>=c.x&&l<=c.x+c.width&&d>=c.y&&d<=c.y+c.height)||null;if(h!==this.hoveredNode&&(this.hoveredNode=h,this.canvas.style.cursor=h?"pointer":"grab",this.hideTooltip(),this.drawGraph()),h&&!this.isDragging){const c=this.getFieldAtPosition(h,d);if(c){const p=this.getFieldTooltipContent(c,h.table.name);this.showTooltip(a.clientX,a.clientY,p.title,p.content,"field")}else this.hideTooltip()}else h||this.hideTooltip();if(this.isDragging){if(this.hideTooltip(),this.selectedNode){const c=(a.clientX-e)/this.zoom,p=(a.clientY-t)/this.zoom;this.selectedNode.x+=c,this.selectedNode.y+=p}else this.panX+=a.clientX-e,this.panY+=a.clientY-t;e=a.clientX,t=a.clientY,this.drawGraph()}}),this.canvas.addEventListener("mouseup",a=>{this.isDragging&&(this.selectedNode||Math.abs(a.clientX-this.dragStartX)>5||Math.abs(a.clientY-this.dragStartY)>5)&&this.savePositionState(),this.isDragging=!1,this.selectedNode=null}),this.canvas.addEventListener("mouseleave",()=>{this.isDragging=!1,this.selectedNode=null,this.hoveredNode=null,this.hideTooltip(),this.drawGraph()}),this.canvas.addEventListener("wheel",a=>{a.preventDefault();const r=this.canvas.getBoundingClientRect(),l=a.clientX-r.left,d=a.clientY-r.top,h=this.zoom,c=a.deltaY>0?.9:1.1;this.zoom=Math.max(.25,Math.min(2,this.zoom*c)),this.panX=l-(l-this.panX)*(this.zoom/h),this.panY=d-(d-this.panY)*(this.zoom/h),this.drawGraph()}),(i=document.getElementById("zoomIn"))==null||i.addEventListener("click",()=>{this.zoom=Math.min(2,this.zoom*1.2),this.updateZoomDisplay(),this.drawGraph()}),(n=document.getElementById("zoomOut"))==null||n.addEventListener("click",()=>{this.zoom=Math.max(.25,this.zoom/1.2),this.updateZoomDisplay(),this.drawGraph()}),(o=document.getElementById("fitView"))==null||o.addEventListener("click",()=>{this.fitToView()}),(s=document.getElementById("resetView"))==null||s.addEventListener("click",()=>{this.zoom=1,this.calculateGraphLayout(),this.updateZoomDisplay(),this.drawGraph()})}drawGraph(){if(!this.ctx||!this.canvas)return;const e=this.ctx,t=this.getThemeColors();this.canvas.width/this.dpr,this.canvas.height/this.dpr,e.save(),e.setTransform(1,0,0,1,0,0),e.fillStyle=t.bgPrimary,e.fillRect(0,0,this.canvas.width,this.canvas.height),e.restore(),e.save(),e.translate(this.panX,this.panY),e.scale(this.zoom,this.zoom),this.drawGridPattern(e);for(const i of this.graphEdges){const n=this.graphNodes.find(s=>s.id===i.from),o=this.graphNodes.find(s=>s.id===i.to);n&&o&&n.visible!==!1&&o.visible!==!1&&this.drawEdge(e,n,o,i)}for(const i of this.graphNodes)i.visible!==!1&&this.drawNode(e,i);e.restore()}drawGridPattern(e){const t=this.getThemeColors(),i=40,n=-this.panX/this.zoom-1e3,o=-this.panY/this.zoom-1e3,s=n+3e3,a=o+3e3;e.strokeStyle=t.gridLine,e.lineWidth=.5;for(let r=Math.floor(n/i)*i;r<s;r+=i)e.beginPath(),e.moveTo(r,o),e.lineTo(r,a),e.stroke();for(let r=Math.floor(o/i)*i;r<a;r+=i)e.beginPath(),e.moveTo(n,r),e.lineTo(s,r),e.stroke()}drawNode(e,t){const i=this.getThemeColors(),n=this.currentTheme==="dark",o=this.hoveredNode===t,s=this.selectedTable===t.id,a=t.x,r=t.y,l=t.width,d=10,h=this.getSortedFields(t.table.inferredFields||[]),c=12,p=h.slice(0,c),u=h.length>c,g=44,b=24,f=12,w=u?28:0,y=g+p.length*b+f+w;t.height=y;const v=n?.4:.08,S=n?.5:.15;e.shadowColor=o||s?`rgba(235, 86, 1, ${S})`:`rgba(0, 0, 0, ${v})`,e.shadowBlur=o?16:8,e.shadowOffsetX=0,e.shadowOffsetY=o?6:3,e.fillStyle=i.nodeBg,e.beginPath(),e.roundRect(a,r,l,y,d),e.fill(),e.shadowColor="transparent",e.strokeStyle=s?i.accentInteractive:o?i.accent:i.nodeBorder,e.lineWidth=s?2:1,e.stroke();const C=e.createLinearGradient(a,r,a,r+g);s?(C.addColorStop(0,i.accentInteractive),C.addColorStop(1,i.accentHover)):(C.addColorStop(0,i.nodeHeader),C.addColorStop(1,n?i.bgSecondary:i.bgHover)),e.fillStyle=C,e.beginPath(),e.roundRect(a,r,l,g,[d,d,0,0]),e.fill(),e.strokeStyle=s?"rgba(255,255,255,0.1)":i.border,e.lineWidth=1,e.beginPath(),e.moveTo(a,r+g),e.lineTo(a+l,r+g),e.stroke(),e.fillStyle=s?"#ffffff":i.textPrimary,e.font='bold 14px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',e.textBaseline="middle";const k=t.table.name,$=l-100;let L=k;if(e.measureText(k).width>$){for(;e.measureText(L+"...").width>$&&L.length>0;)L=L.slice(0,-1);L+="..."}e.fillText(L,a+14,r+g/2);const I=`${h.length} fields`;e.font="11px -apple-system, BlinkMacSystemFont, sans-serif";const B=e.measureText(I).width+14;e.fillStyle=s?"rgba(255,255,255,0.25)":n?"rgba(255,255,255,0.1)":"rgba(0,0,0,0.06)",e.beginPath(),e.roundRect(a+l-B-10,r+(g-20)/2,B,20,10),e.fill(),e.fillStyle=s?"rgba(255,255,255,0.9)":i.textSecondary,e.textAlign="center",e.fillText(I,a+l-B/2-10,r+g/2),e.textAlign="left";let M=r+g+8;for(const T of p){const z=T.name.startsWith("_"),P=T.name==="_id",N=T.type.includes("Id<");o&&(e.fillStyle=n?"rgba(255, 255, 255, 0.03)":"rgba(0, 0, 0, 0.02)",e.fillRect(a+4,M-6,l-8,b)),P&&this.drawKeyIcon(e,a+12,M+2,s,i);const F=P?a+28:a+14;if(e.font='12px "SF Mono", Monaco, "Cascadia Code", monospace',z?e.fillStyle=i.textMuted:N?e.fillStyle=i.accent:e.fillStyle=i.accentInteractive,e.fillText(T.name,F,M+4),T.optional){const D=e.measureText(T.name).width;e.fillStyle=i.warning,e.font="10px -apple-system, sans-serif",e.fillText("?",F+D+2,M+3)}e.font='11px "SF Mono", Monaco, "Cascadia Code", monospace',e.fillStyle=z?i.textMuted:i.textSecondary,e.textAlign="right";let E=T.type;const H=80;if(e.measureText(E).width>H){for(;e.measureText(E+"...").width>H&&E.length>0;)E=E.slice(0,-1);E+="..."}e.fillText(E,a+l-12,M+4),e.textAlign="left",M+=b}if(u){const T=h.length-c;e.fillStyle=i.bgSecondary,e.beginPath(),e.roundRect(a+4,M,l-8,24,[0,0,d-4,d-4]),e.fill(),e.fillStyle=i.textSecondary,e.font="11px -apple-system, BlinkMacSystemFont, sans-serif",e.textAlign="center",e.fillText(`+ ${T} more field${T>1?"s":""}`,a+l/2,M+14),e.textAlign="left"}}getSortedFields(e){const t=["_id","_creationTime"];return[...e].sort((i,n)=>{const o=t.includes(i.name),s=t.includes(n.name);return o&&!s?-1:!o&&s?1:o&&s?t.indexOf(i.name)-t.indexOf(n.name):i.name.localeCompare(n.name)})}drawKeyIcon(e,t,i,n,o){e.save(),e.fillStyle=n?o.accentInteractive:o.warning,e.beginPath(),e.arc(t+4,i,4,0,Math.PI*2),e.fill(),e.fillRect(t+7,i-1,6,2),e.fillRect(t+10,i-1,1,3),e.fillRect(t+12,i-1,1,2),e.restore()}drawEdge(e,t,i,n){const o=this.hoveredNode&&(this.hoveredNode.id===n.from||this.hoveredNode.id===n.to),s=this.calculateAttachmentPoints(t,i),a=Math.sqrt(Math.pow(s.toX-s.fromX,2)+Math.pow(s.toY-s.fromY,2)),r=Math.min(a*.4,100);let l,d,h,c;s.fromSide==="right"?(l=s.fromX+r,d=s.fromY):s.fromSide==="left"?(l=s.fromX-r,d=s.fromY):s.fromSide==="bottom"?(l=s.fromX,d=s.fromY+r):(l=s.fromX,d=s.fromY-r),s.toSide==="left"?(h=s.toX-r,c=s.toY):s.toSide==="right"?(h=s.toX+r,c=s.toY):s.toSide==="top"?(h=s.toX,c=s.toY-r):(h=s.toX,c=s.toY+r),o&&(e.save(),e.shadowColor="rgba(235, 86, 1, 0.3)",e.shadowBlur=8,e.shadowOffsetX=0,e.shadowOffsetY=0),e.strokeStyle=o?"#EB5601":"#8b7355",e.lineWidth=o?2.5:1.5,n.inferred?e.setLineDash([6,4]):e.setLineDash([]),e.beginPath(),e.moveTo(s.fromX,s.fromY),e.bezierCurveTo(l,d,h,c,s.toX,s.toY),e.stroke(),e.setLineDash([]),o&&e.restore(),this.drawArrowHead(e,h,c,s.toX,s.toY,o);const p=.5,u=this.bezierPoint(s.fromX,l,h,s.toX,p),g=this.bezierPoint(s.fromY,d,c,s.toY,p)-12;e.font="10px -apple-system, BlinkMacSystemFont, sans-serif";const b=n.fromField,f=e.measureText(b).width+10,w=16;e.fillStyle=o?"rgba(235, 86, 1, 0.1)":"rgba(255, 255, 255, 0.95)",e.beginPath(),e.roundRect(u-f/2,g-w/2,f,w,4),e.fill(),e.strokeStyle=o?"rgba(235, 86, 1, 0.3)":"#e6e4e1",e.lineWidth=1,e.stroke(),e.fillStyle=o?"#EB5601":"#6b6b6b",e.textAlign="center",e.textBaseline="middle",e.fillText(b,u,g),e.textAlign="left",e.textBaseline="alphabetic"}calculateAttachmentPoints(e,t){const i=e.x+e.width/2,n=e.y+e.height/2,o=t.x+t.width/2,s=t.y+t.height/2,a=o-i,r=s-n;let l,d,h,c,p,u;return Math.abs(a)>Math.abs(r)?a>0?(l="right",d="left",h=e.x+e.width,c=n,p=t.x,u=s):(l="left",d="right",h=e.x,c=n,p=t.x+t.width,u=s):r>0?(l="bottom",d="top",h=i,c=e.y+e.height,p=o,u=t.y):(l="top",d="bottom",h=i,c=e.y,p=o,u=t.y+t.height),{fromX:h,fromY:c,fromSide:l,toX:p,toY:u,toSide:d}}drawArrowHead(e,t,i,n,o,s){const a=Math.atan2(o-i,n-t),r=s?10:8;e.fillStyle=s?"#EB5601":"#8b7355",e.beginPath(),e.moveTo(n,o),e.lineTo(n-r*Math.cos(a-Math.PI/6),o-r*Math.sin(a-Math.PI/6)),e.lineTo(n-r*Math.cos(a+Math.PI/6),o-r*Math.sin(a+Math.PI/6)),e.closePath(),e.fill()}bezierPoint(e,t,i,n,o){const s=1-o;return s*s*s*e+3*s*s*o*t+3*s*o*o*i+o*o*o*n}updateCodePanel(){var i,n,o,s;const e=document.getElementById("codeBlock"),t=document.querySelector(".code-filename");if(e&&this.selectedTable){const a=(n=(i=this.config)==null?void 0:i.tables)==null?void 0:n.find(l=>l.name===this.selectedTable),r=((s=(o=this.config)==null?void 0:o.allDocuments)==null?void 0:s[this.selectedTable])||[];if(a){const l={table:this.selectedTable,documentCount:a.documentCount,fields:{}};if(a.inferredFields)for(const d of a.inferredFields)l.fields[d.name]={type:d.type,required:!d.optional};r.length>0&&(l.sample=r[0]),e.innerHTML=this.syntaxHighlight(JSON.stringify(l,null,2))}}t&&this.selectedTable&&(t.textContent=`${this.selectedTable}.json`)}savePositionState(){const e={nodes:this.graphNodes.map(t=>({id:t.id,x:t.x,y:t.y})),panX:this.panX,panY:this.panY,zoom:this.zoom};this.historyIndex<this.positionHistory.length-1&&(this.positionHistory=this.positionHistory.slice(0,this.historyIndex+1)),this.positionHistory.push(e),this.positionHistory.length>this.maxHistorySize?this.positionHistory.shift():this.historyIndex++,this.updateUndoRedoButtons()}undo(){this.historyIndex<=0||(this.historyIndex--,this.restorePositionState(this.positionHistory[this.historyIndex]),this.updateUndoRedoButtons())}redo(){this.historyIndex>=this.positionHistory.length-1||(this.historyIndex++,this.restorePositionState(this.positionHistory[this.historyIndex]),this.updateUndoRedoButtons())}restorePositionState(e){for(const t of e.nodes){const i=this.graphNodes.find(n=>n.id===t.id);i&&(i.x=t.x,i.y=t.y)}this.panX=e.panX,this.panY=e.panY,this.zoom=e.zoom,this.updateZoomDisplay(),this.drawGraph()}updateUndoRedoButtons(){const e=document.getElementById("undoBtn"),t=document.getElementById("redoBtn");e&&(e.disabled=this.historyIndex<=0),t&&(t.disabled=this.historyIndex>=this.positionHistory.length-1)}fitToView(){if(this.graphNodes.length===0)return;const e=this.graphNodes.filter(p=>p.visible!==!1);if(e.length===0)return;const t=60,i=Math.min(...e.map(p=>p.x))-t,n=Math.max(...e.map(p=>p.x+p.width))+t,o=Math.min(...e.map(p=>p.y))-t,s=Math.max(...e.map(p=>p.y+p.height))+t,a=n-i,r=s-o;if(!this.canvas)return;const l=this.canvas.width/this.dpr,d=this.canvas.height/this.dpr,h=l/a,c=d/r;this.zoom=Math.min(h,c,1.5),this.zoom=Math.max(this.zoom,.25),this.panX=(l-a*this.zoom)/2-i*this.zoom,this.panY=(d-r*this.zoom)/2-o*this.zoom,this.updateZoomDisplay(),this.drawGraph()}autoArrange(){this.calculateGraphLayout(),this.drawGraph(),this.savePositionState()}updateZoomDisplay(){const e=document.getElementById("zoomLevel"),t=document.getElementById("zoomDisplay"),i=`${Math.round(this.zoom*100)}%`;e&&(e.textContent=i),t&&(t.textContent=i)}toggleCodePanel(){this.showCodePanel=!this.showCodePanel;const e=document.getElementById("sidebarContainer"),t=document.getElementById("viewCodeBtn");e&&e.classList.toggle("hidden",!this.showCodePanel),t&&t.classList.toggle("active",this.showCodePanel),setTimeout(()=>this.resizeCanvas(),50)}toggleExportMenu(){this.showExportMenu=!this.showExportMenu,this.showFilterDropdown=!1,this.renderDropdowns()}toggleFilterDropdown(){this.showFilterDropdown=!this.showFilterDropdown,this.showExportMenu=!1,this.renderDropdowns()}renderDropdowns(){var t,i;(t=document.getElementById("exportMenu"))==null||t.remove(),(i=document.getElementById("filterMenu"))==null||i.remove();const e=document.querySelector(".graph-view");e&&(this.showExportMenu&&(e.insertAdjacentHTML("beforeend",this.renderExportMenu()),this.setupExportMenuEvents()),this.showFilterDropdown&&(e.insertAdjacentHTML("beforeend",this.renderFilterDropdown()),this.setupFilterMenuEvents()))}setupExportMenuEvents(){var e,t,i;(e=document.getElementById("exportJson"))==null||e.addEventListener("click",()=>{this.exportSchema("json"),this.showExportMenu=!1,this.renderDropdowns()}),(t=document.getElementById("exportTs"))==null||t.addEventListener("click",()=>{this.exportSchema("typescript"),this.showExportMenu=!1,this.renderDropdowns()}),(i=document.getElementById("exportPng"))==null||i.addEventListener("click",()=>{this.exportAsPng(),this.showExportMenu=!1,this.renderDropdowns()}),setTimeout(()=>{document.addEventListener("click",this.handleOutsideClick.bind(this),{once:!0})},0)}setupFilterMenuEvents(){var e,t,i;(e=document.getElementById("filterClose"))==null||e.addEventListener("click",()=>{this.showFilterDropdown=!1,this.renderDropdowns()}),(t=document.getElementById("filterApply"))==null||t.addEventListener("click",()=>{this.applyFilters()}),(i=document.getElementById("filterClear"))==null||i.addEventListener("click",()=>{this.clearFilters()})}handleOutsideClick(e){const t=document.getElementById("exportMenu"),i=document.getElementById("exportBtn"),n=document.getElementById("filterMenu"),o=document.getElementById("filterBtn");t&&!t.contains(e.target)&&!(i!=null&&i.contains(e.target))&&(this.showExportMenu=!1,this.renderDropdowns()),n&&!n.contains(e.target)&&!(o!=null&&o.contains(e.target))&&(this.showFilterDropdown=!1,this.renderDropdowns())}exportSchema(e){var s;const t=((s=this.config)==null?void 0:s.tables)||[];let i,n,o;if(e==="json"){const a={};for(const r of t)a[r.name]={documentCount:r.documentCount,fields:(r.inferredFields||[]).reduce((l,d)=>(l[d.name]={type:d.type,required:!d.optional},l),{})};i=JSON.stringify(a,null,2),n="convex-schema.json",o="application/json"}else{const a=['import { defineSchema, defineTable } from "convex/server";','import { v } from "convex/values";',"","export default defineSchema({"];for(const r of t){const l=(r.inferredFields||[]).filter(d=>!d.name.startsWith("_")).map(d=>` ${d.name}: ${this.toConvexValidator(d.type)}${d.optional?".optional()":""},`).join(`
465
+ `:""}generateSchemaCode(){var n,o,s;const e=((n=this.config)==null?void 0:n.tables)||[],t=((o=this.config)==null?void 0:o.allDocuments)||{},i={};for(const a of e){const r={};if(a.inferredFields)for(const l of a.inferredFields)r[l.name]=l.type+(l.optional?"?":"");i[a.name]={fields:r,documentCount:a.documentCount,sample:((s=t[a.name])==null?void 0:s[0])||null}}return this.syntaxHighlight(JSON.stringify(i,null,2))}syntaxHighlight(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?)/g,t=>{let i="json-string";return/:$/.test(t)&&(i="json-key"),`<span class="${i}">${t}</span>`}).replace(/\b(true|false)\b/g,'<span class="json-boolean">$1</span>').replace(/\b(null)\b/g,'<span class="json-null">$1</span>').replace(/\b(-?\d+\.?\d*)\b/g,'<span class="json-number">$1</span>')}initGraphView(){if(this.canvas=document.getElementById("graphCanvas"),!this.canvas)return;this.dpr=window.devicePixelRatio||1;const e=this.canvas.parentElement;if(e){const t=e.clientWidth,i=e.clientHeight;this.canvas.width=t*this.dpr,this.canvas.height=i*this.dpr,this.canvas.style.width=t+"px",this.canvas.style.height=i+"px"}this.ctx=this.canvas.getContext("2d"),this.ctx&&(this.ctx.scale(this.dpr,this.dpr),this.calculateGraphLayout(),this.setupGraphEvents(),this.drawGraph(),this.savePositionState(),window.addEventListener("resize",()=>{if(this.canvas&&this.canvas.parentElement&&this.ctx){const t=this.canvas.parentElement.clientWidth,i=this.canvas.parentElement.clientHeight;this.dpr=window.devicePixelRatio||1,this.canvas.width=t*this.dpr,this.canvas.height=i*this.dpr,this.canvas.style.width=t+"px",this.canvas.style.height=i+"px",this.ctx.scale(this.dpr,this.dpr),this.drawGraph()}}))}calculateGraphLayout(){var a,r;const e=((a=this.config)==null?void 0:a.tables)||[];(r=this.config)!=null&&r.allDocuments,this.graphNodes=[],this.graphEdges=[];const t=220,i=160,n=80,o=60,s=Math.ceil(Math.sqrt(e.length));e.forEach((l,d)=>{const h=d%s,c=Math.floor(d/s);this.graphNodes.push({id:l.name,x:100+h*(t+n),y:100+c*(i+o),width:t,height:i,table:l})});for(const l of this.graphNodes){const d=l.table.inferredFields||[];for(const h of d){const c=h.type.match(/Id<["'](\w+)["']>/);if(c){const u=c[1],g=this.graphNodes.find(b=>b.id===u);if(g&&g.id!==l.id){this.graphEdges.push({from:l.id,to:g.id,fromField:h.name,toField:"_id",inferred:!1});continue}}const p=h.name.toLowerCase();for(const u of this.graphNodes){if(u.id===l.id)continue;const g=u.id.toLowerCase(),b=g.endsWith("s")?g.slice(0,-1):g;(p===g+"id"||p===b+"id"||p===b+"_id"||p===g+"_id")&&(this.graphEdges.some(w=>w.from===l.id&&w.to===u.id&&w.fromField===h.name)||this.graphEdges.push({from:l.id,to:u.id,fromField:h.name,toField:"_id",inferred:!0}))}}}if(this.canvas&&this.graphNodes.length>0){const l=Math.min(...this.graphNodes.map(f=>f.x)),d=Math.max(...this.graphNodes.map(f=>f.x+f.width)),h=Math.min(...this.graphNodes.map(f=>f.y)),c=Math.max(...this.graphNodes.map(f=>f.y+f.height)),p=d-l,u=c-h,g=this.canvas.width/this.dpr,b=this.canvas.height/this.dpr;this.panX=(g-p)/2-l,this.panY=(b-u)/2-h}}setupGraphEvents(){var i,n,o,s;if(!this.canvas)return;let e=0,t=0;this.canvas.addEventListener("mousedown",a=>{const r=this.canvas.getBoundingClientRect(),l=(a.clientX-r.left-this.panX)/this.zoom,d=(a.clientY-r.top-this.panY)/this.zoom;this.selectedNode=this.graphNodes.find(h=>l>=h.x&&l<=h.x+h.width&&d>=h.y&&d<=h.y+h.height)||null,this.selectedNode&&(this.selectTable(this.selectedNode.id),this.updateCodePanel()),this.isDragging=!0,e=a.clientX,t=a.clientY,this.dragStartX=a.clientX,this.dragStartY=a.clientY}),this.canvas.addEventListener("mousemove",a=>{const r=this.canvas.getBoundingClientRect(),l=(a.clientX-r.left-this.panX)/this.zoom,d=(a.clientY-r.top-this.panY)/this.zoom,h=this.graphNodes.find(c=>c.visible!==!1&&l>=c.x&&l<=c.x+c.width&&d>=c.y&&d<=c.y+c.height)||null;if(h!==this.hoveredNode&&(this.hoveredNode=h,this.canvas.style.cursor=h?"pointer":"grab",this.hideTooltip(),this.drawGraph()),h&&!this.isDragging){const c=this.getFieldAtPosition(h,d);if(c){const p=this.getFieldTooltipContent(c,h.table.name);this.showTooltip(a.clientX,a.clientY,p.title,p.content,"field")}else this.hideTooltip()}else h||this.hideTooltip();if(this.isDragging){if(this.hideTooltip(),this.selectedNode){const c=(a.clientX-e)/this.zoom,p=(a.clientY-t)/this.zoom;this.selectedNode.x+=c,this.selectedNode.y+=p}else this.panX+=a.clientX-e,this.panY+=a.clientY-t;e=a.clientX,t=a.clientY,this.drawGraph()}}),this.canvas.addEventListener("mouseup",a=>{this.isDragging&&(this.selectedNode||Math.abs(a.clientX-this.dragStartX)>5||Math.abs(a.clientY-this.dragStartY)>5)&&this.savePositionState(),this.isDragging=!1,this.selectedNode=null}),this.canvas.addEventListener("mouseleave",()=>{this.isDragging=!1,this.selectedNode=null,this.hoveredNode=null,this.hideTooltip(),this.drawGraph()}),this.canvas.addEventListener("wheel",a=>{a.preventDefault();const r=this.canvas.getBoundingClientRect(),l=a.clientX-r.left,d=a.clientY-r.top,h=this.zoom,c=a.deltaY>0?.9:1.1;this.zoom=Math.max(.25,Math.min(2,this.zoom*c)),this.panX=l-(l-this.panX)*(this.zoom/h),this.panY=d-(d-this.panY)*(this.zoom/h),this.drawGraph()}),(i=document.getElementById("zoomIn"))==null||i.addEventListener("click",()=>{this.zoom=Math.min(2,this.zoom*1.2),this.updateZoomDisplay(),this.drawGraph()}),(n=document.getElementById("zoomOut"))==null||n.addEventListener("click",()=>{this.zoom=Math.max(.25,this.zoom/1.2),this.updateZoomDisplay(),this.drawGraph()}),(o=document.getElementById("fitView"))==null||o.addEventListener("click",()=>{this.fitToView()}),(s=document.getElementById("resetView"))==null||s.addEventListener("click",()=>{this.zoom=1,this.calculateGraphLayout(),this.updateZoomDisplay(),this.drawGraph()})}drawGraph(){if(!this.ctx||!this.canvas)return;const e=this.ctx,t=this.getThemeColors();this.canvas.width/this.dpr,this.canvas.height/this.dpr,e.save(),e.setTransform(1,0,0,1,0,0),e.fillStyle=t.bgPrimary,e.fillRect(0,0,this.canvas.width,this.canvas.height),e.restore(),e.save(),e.translate(this.panX,this.panY),e.scale(this.zoom,this.zoom),this.drawGridPattern(e);for(const i of this.graphEdges){const n=this.graphNodes.find(s=>s.id===i.from),o=this.graphNodes.find(s=>s.id===i.to);n&&o&&n.visible!==!1&&o.visible!==!1&&this.drawEdge(e,n,o,i)}for(const i of this.graphNodes)i.visible!==!1&&this.drawNode(e,i);e.restore()}drawGridPattern(e){const t=this.getThemeColors(),i=40,n=-this.panX/this.zoom-1e3,o=-this.panY/this.zoom-1e3,s=n+3e3,a=o+3e3;e.strokeStyle=t.gridLine,e.lineWidth=.5;for(let r=Math.floor(n/i)*i;r<s;r+=i)e.beginPath(),e.moveTo(r,o),e.lineTo(r,a),e.stroke();for(let r=Math.floor(o/i)*i;r<a;r+=i)e.beginPath(),e.moveTo(n,r),e.lineTo(s,r),e.stroke()}drawNode(e,t){const i=this.getThemeColors(),n=this.currentTheme==="dark",o=this.hoveredNode===t,s=this.selectedTable===t.id,a=t.x,r=t.y,l=t.width,d=10,h=this.getSortedFields(t.table.inferredFields||[]),c=12,p=h.slice(0,c),u=h.length>c,g=44,b=24,f=12,w=u?28:0,y=g+p.length*b+f+w;t.height=y;const v=n?.4:.08,C=n?.5:.15;e.shadowColor=o||s?`rgba(235, 86, 1, ${C})`:`rgba(0, 0, 0, ${v})`,e.shadowBlur=o?16:8,e.shadowOffsetX=0,e.shadowOffsetY=o?6:3,e.fillStyle=i.nodeBg,e.beginPath(),e.roundRect(a,r,l,y,d),e.fill(),e.shadowColor="transparent",e.strokeStyle=s?i.accentInteractive:o?i.accent:i.nodeBorder,e.lineWidth=s?2:1,e.stroke();const S=e.createLinearGradient(a,r,a,r+g);s?(S.addColorStop(0,i.accentInteractive),S.addColorStop(1,i.accentHover)):(S.addColorStop(0,i.nodeHeader),S.addColorStop(1,n?i.bgSecondary:i.bgHover)),e.fillStyle=S,e.beginPath(),e.roundRect(a,r,l,g,[d,d,0,0]),e.fill(),e.strokeStyle=s?"rgba(255,255,255,0.1)":i.border,e.lineWidth=1,e.beginPath(),e.moveTo(a,r+g),e.lineTo(a+l,r+g),e.stroke(),e.fillStyle=s?"#ffffff":i.textPrimary,e.font='bold 14px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',e.textBaseline="middle";const k=t.table.name,$=l-100;let L=k;if(e.measureText(k).width>$){for(;e.measureText(L+"...").width>$&&L.length>0;)L=L.slice(0,-1);L+="..."}e.fillText(L,a+14,r+g/2);const I=`${h.length} fields`;e.font="11px -apple-system, BlinkMacSystemFont, sans-serif";const B=e.measureText(I).width+14;e.fillStyle=s?"rgba(255,255,255,0.25)":n?"rgba(255,255,255,0.1)":"rgba(0,0,0,0.06)",e.beginPath(),e.roundRect(a+l-B-10,r+(g-20)/2,B,20,10),e.fill(),e.fillStyle=s?"rgba(255,255,255,0.9)":i.textSecondary,e.textAlign="center",e.fillText(I,a+l-B/2-10,r+g/2),e.textAlign="left";let M=r+g+8;for(const T of p){const z=T.name.startsWith("_"),P=T.name==="_id",N=T.type.includes("Id<");o&&(e.fillStyle=n?"rgba(255, 255, 255, 0.03)":"rgba(0, 0, 0, 0.02)",e.fillRect(a+4,M-6,l-8,b)),P&&this.drawKeyIcon(e,a+12,M+2,s,i);const H=P?a+28:a+14;if(e.font='12px "SF Mono", Monaco, "Cascadia Code", monospace',z?e.fillStyle=i.textMuted:N?e.fillStyle=i.accent:e.fillStyle=i.accentInteractive,e.fillText(T.name,H,M+4),T.optional){const D=e.measureText(T.name).width;e.fillStyle=i.warning,e.font="10px -apple-system, sans-serif",e.fillText("?",H+D+2,M+3)}e.font='11px "SF Mono", Monaco, "Cascadia Code", monospace',e.fillStyle=z?i.textMuted:i.textSecondary,e.textAlign="right";let E=T.type;const F=80;if(e.measureText(E).width>F){for(;e.measureText(E+"...").width>F&&E.length>0;)E=E.slice(0,-1);E+="..."}e.fillText(E,a+l-12,M+4),e.textAlign="left",M+=b}if(u){const T=h.length-c;e.fillStyle=i.bgSecondary,e.beginPath(),e.roundRect(a+4,M,l-8,24,[0,0,d-4,d-4]),e.fill(),e.fillStyle=i.textSecondary,e.font="11px -apple-system, BlinkMacSystemFont, sans-serif",e.textAlign="center",e.fillText(`+ ${T} more field${T>1?"s":""}`,a+l/2,M+14),e.textAlign="left"}}getSortedFields(e){const t=["_id","_creationTime"];return[...e].sort((i,n)=>{const o=t.includes(i.name),s=t.includes(n.name);return o&&!s?-1:!o&&s?1:o&&s?t.indexOf(i.name)-t.indexOf(n.name):i.name.localeCompare(n.name)})}drawKeyIcon(e,t,i,n,o){e.save(),e.fillStyle=n?o.accentInteractive:o.warning,e.beginPath(),e.arc(t+4,i,4,0,Math.PI*2),e.fill(),e.fillRect(t+7,i-1,6,2),e.fillRect(t+10,i-1,1,3),e.fillRect(t+12,i-1,1,2),e.restore()}drawEdge(e,t,i,n){const o=this.hoveredNode&&(this.hoveredNode.id===n.from||this.hoveredNode.id===n.to),s=this.calculateAttachmentPoints(t,i),a=Math.sqrt(Math.pow(s.toX-s.fromX,2)+Math.pow(s.toY-s.fromY,2)),r=Math.min(a*.4,100);let l,d,h,c;s.fromSide==="right"?(l=s.fromX+r,d=s.fromY):s.fromSide==="left"?(l=s.fromX-r,d=s.fromY):s.fromSide==="bottom"?(l=s.fromX,d=s.fromY+r):(l=s.fromX,d=s.fromY-r),s.toSide==="left"?(h=s.toX-r,c=s.toY):s.toSide==="right"?(h=s.toX+r,c=s.toY):s.toSide==="top"?(h=s.toX,c=s.toY-r):(h=s.toX,c=s.toY+r),o&&(e.save(),e.shadowColor="rgba(235, 86, 1, 0.3)",e.shadowBlur=8,e.shadowOffsetX=0,e.shadowOffsetY=0),e.strokeStyle=o?"#EB5601":"#8b7355",e.lineWidth=o?2.5:1.5,n.inferred?e.setLineDash([6,4]):e.setLineDash([]),e.beginPath(),e.moveTo(s.fromX,s.fromY),e.bezierCurveTo(l,d,h,c,s.toX,s.toY),e.stroke(),e.setLineDash([]),o&&e.restore(),this.drawArrowHead(e,h,c,s.toX,s.toY,o);const p=.5,u=this.bezierPoint(s.fromX,l,h,s.toX,p),g=this.bezierPoint(s.fromY,d,c,s.toY,p)-12;e.font="10px -apple-system, BlinkMacSystemFont, sans-serif";const b=n.fromField,f=e.measureText(b).width+10,w=16;e.fillStyle=o?"rgba(235, 86, 1, 0.1)":"rgba(255, 255, 255, 0.95)",e.beginPath(),e.roundRect(u-f/2,g-w/2,f,w,4),e.fill(),e.strokeStyle=o?"rgba(235, 86, 1, 0.3)":"#e6e4e1",e.lineWidth=1,e.stroke(),e.fillStyle=o?"#EB5601":"#6b6b6b",e.textAlign="center",e.textBaseline="middle",e.fillText(b,u,g),e.textAlign="left",e.textBaseline="alphabetic"}calculateAttachmentPoints(e,t){const i=e.x+e.width/2,n=e.y+e.height/2,o=t.x+t.width/2,s=t.y+t.height/2,a=o-i,r=s-n;let l,d,h,c,p,u;return Math.abs(a)>Math.abs(r)?a>0?(l="right",d="left",h=e.x+e.width,c=n,p=t.x,u=s):(l="left",d="right",h=e.x,c=n,p=t.x+t.width,u=s):r>0?(l="bottom",d="top",h=i,c=e.y+e.height,p=o,u=t.y):(l="top",d="bottom",h=i,c=e.y,p=o,u=t.y+t.height),{fromX:h,fromY:c,fromSide:l,toX:p,toY:u,toSide:d}}drawArrowHead(e,t,i,n,o,s){const a=Math.atan2(o-i,n-t),r=s?10:8;e.fillStyle=s?"#EB5601":"#8b7355",e.beginPath(),e.moveTo(n,o),e.lineTo(n-r*Math.cos(a-Math.PI/6),o-r*Math.sin(a-Math.PI/6)),e.lineTo(n-r*Math.cos(a+Math.PI/6),o-r*Math.sin(a+Math.PI/6)),e.closePath(),e.fill()}bezierPoint(e,t,i,n,o){const s=1-o;return s*s*s*e+3*s*s*o*t+3*s*o*o*i+o*o*o*n}updateCodePanel(){var i,n,o,s;const e=document.getElementById("codeBlock"),t=document.querySelector(".code-filename");if(e&&this.selectedTable){const a=(n=(i=this.config)==null?void 0:i.tables)==null?void 0:n.find(l=>l.name===this.selectedTable),r=((s=(o=this.config)==null?void 0:o.allDocuments)==null?void 0:s[this.selectedTable])||[];if(a){const l={table:this.selectedTable,documentCount:a.documentCount,fields:{}};if(a.inferredFields)for(const d of a.inferredFields)l.fields[d.name]={type:d.type,required:!d.optional};r.length>0&&(l.sample=r[0]),e.innerHTML=this.syntaxHighlight(JSON.stringify(l,null,2))}}t&&this.selectedTable&&(t.textContent=`${this.selectedTable}.json`)}savePositionState(){const e={nodes:this.graphNodes.map(t=>({id:t.id,x:t.x,y:t.y})),panX:this.panX,panY:this.panY,zoom:this.zoom};this.historyIndex<this.positionHistory.length-1&&(this.positionHistory=this.positionHistory.slice(0,this.historyIndex+1)),this.positionHistory.push(e),this.positionHistory.length>this.maxHistorySize?this.positionHistory.shift():this.historyIndex++,this.updateUndoRedoButtons()}undo(){this.historyIndex<=0||(this.historyIndex--,this.restorePositionState(this.positionHistory[this.historyIndex]),this.updateUndoRedoButtons())}redo(){this.historyIndex>=this.positionHistory.length-1||(this.historyIndex++,this.restorePositionState(this.positionHistory[this.historyIndex]),this.updateUndoRedoButtons())}restorePositionState(e){for(const t of e.nodes){const i=this.graphNodes.find(n=>n.id===t.id);i&&(i.x=t.x,i.y=t.y)}this.panX=e.panX,this.panY=e.panY,this.zoom=e.zoom,this.updateZoomDisplay(),this.drawGraph()}updateUndoRedoButtons(){const e=document.getElementById("undoBtn"),t=document.getElementById("redoBtn");e&&(e.disabled=this.historyIndex<=0),t&&(t.disabled=this.historyIndex>=this.positionHistory.length-1)}fitToView(){if(this.graphNodes.length===0)return;const e=this.graphNodes.filter(p=>p.visible!==!1);if(e.length===0)return;const t=60,i=Math.min(...e.map(p=>p.x))-t,n=Math.max(...e.map(p=>p.x+p.width))+t,o=Math.min(...e.map(p=>p.y))-t,s=Math.max(...e.map(p=>p.y+p.height))+t,a=n-i,r=s-o;if(!this.canvas)return;const l=this.canvas.width/this.dpr,d=this.canvas.height/this.dpr,h=l/a,c=d/r;this.zoom=Math.min(h,c,1.5),this.zoom=Math.max(this.zoom,.25),this.panX=(l-a*this.zoom)/2-i*this.zoom,this.panY=(d-r*this.zoom)/2-o*this.zoom,this.updateZoomDisplay(),this.drawGraph()}autoArrange(){this.calculateGraphLayout(),this.drawGraph(),this.savePositionState()}updateZoomDisplay(){const e=document.getElementById("zoomLevel"),t=document.getElementById("zoomDisplay"),i=`${Math.round(this.zoom*100)}%`;e&&(e.textContent=i),t&&(t.textContent=i)}toggleCodePanel(){this.showCodePanel=!this.showCodePanel;const e=document.getElementById("sidebarContainer"),t=document.getElementById("viewCodeBtn");e&&e.classList.toggle("hidden",!this.showCodePanel),t&&t.classList.toggle("active",this.showCodePanel),setTimeout(()=>this.resizeCanvas(),50)}toggleExportMenu(){this.showExportMenu=!this.showExportMenu,this.showFilterDropdown=!1,this.renderDropdowns()}toggleFilterDropdown(){this.showFilterDropdown=!this.showFilterDropdown,this.showExportMenu=!1,this.renderDropdowns()}renderDropdowns(){var t,i;(t=document.getElementById("exportMenu"))==null||t.remove(),(i=document.getElementById("filterMenu"))==null||i.remove();const e=document.querySelector(".graph-view");e&&(this.showExportMenu&&(e.insertAdjacentHTML("beforeend",this.renderExportMenu()),this.setupExportMenuEvents()),this.showFilterDropdown&&(e.insertAdjacentHTML("beforeend",this.renderFilterDropdown()),this.setupFilterMenuEvents()))}setupExportMenuEvents(){var e,t,i;(e=document.getElementById("exportJson"))==null||e.addEventListener("click",()=>{this.exportSchema("json"),this.showExportMenu=!1,this.renderDropdowns()}),(t=document.getElementById("exportTs"))==null||t.addEventListener("click",()=>{this.exportSchema("typescript"),this.showExportMenu=!1,this.renderDropdowns()}),(i=document.getElementById("exportPng"))==null||i.addEventListener("click",()=>{this.exportAsPng(),this.showExportMenu=!1,this.renderDropdowns()}),setTimeout(()=>{document.addEventListener("click",this.handleOutsideClick.bind(this),{once:!0})},0)}setupFilterMenuEvents(){var e,t,i;(e=document.getElementById("filterClose"))==null||e.addEventListener("click",()=>{this.showFilterDropdown=!1,this.renderDropdowns()}),(t=document.getElementById("filterApply"))==null||t.addEventListener("click",()=>{this.applyFilters()}),(i=document.getElementById("filterClear"))==null||i.addEventListener("click",()=>{this.clearFilters()})}handleOutsideClick(e){const t=document.getElementById("exportMenu"),i=document.getElementById("exportBtn"),n=document.getElementById("filterMenu"),o=document.getElementById("filterBtn");t&&!t.contains(e.target)&&!(i!=null&&i.contains(e.target))&&(this.showExportMenu=!1,this.renderDropdowns()),n&&!n.contains(e.target)&&!(o!=null&&o.contains(e.target))&&(this.showFilterDropdown=!1,this.renderDropdowns())}exportSchema(e){var s;const t=((s=this.config)==null?void 0:s.tables)||[];let i,n,o;if(e==="json"){const a={};for(const r of t)a[r.name]={documentCount:r.documentCount,fields:(r.inferredFields||[]).reduce((l,d)=>(l[d.name]={type:d.type,required:!d.optional},l),{})};i=JSON.stringify(a,null,2),n="convex-schema.json",o="application/json"}else{const a=['import { defineSchema, defineTable } from "convex/server";','import { v } from "convex/values";',"","export default defineSchema({"];for(const r of t){const l=(r.inferredFields||[]).filter(d=>!d.name.startsWith("_")).map(d=>` ${d.name}: ${this.toConvexValidator(d.type)}${d.optional?".optional()":""},`).join(`
456
466
  `);a.push(` ${r.name}: defineTable({`),l&&a.push(l),a.push(" }),")}a.push("});"),i=a.join(`
457
- `),n="schema.ts",o="text/typescript"}this.downloadFile(i,n,o)}toConvexValidator(e){return e.startsWith("Id<")?`v.id(${e.slice(3,-1)})`:e==="string"?"v.string()":e==="number"?"v.number()":e==="boolean"?"v.boolean()":e==="null"?"v.null()":e.startsWith("array")?"v.array(v.any())":e==="object"?"v.object({})":"v.any()"}exportAsPng(){if(!this.canvas)return;const e=document.createElement("a");e.download="convex-schema-graph.png",e.href=this.canvas.toDataURL("image/png"),e.click()}downloadFile(e,t,i){const n=new Blob([e],{type:i}),o=URL.createObjectURL(n),s=document.createElement("a");s.href=o,s.download=t,s.click(),URL.revokeObjectURL(o)}applyFilters(){var o,s,a,r;const e=((o=document.getElementById("filterTableName"))==null?void 0:o.value)||"",t=((s=document.getElementById("filterFieldName"))==null?void 0:s.value)||"",i=((a=document.getElementById("filterFieldType"))==null?void 0:a.value)||"",n=((r=document.getElementById("filterShowEmpty"))==null?void 0:r.checked)??!0;this.filterState={tableName:e,fieldName:t,fieldType:i,showEmpty:n};for(const l of this.graphNodes){let d=!0;e&&!l.table.name.toLowerCase().includes(e.toLowerCase())&&(d=!1),!n&&l.table.documentCount===0&&(d=!1),d&&(t||i)&&((l.table.inferredFields||[]).some(p=>{const u=!t||p.name.toLowerCase().includes(t.toLowerCase()),g=!i||p.type.toLowerCase().includes(i.toLowerCase());return u&&g})||(d=!1)),l.visible=d}this.drawGraph(),this.showFilterDropdown=!1,this.renderDropdowns()}clearFilters(){this.filterState={tableName:"",fieldName:"",fieldType:"",showEmpty:!0};const e=document.getElementById("filterTableName"),t=document.getElementById("filterFieldName"),i=document.getElementById("filterFieldType"),n=document.getElementById("filterShowEmpty");e&&(e.value=""),t&&(t.value=""),i&&(i.value=""),n&&(n.checked=!0);for(const o of this.graphNodes)o.visible=!0;this.drawGraph()}setupEventListeners(){var e,t,i,n,o,s,a,r,l,d,h,c,p,u,g,b,f,w;if(document.querySelectorAll(".view-btn").forEach(y=>{y.addEventListener("click",v=>{const S=v.currentTarget.dataset.view;S&&S!==this.viewMode&&(this.viewMode=S,this.render())})}),(e=document.getElementById("refreshBtn"))==null||e.addEventListener("click",()=>this.refresh()),(t=document.getElementById("themeToggle"))==null||t.addEventListener("click",()=>this.toggleTheme()),this.viewMode==="graph"){(i=document.getElementById("viewCodeBtn"))==null||i.addEventListener("click",()=>this.toggleCodePanel()),(n=document.getElementById("exportBtn"))==null||n.addEventListener("click",v=>{v.stopPropagation(),this.toggleExportMenu()}),(o=document.getElementById("autoArrangeBtn"))==null||o.addEventListener("click",()=>this.autoArrange()),(s=document.getElementById("undoBtn"))==null||s.addEventListener("click",()=>this.undo()),(a=document.getElementById("redoBtn"))==null||a.addEventListener("click",()=>this.redo()),(r=document.getElementById("filterBtn"))==null||r.addEventListener("click",v=>{v.stopPropagation(),this.toggleFilterDropdown()}),(l=document.getElementById("zoomInToolbar"))==null||l.addEventListener("click",()=>{this.zoom=Math.min(2,this.zoom*1.2),this.updateZoomDisplay(),this.drawGraph()}),(d=document.getElementById("zoomOutToolbar"))==null||d.addEventListener("click",()=>{this.zoom=Math.max(.25,this.zoom/1.2),this.updateZoomDisplay(),this.drawGraph()}),(h=document.getElementById("fitViewBtn"))==null||h.addEventListener("click",()=>this.fitToView()),(c=document.getElementById("sectionHeaderTables"))==null||c.addEventListener("click",()=>{this.toggleSidebarSection("tables")}),(p=document.getElementById("sectionHeaderConvex"))==null||p.addEventListener("click",()=>{this.toggleSidebarSection("convex")}),(u=document.getElementById("sortBtn"))==null||u.addEventListener("click",()=>{this.cycleSortOrder()});const y=document.getElementById("graphSidebarSearch");y==null||y.addEventListener("input",v=>{this.searchQuery=v.target.value.toLowerCase(),this.updateSidebarTableList()}),(g=document.getElementById("graphSidebarToggle"))==null||g.addEventListener("click",()=>{this.graphSidebarCollapsed=!this.graphSidebarCollapsed;const v=document.getElementById("enhancedSidebar"),S=document.getElementById("graphSidebarToggle");if(v&&v.classList.toggle("collapsed",this.graphSidebarCollapsed),S){S.title=this.graphSidebarCollapsed?"Expand sidebar":"Collapse sidebar";const C=S.querySelector("svg path");C&&C.setAttribute("d",this.graphSidebarCollapsed?"M5 2L10 7L5 12":"M9 2L4 7L9 12")}setTimeout(()=>this.resizeCanvas(),50)}),this.setupSidebarTableEvents()}if((b=document.getElementById("sidebarToggle"))==null||b.addEventListener("click",()=>{this.sidebarCollapsed=!this.sidebarCollapsed;const y=document.getElementById("sidebarContainer"),v=document.getElementById("sidebarToggle");y&&y.classList.toggle("collapsed",this.sidebarCollapsed),v&&(v.title=this.sidebarCollapsed?"Show panel":"Hide panel"),this.viewMode==="graph"&&setTimeout(()=>this.resizeCanvas(),50)}),this.setupSidebarResize(),this.viewMode==="list"){(f=document.getElementById("prevPage"))==null||f.addEventListener("click",()=>this.changePage(-1)),(w=document.getElementById("nextPage"))==null||w.addEventListener("click",()=>this.changePage(1));const y=document.getElementById("searchInput");y==null||y.addEventListener("input",v=>{this.searchQuery=v.target.value.toLowerCase(),this.renderTableList()})}}setupSidebarResize(){const e=document.getElementById("resizeHandle");if(!e)return;let t=0,i=0;const n=s=>{if(!this.isResizingSidebar)return;const a=s.clientX-t,r=Math.max(180,Math.min(600,i+a));if(this.viewMode==="list"){this.sidebarWidth=r;const l=document.querySelector(".sidebar");l&&(l.style.width=r+"px")}else{this.codePanelWidth=r;const l=document.getElementById("codePanel");l&&(l.style.width=r+"px")}},o=()=>{this.isResizingSidebar=!1,e.classList.remove("dragging"),document.body.style.cursor="",document.body.style.userSelect="",document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",o),this.viewMode==="graph"&&this.resizeCanvas()};e.addEventListener("mousedown",s=>{s.preventDefault(),this.isResizingSidebar=!0,t=s.clientX,i=this.viewMode==="list"?this.sidebarWidth:this.codePanelWidth,e.classList.add("dragging"),document.body.style.cursor="col-resize",document.body.style.userSelect="none",document.addEventListener("mousemove",n),document.addEventListener("mouseup",o)})}resizeCanvas(){if(!this.canvas||!this.canvas.parentElement||!this.ctx)return;const e=this.canvas.parentElement.clientWidth,t=this.canvas.parentElement.clientHeight;this.dpr=window.devicePixelRatio||1,this.canvas.width=e*this.dpr,this.canvas.height=t*this.dpr,this.canvas.style.width=e+"px",this.canvas.style.height=t+"px",this.ctx.setTransform(1,0,0,1,0,0),this.ctx.scale(this.dpr,this.dpr),this.drawGraph()}setupKeyboardShortcuts(){document.addEventListener("keydown",e=>{var t,i;if(e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement){e.key==="Escape"&&e.target.blur();return}switch(e.key){case"r":this.refresh();break;case"g":this.viewMode=this.viewMode==="graph"?"list":"graph",this.render();break;case"b":(t=document.getElementById("sidebarToggle"))==null||t.click();break;case"c":this.viewMode==="graph"&&this.toggleCodePanel();break;case"a":this.viewMode==="graph"&&this.autoArrange();break;case"f":this.viewMode==="graph"&&this.fitToView();break;case"z":(e.metaKey||e.ctrlKey)&&this.viewMode==="graph"&&(e.preventDefault(),e.shiftKey?this.redo():this.undo());break;case"+":case"=":this.viewMode==="graph"&&(this.zoom=Math.min(2,this.zoom*1.2),this.updateZoomDisplay(),this.drawGraph());break;case"-":this.viewMode==="graph"&&(this.zoom=Math.max(.25,this.zoom/1.2),this.updateZoomDisplay(),this.drawGraph());break;case"ArrowLeft":this.viewMode==="list"&&this.changePage(-1);break;case"ArrowRight":this.viewMode==="list"&&this.changePage(1);break;case"ArrowUp":e.preventDefault(),this.viewMode==="list"&&this.navigateTable(-1);break;case"ArrowDown":e.preventDefault(),this.viewMode==="list"&&this.navigateTable(1);break;case"/":e.preventDefault(),(i=document.getElementById("searchInput"))==null||i.focus();break}})}renderTableList(){var n;const e=document.getElementById("tableList");if(!e)return;const t=((n=this.config)==null?void 0:n.tables)||[],i=t.filter(o=>o.name.toLowerCase().includes(this.searchQuery));if(i.length===0){e.innerHTML=`
467
+ `),n="schema.ts",o="text/typescript"}this.downloadFile(i,n,o)}toConvexValidator(e){return e.startsWith("Id<")?`v.id(${e.slice(3,-1)})`:e==="string"?"v.string()":e==="number"?"v.number()":e==="boolean"?"v.boolean()":e==="null"?"v.null()":e.startsWith("array")?"v.array(v.any())":e==="object"?"v.object({})":"v.any()"}exportAsPng(){if(!this.canvas)return;const e=document.createElement("a");e.download="convex-schema-graph.png",e.href=this.canvas.toDataURL("image/png"),e.click()}downloadFile(e,t,i){const n=new Blob([e],{type:i}),o=URL.createObjectURL(n),s=document.createElement("a");s.href=o,s.download=t,s.click(),URL.revokeObjectURL(o)}applyFilters(){var o,s,a,r;const e=((o=document.getElementById("filterTableName"))==null?void 0:o.value)||"",t=((s=document.getElementById("filterFieldName"))==null?void 0:s.value)||"",i=((a=document.getElementById("filterFieldType"))==null?void 0:a.value)||"",n=((r=document.getElementById("filterShowEmpty"))==null?void 0:r.checked)??!0;this.filterState={tableName:e,fieldName:t,fieldType:i,showEmpty:n};for(const l of this.graphNodes){let d=!0;e&&!l.table.name.toLowerCase().includes(e.toLowerCase())&&(d=!1),!n&&l.table.documentCount===0&&(d=!1),d&&(t||i)&&((l.table.inferredFields||[]).some(p=>{const u=!t||p.name.toLowerCase().includes(t.toLowerCase()),g=!i||p.type.toLowerCase().includes(i.toLowerCase());return u&&g})||(d=!1)),l.visible=d}this.drawGraph(),this.showFilterDropdown=!1,this.renderDropdowns()}clearFilters(){this.filterState={tableName:"",fieldName:"",fieldType:"",showEmpty:!0};const e=document.getElementById("filterTableName"),t=document.getElementById("filterFieldName"),i=document.getElementById("filterFieldType"),n=document.getElementById("filterShowEmpty");e&&(e.value=""),t&&(t.value=""),i&&(i.value=""),n&&(n.checked=!0);for(const o of this.graphNodes)o.visible=!0;this.drawGraph()}setupEventListeners(){var e,t,i,n,o,s,a,r,l,d,h,c,p,u,g,b,f,w;if(document.querySelectorAll(".view-btn").forEach(y=>{y.addEventListener("click",v=>{const C=v.currentTarget.dataset.view;C&&C!==this.viewMode&&(this.viewMode=C,this.render())})}),(e=document.getElementById("refreshBtn"))==null||e.addEventListener("click",()=>this.refresh()),(t=document.getElementById("themeToggle"))==null||t.addEventListener("click",()=>this.toggleTheme()),this.viewMode==="graph"){(i=document.getElementById("viewCodeBtn"))==null||i.addEventListener("click",()=>this.toggleCodePanel()),(n=document.getElementById("exportBtn"))==null||n.addEventListener("click",v=>{v.stopPropagation(),this.toggleExportMenu()}),(o=document.getElementById("autoArrangeBtn"))==null||o.addEventListener("click",()=>this.autoArrange()),(s=document.getElementById("undoBtn"))==null||s.addEventListener("click",()=>this.undo()),(a=document.getElementById("redoBtn"))==null||a.addEventListener("click",()=>this.redo()),(r=document.getElementById("filterBtn"))==null||r.addEventListener("click",v=>{v.stopPropagation(),this.toggleFilterDropdown()}),(l=document.getElementById("zoomInToolbar"))==null||l.addEventListener("click",()=>{this.zoom=Math.min(2,this.zoom*1.2),this.updateZoomDisplay(),this.drawGraph()}),(d=document.getElementById("zoomOutToolbar"))==null||d.addEventListener("click",()=>{this.zoom=Math.max(.25,this.zoom/1.2),this.updateZoomDisplay(),this.drawGraph()}),(h=document.getElementById("fitViewBtn"))==null||h.addEventListener("click",()=>this.fitToView()),(c=document.getElementById("sectionHeaderTables"))==null||c.addEventListener("click",()=>{this.toggleSidebarSection("tables")}),(p=document.getElementById("sectionHeaderConvex"))==null||p.addEventListener("click",()=>{this.toggleSidebarSection("convex")}),(u=document.getElementById("sortBtn"))==null||u.addEventListener("click",()=>{this.cycleSortOrder()});const y=document.getElementById("graphSidebarSearch");y==null||y.addEventListener("input",v=>{this.searchQuery=v.target.value.toLowerCase(),this.updateSidebarTableList()}),(g=document.getElementById("graphSidebarToggle"))==null||g.addEventListener("click",()=>{this.graphSidebarCollapsed=!this.graphSidebarCollapsed;const v=document.getElementById("enhancedSidebar"),C=document.getElementById("graphSidebarToggle");if(v&&v.classList.toggle("collapsed",this.graphSidebarCollapsed),C){C.title=this.graphSidebarCollapsed?"Expand sidebar":"Collapse sidebar";const S=C.querySelector("svg path");S&&S.setAttribute("d",this.graphSidebarCollapsed?"M5 2L10 7L5 12":"M9 2L4 7L9 12")}setTimeout(()=>this.resizeCanvas(),50)}),this.setupSidebarTableEvents()}if((b=document.getElementById("sidebarToggle"))==null||b.addEventListener("click",()=>{this.sidebarCollapsed=!this.sidebarCollapsed;const y=document.getElementById("sidebarContainer"),v=document.getElementById("sidebarToggle");y&&y.classList.toggle("collapsed",this.sidebarCollapsed),v&&(v.title=this.sidebarCollapsed?"Show panel":"Hide panel"),this.viewMode==="graph"&&setTimeout(()=>this.resizeCanvas(),50)}),this.setupSidebarResize(),this.viewMode==="list"){(f=document.getElementById("prevPage"))==null||f.addEventListener("click",()=>this.changePage(-1)),(w=document.getElementById("nextPage"))==null||w.addEventListener("click",()=>this.changePage(1));const y=document.getElementById("searchInput");y==null||y.addEventListener("input",v=>{this.searchQuery=v.target.value.toLowerCase(),this.renderTableList()})}}setupSidebarResize(){const e=document.getElementById("resizeHandle");if(!e)return;let t=0,i=0;const n=s=>{if(!this.isResizingSidebar)return;const a=s.clientX-t,r=Math.max(180,Math.min(600,i+a));if(this.viewMode==="list"){this.sidebarWidth=r;const l=document.querySelector(".sidebar");l&&(l.style.width=r+"px")}else{this.codePanelWidth=r;const l=document.getElementById("codePanel");l&&(l.style.width=r+"px")}},o=()=>{this.isResizingSidebar=!1,e.classList.remove("dragging"),document.body.style.cursor="",document.body.style.userSelect="",document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",o),this.viewMode==="graph"&&this.resizeCanvas()};e.addEventListener("mousedown",s=>{s.preventDefault(),this.isResizingSidebar=!0,t=s.clientX,i=this.viewMode==="list"?this.sidebarWidth:this.codePanelWidth,e.classList.add("dragging"),document.body.style.cursor="col-resize",document.body.style.userSelect="none",document.addEventListener("mousemove",n),document.addEventListener("mouseup",o)})}resizeCanvas(){if(!this.canvas||!this.canvas.parentElement||!this.ctx)return;const e=this.canvas.parentElement.clientWidth,t=this.canvas.parentElement.clientHeight;this.dpr=window.devicePixelRatio||1,this.canvas.width=e*this.dpr,this.canvas.height=t*this.dpr,this.canvas.style.width=e+"px",this.canvas.style.height=t+"px",this.ctx.setTransform(1,0,0,1,0,0),this.ctx.scale(this.dpr,this.dpr),this.drawGraph()}setupKeyboardShortcuts(){document.addEventListener("keydown",e=>{var t,i;if(e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement){e.key==="Escape"&&e.target.blur();return}switch(e.key){case"r":this.refresh();break;case"g":this.viewMode=this.viewMode==="graph"?"list":"graph",this.render();break;case"b":(t=document.getElementById("sidebarToggle"))==null||t.click();break;case"c":this.viewMode==="graph"&&this.toggleCodePanel();break;case"a":this.viewMode==="graph"&&this.autoArrange();break;case"f":this.viewMode==="graph"&&this.fitToView();break;case"z":(e.metaKey||e.ctrlKey)&&this.viewMode==="graph"&&(e.preventDefault(),e.shiftKey?this.redo():this.undo());break;case"+":case"=":this.viewMode==="graph"&&(this.zoom=Math.min(2,this.zoom*1.2),this.updateZoomDisplay(),this.drawGraph());break;case"-":this.viewMode==="graph"&&(this.zoom=Math.max(.25,this.zoom/1.2),this.updateZoomDisplay(),this.drawGraph());break;case"ArrowLeft":this.viewMode==="list"&&this.changePage(-1);break;case"ArrowRight":this.viewMode==="list"&&this.changePage(1);break;case"ArrowUp":e.preventDefault(),this.viewMode==="list"&&this.navigateTable(-1);break;case"ArrowDown":e.preventDefault(),this.viewMode==="list"&&this.navigateTable(1);break;case"/":e.preventDefault(),(i=document.getElementById("searchInput"))==null||i.focus();break}})}renderTableList(){var n;const e=document.getElementById("tableList");if(!e)return;const t=((n=this.config)==null?void 0:n.tables)||[],i=t.filter(o=>o.name.toLowerCase().includes(this.searchQuery));if(i.length===0){e.innerHTML=`
458
468
  <li class="empty-state" style="padding: 30px 20px;">
459
469
  <p>${t.length===0?"No tables found":"No matching tables"}</p>
460
470
  </li>
461
471
  `;return}e.innerHTML=i.map(o=>`
462
472
  <li class="table-item ${o.name===this.selectedTable?"active":""}" data-table="${o.name}">
463
473
  <span class="table-name">
464
- <span class="table-icon">☰</span>
474
+ <svg class="table-icon" width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5">
475
+ <rect x="1" y="1" width="12" height="12" rx="2"/>
476
+ <path d="M1 5H13M5 5V13"/>
477
+ </svg>
465
478
  ${o.name}
466
479
  </span>
467
480
  <span class="table-count">${this.formatCount(o.documentCount)}</span>
@@ -2,7 +2,14 @@
2
2
  * Convex Client Wrapper
3
3
  *
4
4
  * Handles authentication and communication with Convex Cloud.
5
- * Uses Convex system APIs to fetch schema information.
5
+ * Uses Convex system APIs to fetch schema and document information.
6
+ *
7
+ * System queries used:
8
+ * - /api/shapes2 for inferred schema
9
+ * - _system/frontend/getSchemas for declared schema
10
+ * - _system/cli/tables for table list
11
+ * - _system/cli/tableSize:default for document counts
12
+ * - _system/cli/tableData for paginated document retrieval
6
13
  */
7
14
  export interface TableInfo {
8
15
  name: string;
@@ -31,31 +38,52 @@ export interface ConnectionTestResult {
31
38
  tables?: string[];
32
39
  error?: string;
33
40
  }
41
+ export interface PaginatedResult<T> {
42
+ documents: T[];
43
+ continueCursor?: string;
44
+ isDone: boolean;
45
+ }
34
46
  export declare class ConvexClient {
35
47
  private deploymentUrl;
36
48
  private adminKey;
37
49
  constructor();
38
50
  private initialize;
51
+ /**
52
+ * Check if admin key is available for system queries
53
+ */
54
+ hasAdminAccess(): boolean;
39
55
  isConnected(): boolean;
40
56
  getDeploymentUrl(): string | null;
41
57
  private fetchConvex;
42
58
  testConnection(): Promise<ConnectionTestResult>;
43
59
  listTables(): Promise<TableInfo[]>;
60
+ /**
61
+ * Get document count for a table using system query
62
+ */
63
+ getTableCount(tableName: string): Promise<number>;
44
64
  getTableSchema(tableName: string): Promise<TableSchema>;
45
65
  private parseShapeToFields;
46
66
  private shapeToTypeString;
47
67
  private parseDocumentTypeToFields;
48
68
  private docTypeToString;
69
+ /**
70
+ * Query documents from a table using system query
71
+ * Requires admin access for document retrieval
72
+ */
49
73
  queryDocuments(tableName: string, options?: {
50
74
  limit?: number;
51
75
  cursor?: string;
52
- orderBy?: string;
53
- order?: 'asc' | 'desc';
54
- }): Promise<{
55
- documents: Document[];
56
- nextCursor?: string;
57
- }>;
76
+ order?: "asc" | "desc";
77
+ }): Promise<PaginatedResult<Document>>;
78
+ /**
79
+ * Get sample documents from all tables
80
+ * Fetches up to DEFAULT_DOC_SAMPLE_LIMIT documents per table
81
+ */
58
82
  getAllDocuments(): Promise<Record<string, Document[]>>;
59
- runQuery(queryString: string): Promise<unknown>;
83
+ /**
84
+ * Run a custom query function by path
85
+ * Requires admin access
86
+ */
87
+ runQuery(queryPath: string, args?: Record<string, unknown>): Promise<unknown>;
60
88
  }
61
89
  //# sourceMappingURL=convex-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convex-client.d.ts","sourceRoot":"","sources":["../src/convex-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,WAAW,EAAE,CAAC;IAC9B,cAAc,EAAE,WAAW,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAuB;;IAMvC,OAAO,CAAC,UAAU;IAkElB,WAAW,IAAI,OAAO;IAItB,gBAAgB,IAAI,MAAM,GAAG,IAAI;YAInB,WAAW;IA2BnB,cAAc,IAAI,OAAO,CAAC,oBAAoB,CAAC;IA4B/C,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA2DlC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAoD7D,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IAkCzB,OAAO,CAAC,yBAAyB;IAgBjC,OAAO,CAAC,eAAe;IAoBjB,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;KACnB,GACL,OAAO,CAAC;QAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAepD,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAWtD,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAOtD"}
1
+ {"version":3,"file":"convex-client.d.ts","sourceRoot":"","sources":["../src/convex-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,WAAW,EAAE,CAAC;IAC9B,cAAc,EAAE,WAAW,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,SAAS,EAAE,CAAC,EAAE,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAuB;;IAMvC,OAAO,CAAC,UAAU;IAsGlB;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB,WAAW,IAAI,OAAO;IAItB,gBAAgB,IAAI,MAAM,GAAG,IAAI;YAInB,WAAW;IA6BnB,cAAc,IAAI,OAAO,CAAC,oBAAoB,CAAC;IA6B/C,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA+ExC;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBjD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA2D7D,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IA8CzB,OAAO,CAAC,yBAAyB;IAkBjC,OAAO,CAAC,eAAe;IA2BvB;;;OAGG;IACG,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;KACnB,GACL,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IA4CrC;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IA+B5D;;;OAGG;IACG,QAAQ,CACZ,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,OAAO,CAAC;CAmBpB"}