tinbase 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/assets/logo.svg +9 -13
  2. package/dist/admin/ui.d.ts +1 -1
  3. package/dist/admin/ui.js +1 -1
  4. package/dist/auth/handler.d.ts +25 -0
  5. package/dist/auth/handler.js +127 -8
  6. package/dist/auth/handler.js.map +1 -1
  7. package/dist/auth/oauth.d.ts +1 -0
  8. package/dist/auth/oauth.js +28 -9
  9. package/dist/auth/oauth.js.map +1 -1
  10. package/dist/cron/service.js +2 -1
  11. package/dist/cron/service.js.map +1 -1
  12. package/dist/db/bootstrap.d.ts +2 -2
  13. package/dist/db/bootstrap.js +19 -0
  14. package/dist/db/bootstrap.js.map +1 -1
  15. package/dist/db/database.d.ts +3 -1
  16. package/dist/db/database.js +6 -1
  17. package/dist/db/database.js.map +1 -1
  18. package/dist/db/emulated.d.ts +3 -3
  19. package/dist/db/emulated.js +46 -13
  20. package/dist/db/emulated.js.map +1 -1
  21. package/dist/functions/deno-shim.d.ts +3 -2
  22. package/dist/functions/deno-shim.js +12 -4
  23. package/dist/functions/deno-shim.js.map +1 -1
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.js +20 -4
  26. package/dist/index.js.map +1 -1
  27. package/dist/jwt.js +5 -0
  28. package/dist/jwt.js.map +1 -1
  29. package/dist/net/service.d.ts +9 -0
  30. package/dist/net/service.js +97 -10
  31. package/dist/net/service.js.map +1 -1
  32. package/dist/node/ws.d.ts +9 -0
  33. package/dist/node/ws.js +8 -2
  34. package/dist/node/ws.js.map +1 -1
  35. package/dist/realtime/engine.js +19 -1
  36. package/dist/realtime/engine.js.map +1 -1
  37. package/dist/retention/service.d.ts +37 -0
  38. package/dist/retention/service.js +66 -0
  39. package/dist/retention/service.js.map +1 -0
  40. package/dist/storage/handler.js +48 -21
  41. package/dist/storage/handler.js.map +1 -1
  42. package/dist/types.d.ts +14 -0
  43. package/dist/types.js.map +1 -1
  44. package/package.json +1 -1
package/dist/admin/ui.js CHANGED
@@ -61,7 +61,7 @@ Error generating stack: \`+e.message+\`
61
61
  \`},On=function(){var e=parseInt(document.body.getAttribute(\`data-scroll-locked\`)||\`0\`,10);return isFinite(e)?e:0},kn=function(){_.useEffect(function(){return document.body.setAttribute(En,(On()+1).toString()),function(){var e=On()-1;e<=0?document.body.removeAttribute(En):document.body.setAttribute(En,e.toString())}},[])},An=function(e){var t=e.noRelative,n=e.noImportant,r=e.gapMode,i=r===void 0?\`margin\`:r;kn();var a=_.useMemo(function(){return wn(i)},[i]);return _.createElement(Tn,{styles:Dn(a,!t,i,n?\`\`:\`!important\`)})},jn=!1;if(typeof window<\`u\`)try{var Mn=Object.defineProperty({},"passive",{get:function(){return jn=!0,!0}});window.addEventListener(\`test\`,Mn,Mn),window.removeEventListener(\`test\`,Mn,Mn)}catch{jn=!1}var Nn=jn?{passive:!1}:!1,Pn=function(e){return e.tagName===\`TEXTAREA\`},Fn=function(e,t){if(!(e instanceof Element))return!1;var n=window.getComputedStyle(e);return n[t]!==\`hidden\`&&!(n.overflowY===n.overflowX&&!Pn(e)&&n[t]===\`visible\`)},In=function(e){return Fn(e,\`overflowY\`)},Ln=function(e){return Fn(e,\`overflowX\`)},Rn=function(e,t){var n=t.ownerDocument,r=t;do{if(typeof ShadowRoot<\`u\`&&r instanceof ShadowRoot&&(r=r.host),Vn(e,r)){var i=Hn(e,r);if(i[1]>i[2])return!0}r=r.parentNode}while(r&&r!==n.body);return!1},zn=function(e){return[e.scrollTop,e.scrollHeight,e.clientHeight]},Bn=function(e){return[e.scrollLeft,e.scrollWidth,e.clientWidth]},Vn=function(e,t){return e===\`v\`?In(t):Ln(t)},Hn=function(e,t){return e===\`v\`?zn(t):Bn(t)},Un=function(e,t){return e===\`h\`&&t===\`rtl\`?-1:1},Wn=function(e,t,n,r,i){var a=Un(e,window.getComputedStyle(t).direction),o=a*r,s=n.target,c=t.contains(s),l=!1,u=o>0,d=0,f=0;do{if(!s)break;var p=Hn(e,s),m=p[0],h=p[1]-p[2]-a*m;(m||h)&&Vn(e,s)&&(d+=h,f+=m);var g=s.parentNode;s=g&&g.nodeType===Node.DOCUMENT_FRAGMENT_NODE?g.host:g}while(!c&&s!==document.body||c&&(t.contains(s)||t===s));return(u&&(i&&Math.abs(d)<1||!i&&o>d)||!u&&(i&&Math.abs(f)<1||!i&&-o>f))&&(l=!0),l},Gn=function(e){return\`changedTouches\`in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]},Kn=function(e){return[e.deltaX,e.deltaY]},qn=function(e){return e&&\`current\`in e?e.current:e},Jn=function(e,t){return e[0]===t[0]&&e[1]===t[1]},Yn=function(e){return\`
62
62
  .block-interactivity-\${e} {pointer-events: none;}
63
63
  .allow-interactivity-\${e} {pointer-events: all;}
64
- \`},Xn=0,Zn=[];function Qn(e){var t=_.useRef([]),n=_.useRef([0,0]),r=_.useRef(),i=_.useState(Xn++)[0],a=_.useState(bn)[0],o=_.useRef(e);_.useEffect(function(){o.current=e},[e]),_.useEffect(function(){if(e.inert){document.body.classList.add(\`block-interactivity-\${i}\`);var t=Jt([e.lockRef.current],(e.shards||[]).map(qn),!0).filter(Boolean);return t.forEach(function(e){return e.classList.add(\`allow-interactivity-\${i}\`)}),function(){document.body.classList.remove(\`block-interactivity-\${i}\`),t.forEach(function(e){return e.classList.remove(\`allow-interactivity-\${i}\`)})}}},[e.inert,e.lockRef.current,e.shards]);var s=_.useCallback(function(e,t){if(\`touches\`in e&&e.touches.length===2||e.type===\`wheel\`&&e.ctrlKey)return!o.current.allowPinchZoom;var i=Gn(e),a=n.current,s=\`deltaX\`in e?e.deltaX:a[0]-i[0],c=\`deltaY\`in e?e.deltaY:a[1]-i[1],l,u=e.target,d=Math.abs(s)>Math.abs(c)?\`h\`:\`v\`;if(\`touches\`in e&&d===\`h\`&&u.type===\`range\`)return!1;var f=window.getSelection(),p=f&&f.anchorNode;if(p&&(p===u||p.contains(u)))return!1;var m=Rn(d,u);if(!m)return!0;if(m?l=d:(l=d===\`v\`?\`h\`:\`v\`,m=Rn(d,u)),!m)return!1;if(!r.current&&\`changedTouches\`in e&&(s||c)&&(r.current=l),!l)return!0;var h=r.current||l;return Wn(h,t,e,h===\`h\`?s:c,!0)},[]),c=_.useCallback(function(e){var n=e;if(!(!Zn.length||Zn[Zn.length-1]!==a)){var r=\`deltaY\`in n?Kn(n):Gn(n),i=t.current.filter(function(e){return e.name===n.type&&(e.target===n.target||n.target===e.shadowParent)&&Jn(e.delta,r)})[0];if(i&&i.should){n.cancelable&&n.preventDefault();return}if(!i){var c=(o.current.shards||[]).map(qn).filter(Boolean).filter(function(e){return e.contains(n.target)});(c.length>0?s(n,c[0]):!o.current.noIsolation)&&n.cancelable&&n.preventDefault()}}},[]),l=_.useCallback(function(e,n,r,i){var a={name:e,delta:n,target:r,should:i,shadowParent:$n(r)};t.current.push(a),setTimeout(function(){t.current=t.current.filter(function(e){return e!==a})},1)},[]),u=_.useCallback(function(e){n.current=Gn(e),r.current=void 0},[]),d=_.useCallback(function(t){l(t.type,Kn(t),t.target,s(t,e.lockRef.current))},[]),f=_.useCallback(function(t){l(t.type,Gn(t),t.target,s(t,e.lockRef.current))},[]);_.useEffect(function(){return Zn.push(a),e.setCallbacks({onScrollCapture:d,onWheelCapture:d,onTouchMoveCapture:f}),document.addEventListener(\`wheel\`,c,Nn),document.addEventListener(\`touchmove\`,c,Nn),document.addEventListener(\`touchstart\`,u,Nn),function(){Zn=Zn.filter(function(e){return e!==a}),document.removeEventListener(\`wheel\`,c,Nn),document.removeEventListener(\`touchmove\`,c,Nn),document.removeEventListener(\`touchstart\`,u,Nn)}},[]);var p=e.removeScrollBar,m=e.inert;return _.createElement(_.Fragment,null,m?_.createElement(a,{styles:Yn(i)}):null,p?_.createElement(An,{noRelative:e.noRelative,gapMode:e.gapMode}):null)}function $n(e){for(var t=null;e!==null;)e instanceof ShadowRoot&&(t=e.host,e=e.host),e=e.parentNode;return t}var er=ln(un,Qn),tr=_.forwardRef(function(e,t){return _.createElement(fn,Kt({},e,{ref:t,sideCar:er}))});tr.classNames=fn.classNames;var nr=function(e){return typeof document>\`u\`?null:(Array.isArray(e)?e[0]:e).ownerDocument.body},rr=new WeakMap,ir=new WeakMap,ar={},or=0,sr=function(e){return e&&(e.host||sr(e.parentNode))},cr=function(e,t){return t.map(function(t){if(e.contains(t))return t;var n=sr(t);return n&&e.contains(n)?n:(console.error(\`aria-hidden\`,t,\`in not contained inside\`,e,\`. Doing nothing\`),null)}).filter(function(e){return!!e})},lr=function(e,t,n,r){var i=cr(t,Array.isArray(e)?e:[e]);ar[n]||(ar[n]=new WeakMap);var a=ar[n],o=[],s=new Set,c=new Set(i),l=function(e){!e||s.has(e)||(s.add(e),l(e.parentNode))};i.forEach(l);var u=function(e){!e||c.has(e)||Array.prototype.forEach.call(e.children,function(e){if(s.has(e))u(e);else try{var t=e.getAttribute(r),i=t!==null&&t!==\`false\`,c=(rr.get(e)||0)+1,l=(a.get(e)||0)+1;rr.set(e,c),a.set(e,l),o.push(e),c===1&&i&&ir.set(e,!0),l===1&&e.setAttribute(n,\`true\`),i||e.setAttribute(r,\`true\`)}catch(t){console.error(\`aria-hidden: cannot operate on \`,e,t)}})};return u(t),s.clear(),or++,function(){o.forEach(function(e){var t=rr.get(e)-1,i=a.get(e)-1;rr.set(e,t),a.set(e,i),t||(ir.has(e)||e.removeAttribute(r),ir.delete(e)),i||e.removeAttribute(n)}),or--,or||(rr=new WeakMap,rr=new WeakMap,ir=new WeakMap,ar={})}},ur=function(e,t,n){n===void 0&&(n=\`data-aria-hidden\`);var r=Array.from(Array.isArray(e)?e:[e]),i=t||nr(e);return i?(r.push.apply(r,Array.from(i.querySelectorAll(\`[aria-live], script\`))),lr(r,i,n,\`aria-hidden\`)):function(){return null}},dr=\`Dialog\`,[fr,pr]=ke(dr),[mr,hr]=fr(dr),gr=e=>{let{__scopeDialog:t,children:n,open:r,defaultOpen:i,onOpenChange:a,modal:o=!0}=e,s=_.useRef(null),c=_.useRef(null),[l,u]=ze({prop:r,defaultProp:i??!1,onChange:a,caller:dr});return(0,j.jsx)(mr,{scope:t,triggerRef:s,contentRef:c,contentId:Pe(),titleId:Pe(),descriptionId:Pe(),open:l,onOpenChange:u,onOpenToggle:_.useCallback(()=>u(e=>!e),[u]),modal:o,children:n})};gr.displayName=dr;var _r=\`DialogTrigger\`,vr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(_r,n),a=De(t,i.triggerRef);return(0,j.jsx)(tt.button,{type:\`button\`,"aria-haspopup":\`dialog\`,"aria-expanded":i.open,"aria-controls":i.open?i.contentId:void 0,"data-state":Rr(i.open),...r,ref:a,onClick:we(e.onClick,i.onOpenToggle)})});vr.displayName=_r;var yr=\`DialogPortal\`,[br,xr]=fr(yr,{forceMount:void 0}),Sr=e=>{let{__scopeDialog:t,forceMount:n,children:r,container:i}=e,a=hr(yr,t);return(0,j.jsx)(br,{scope:t,forceMount:n,children:_.Children.map(r,e=>(0,j.jsx)(It,{present:n||a.open,children:(0,j.jsx)(Pt,{asChild:!0,container:i,children:e})}))})};Sr.displayName=yr;var Cr=\`DialogOverlay\`,wr=_.forwardRef((e,t)=>{let n=xr(Cr,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=hr(Cr,e.__scopeDialog);return a.modal?(0,j.jsx)(It,{present:r||a.open,children:(0,j.jsx)(Er,{...i,ref:t})}):null});wr.displayName=Cr;var Tr=Ue(\`DialogOverlay.RemoveScroll\`),Er=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Cr,n),a=De(t,pt());return(0,j.jsx)(tr,{as:Tr,allowPinchZoom:!0,shards:[i.contentRef],children:(0,j.jsx)(tt.div,{"data-state":Rr(i.open),...r,ref:a,style:{pointerEvents:\`auto\`,...r.style}})})}),Dr=\`DialogContent\`,Or=_.forwardRef((e,t)=>{let n=xr(Dr,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=hr(Dr,e.__scopeDialog);return(0,j.jsx)(It,{present:r||a.open,children:a.modal?(0,j.jsx)(kr,{...i,ref:t}):(0,j.jsx)(Ar,{...i,ref:t})})});Or.displayName=Dr;var kr=_.forwardRef((e,t)=>{let n=hr(Dr,e.__scopeDialog),r=_.useRef(null),i=De(t,n.contentRef,r);return _.useEffect(()=>{let e=r.current;if(e)return ur(e)},[]),(0,j.jsx)(jr,{...e,ref:i,trapFocus:n.open,disableOutsidePointerEvents:n.open,onCloseAutoFocus:we(e.onCloseAutoFocus,e=>{e.preventDefault(),n.triggerRef.current?.focus()}),onPointerDownOutside:we(e.onPointerDownOutside,e=>{let t=e.detail.originalEvent,n=t.button===0&&t.ctrlKey===!0;(t.button===2||n)&&e.preventDefault()}),onFocusOutside:we(e.onFocusOutside,e=>e.preventDefault())})}),Ar=_.forwardRef((e,t)=>{let n=hr(Dr,e.__scopeDialog),r=_.useRef(!1),i=_.useRef(!1);return(0,j.jsx)(jr,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{e.onCloseAutoFocus?.(t),t.defaultPrevented||(r.current||n.triggerRef.current?.focus(),t.preventDefault()),r.current=!1,i.current=!1},onInteractOutside:t=>{e.onInteractOutside?.(t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type===\`pointerdown\`&&(i.current=!0));let a=t.target;n.triggerRef.current?.contains(a)&&t.preventDefault(),t.detail.originalEvent.type===\`focusin\`&&i.current&&t.preventDefault()}})}),jr=_.forwardRef((e,t)=>{let{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:i,onCloseAutoFocus:a,...o}=e,s=hr(Dr,n);return Wt(),(0,j.jsx)(j.Fragment,{children:(0,j.jsx)(St,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:i,onUnmountAutoFocus:a,children:(0,j.jsx)(ut,{role:\`dialog\`,id:s.contentId,"aria-describedby":s.descriptionId,"aria-labelledby":s.titleId,"data-state":Rr(s.open),...o,ref:t,deferPointerDownOutside:!0,onDismiss:()=>s.onOpenChange(!1)})})})}),Mr=\`DialogTitle\`,Nr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Mr,n);return(0,j.jsx)(tt.h2,{id:i.titleId,...r,ref:t})});Nr.displayName=Mr;var Pr=\`DialogDescription\`,Fr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Pr,n);return(0,j.jsx)(tt.p,{id:i.descriptionId,...r,ref:t})});Fr.displayName=Pr;var Ir=\`DialogClose\`,Lr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Ir,n);return(0,j.jsx)(tt.button,{type:\`button\`,...r,ref:t,onClick:we(e.onClick,()=>i.onOpenChange(!1))})});Lr.displayName=Ir;function Rr(e){return e?\`open\`:\`closed\`}function zr(e){var t,n,r=\`\`;if(typeof e==\`string\`||typeof e==\`number\`)r+=e;else if(typeof e==\`object\`)if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=zr(e[t]))&&(r&&(r+=\` \`),r+=n)}else for(n in e)e[n]&&(r&&(r+=\` \`),r+=n);return r}function Br(){for(var e,t,n=0,r=\`\`,i=arguments.length;n<i;n++)(e=arguments[n])&&(t=zr(e))&&(r&&(r+=\` \`),r+=t);return r}function N({variant:e=\`default\`,size:t=\`sm\`,className:n,...r}){return(0,j.jsx)(\`button\`,{className:Br(\`inline-flex items-center justify-center gap-1.5 rounded-md transition-colors disabled:opacity-50 disabled:pointer-events-none\`,t===\`sm\`?\`h-8 px-3 text-[13px]\`:\`h-6 px-2 text-xs\`,{default:\`bg-emerald-600 text-white hover:bg-emerald-500 font-medium\`,outline:\`border border-neutral-700 text-neutral-200 hover:bg-neutral-800 hover:border-neutral-600\`,ghost:\`text-neutral-300 hover:bg-neutral-800\`,danger:\`border border-red-900/60 text-red-400 hover:bg-red-950/40\`}[e],n),...r})}function Vr({className:e,...t}){return(0,j.jsx)(\`input\`,{className:Br(\`h-8 w-full rounded-md border border-neutral-700 bg-neutral-900 px-2.5 text-[13px] text-neutral-100\`,\`placeholder:text-neutral-600 focus:border-brand focus:outline-none\`,e),...t})}function Hr({className:e,...t}){return(0,j.jsx)(\`textarea\`,{className:Br(\`w-full rounded-md border border-neutral-700 bg-neutral-900 p-3 font-mono text-[13px] text-neutral-100\`,\`placeholder:text-neutral-600 focus:border-brand focus:outline-none\`,e),...t})}function Ur({children:e}){return(0,j.jsx)(\`label\`,{className:\`mb-1 block text-xs font-medium text-neutral-400\`,children:e})}function Wr({open:e,onClose:t,title:n,children:r,wide:i}){return(0,j.jsx)(gr,{open:e,onOpenChange:e=>!e&&t(),children:(0,j.jsxs)(Sr,{children:[(0,j.jsx)(wr,{className:\`fixed inset-0 z-50 bg-black/60 backdrop-blur-sm\`}),(0,j.jsxs)(Or,{className:Br(\`fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2 rounded-lg border border-neutral-700 bg-neutral-850 bg-[#1f1f1f] shadow-2xl\`,\`max-h-[85vh] overflow-auto\`,i?\`w-[640px]\`:\`w-[440px]\`),children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between border-b border-neutral-800 px-4 py-3\`,children:[(0,j.jsx)(Nr,{className:\`text-sm font-semibold\`,children:n}),(0,j.jsx)(Lr,{className:\`text-neutral-500 hover:text-neutral-200\`,children:(0,j.jsx)(ve,{size:16})})]}),(0,j.jsx)(\`div\`,{className:\`p-4\`,children:r})]})]})})}function Gr(){return(0,j.jsx)(\`div\`,{className:\`flex items-center justify-center py-16 text-neutral-500\`,children:(0,j.jsx)(\`div\`,{className:\`size-5 animate-spin rounded-full border-2 border-neutral-700 border-t-brand\`})})}function Kr({children:e}){return(0,j.jsx)(\`div\`,{className:\`py-16 text-center text-[13px] text-neutral-500\`,children:e})}var qr=50;function Jr(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)(0),[c,l]=(0,_.useState)(0),[u,d]=(0,_.useState)(!0),[f,p]=(0,_.useState)(null),[m,h]=(0,_.useState)(!1),[g,v]=(0,_.useState)(\`\`),y=e.find(e=>e.name===n)||null,b=(0,_.useCallback)(async()=>{let e=await A.tables();t(e),r(t=>t??e[0]?.name??null)},[]);(0,_.useEffect)(()=>{b().finally(()=>d(!1))},[b]);let x=(0,_.useCallback)(async()=>{if(!n||!y)return;let e=y.primaryKey[0]?\`\${y.primaryKey[0]}.asc\`:void 0,{rows:t,total:r}=await A.rows(n,{limit:qr,offset:c*qr,order:e});a(t),s(r)},[n,c,y]);(0,_.useEffect)(()=>{x()},[x]);function ee(e){let t={};for(let n of y.primaryKey)t[n]=e[n];return t}async function S(e){if(!y?.primaryKey.length)return alert(\`Cannot delete: table has no primary key\`);if(confirm(\`Delete this row?\`))try{await A.deleteRow(n,ee(e)),await x(),await b()}catch(e){alert(e.message)}}return u?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex w-60 shrink-0 flex-col border-r border-neutral-800 bg-[#191919]\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between px-3 py-2.5 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:[\`Tables \`,(0,j.jsx)(\`span\`,{className:\`text-neutral-600\`,children:e.length})]}),(0,j.jsxs)(\`div\`,{className:\`flex-1 overflow-auto\`,children:[e.map(e=>(0,j.jsxs)(\`button\`,{onClick:()=>{r(e.name),l(0)},className:\`flex w-full items-center justify-between px-3 py-1.5 text-left text-[13px] \`+(n===e.name?\`bg-neutral-800 text-neutral-100\`:\`text-neutral-400 hover:bg-neutral-850 hover:bg-neutral-800/50\`),children:[(0,j.jsx)(\`span\`,{className:\`truncate font-mono\`,children:e.name}),(0,j.jsx)(\`span\`,{className:\`text-[11px] text-neutral-600\`,children:e.rowCount})]},e.name)),e.length===0&&(0,j.jsx)(Kr,{children:\`No tables. Create one in the SQL Editor.\`})]})]}),(0,j.jsx)(\`div\`,{className:\`flex min-w-0 flex-1 flex-col\`,children:y?(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(\`span\`,{className:\`font-mono text-sm\`,children:y.name}),(0,j.jsxs)(\`span\`,{className:\`rounded bg-neutral-800 px-1.5 py-0.5 text-[11px] text-neutral-400\`,children:[o,\` rows\`]}),(0,j.jsxs)(\`div\`,{className:\`ml-auto flex items-center gap-1.5\`,children:[(0,j.jsx)(N,{variant:\`ghost\`,size:\`xs\`,onClick:()=>void x(),children:(0,j.jsx)(fe,{size:13})}),(0,j.jsxs)(N,{size:\`xs\`,onClick:()=>h(!0),children:[(0,j.jsx)(de,{size:13}),\` Insert\`]})]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`sticky top-0 z-10 bg-[#1c1c1c]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800\`,children:[(0,j.jsx)(\`th\`,{className:\`w-16 px-2 py-1.5\`}),y.columns.map(e=>(0,j.jsxs)(\`th\`,{className:\`whitespace-nowrap px-3 py-1.5 text-left font-medium text-neutral-400\`,children:[(0,j.jsx)(\`span\`,{className:\`font-mono text-neutral-200\`,children:e.name}),e.isPrimaryKey&&(0,j.jsx)(\`span\`,{className:\`ml-1 text-[10px] text-brand\`,children:\`PK\`}),(0,j.jsx)(\`span\`,{className:\`ml-1.5 text-[11px] font-normal text-neutral-600\`,children:e.type})]},e.name))]})}),(0,j.jsx)(\`tbody\`,{children:i.map((e,t)=>(0,j.jsxs)(\`tr\`,{className:\`group border-b border-neutral-850 border-neutral-800/60 hover:bg-neutral-800/30\`,children:[(0,j.jsx)(\`td\`,{className:\`px-2\`,children:(0,j.jsxs)(\`div\`,{className:\`flex gap-0.5 opacity-0 group-hover:opacity-100\`,children:[(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-brand\`,onClick:()=>p(e),children:(0,j.jsx)(T,{size:13})}),(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-red-400\`,onClick:()=>S(e),children:(0,j.jsx)(ge,{size:13})})]})}),y.columns.map(t=>(0,j.jsx)(\`td\`,{className:\`max-w-[320px] truncate px-3 py-1.5 font-mono text-neutral-300\`,children:(0,j.jsx)(Yr,{value:e[t.name]})},t.name))]},t))})]}),i.length===0&&(0,j.jsx)(Kr,{children:\`No rows yet.\`})]}),(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-t border-neutral-800 px-4 py-2 text-xs text-neutral-500\`,children:[(0,j.jsx)(N,{variant:\`ghost\`,size:\`xs\`,disabled:c===0,onClick:()=>l(e=>e-1),children:(0,j.jsx)(ie,{size:13})}),(0,j.jsxs)(\`span\`,{children:[o===0?0:c*qr+1,\`–\`,Math.min((c+1)*qr,o),\` of \`,o]}),(0,j.jsx)(N,{variant:\`ghost\`,size:\`xs\`,disabled:(c+1)*qr>=o,onClick:()=>l(e=>e+1),children:(0,j.jsx)(ae,{size:13})})]})]}):(0,j.jsx)(Kr,{children:\`Select a table.\`})}),f&&y&&(0,j.jsx)(Xr,{table:y,initial:f,onClose:()=>p(null),onSave:async e=>{await A.updateRow(n,ee(f),e),p(null),await x()}}),m&&y&&(0,j.jsx)(Xr,{table:y,initial:{},isNew:!0,onClose:()=>h(!1),onSave:async e=>{await A.insertRow(n,e),h(!1),await x(),await b()}}),g&&(0,j.jsx)(\`p\`,{className:\`text-red-400\`,children:g})]})}function Yr({value:e}){return e==null?(0,j.jsx)(\`span\`,{className:\`text-neutral-600\`,children:\`NULL\`}):typeof e==\`boolean\`?(0,j.jsx)(\`span\`,{className:\`text-blue-400\`,children:String(e)}):typeof e==\`object\`?(0,j.jsx)(\`span\`,{className:\`text-amber-300/80\`,children:JSON.stringify(e)}):(0,j.jsx)(j.Fragment,{children:String(e)})}function Xr({table:e,initial:t,isNew:n,onClose:r,onSave:i}){let a=e.columns.filter(e=>!(n&&e.isPrimaryKey&&e.hasDefault)),[o,s]=(0,_.useState)(()=>{let e={};for(let n of a){let r=t[n.name];e[n.name]=r==null?\`\`:typeof r==\`object\`?JSON.stringify(r):String(r)}return e}),[c,l]=(0,_.useState)({}),[u,d]=(0,_.useState)(\`\`),[f,p]=(0,_.useState)(!1);async function m(){p(!0),d(\`\`);let e={};for(let t of a){if(!n&&!c[t.name])continue;let r=o[t.name];if(r===\`\`&&(t.nullable||t.hasDefault)){n||(e[t.name]=null);continue}e[t.name]=Zr(r,t.type)}try{await i(e)}catch(e){d(e.message),p(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:r,title:n?\`Insert into \${e.name}\`:\`Edit row in \${e.name}\`,wide:!0,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[a.map(e=>(0,j.jsxs)(\`div\`,{children:[(0,j.jsxs)(Ur,{children:[e.name,(0,j.jsxs)(\`span\`,{className:\`ml-1.5 font-normal text-neutral-600\`,children:[e.type,e.isPrimaryKey?\` · PK\`:\`\`,!e.nullable&&!e.hasDefault?\` · required\`:\`\`]})]}),(0,j.jsx)(Vr,{value:o[e.name]??\`\`,placeholder:e.hasDefault?\`default\`:e.nullable?\`NULL\`:\`\`,onChange:t=>{s(n=>({...n,[e.name]:t.target.value})),l(t=>({...t,[e.name]:!0}))}})]},e.name)),u&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:u}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2 pt-1\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:r,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:m,disabled:f,children:f?\`Saving…\`:n?\`Insert\`:\`Save\`})]})]})})}function Zr(e,t){if(t===\`bool\`)return e===\`true\`||e===\`t\`||e===\`1\`;if([\`int2\`,\`int4\`,\`int8\`,\`float4\`,\`float8\`,\`numeric\`].includes(t)){let t=Number(e);return Number.isNaN(t)?e:t}if(t===\`json\`||t===\`jsonb\`)try{return JSON.parse(e)}catch{return e}if(t.startsWith(\`_\`))try{return JSON.parse(e)}catch{return e}return e}function Qr(){let[e,t]=(0,_.useState)(\`select * from \`),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)(!1);async function o(){a(!0),r(await A.sql(e)),a(!1)}let s=n?.rows?.[0]?Object.keys(n.rows[0]):[];return(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`border-b border-neutral-800 p-3\`,children:[(0,j.jsx)(Hr,{className:\`h-40\`,value:e,onChange:e=>t(e.target.value),onKeyDown:e=>(e.metaKey||e.ctrlKey)&&e.key===\`Enter\`&&o(),spellCheck:!1,placeholder:\`select * from … (⌘⏎ to run)\`}),(0,j.jsxs)(\`div\`,{className:\`mt-2 flex items-center gap-3\`,children:[(0,j.jsxs)(N,{onClick:o,disabled:i,children:[(0,j.jsx)(E,{size:13}),\` Run\`]}),(0,j.jsx)(\`span\`,{className:\`text-xs text-neutral-500\`,children:\`⌘⏎\`}),n&&(0,j.jsx)(\`span\`,{className:\`ml-auto text-xs text-neutral-500\`,children:n.ok?\`\${n.rowCount} rows · \${n.ms} ms\${n.affectedRows==null?\`\`:\` · \${n.affectedRows} affected\`}\`:\`\`})]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto\`,children:[!n&&(0,j.jsx)(Kr,{children:\`Run a query to see results.\`}),n&&!n.ok&&(0,j.jsxs)(\`div\`,{className:\`m-4 rounded-md border border-red-900/50 bg-red-950/30 p-3 text-[13px] text-red-300\`,children:[(0,j.jsx)(\`div\`,{className:\`font-mono\`,children:n.error}),n.code&&(0,j.jsxs)(\`div\`,{className:\`mt-1 text-xs text-red-400/70\`,children:[\`SQLSTATE \`,n.code]}),n.hint&&(0,j.jsxs)(\`div\`,{className:\`mt-1 text-xs text-neutral-400\`,children:[\`Hint: \`,n.hint]})]}),n?.ok&&s.length>0&&(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`sticky top-0 bg-[#1c1c1c]\`,children:(0,j.jsx)(\`tr\`,{className:\`border-b border-neutral-800\`,children:s.map(e=>(0,j.jsx)(\`th\`,{className:\`whitespace-nowrap px-3 py-1.5 text-left font-mono font-medium text-neutral-300\`,children:e},e))})}),(0,j.jsx)(\`tbody\`,{children:n.rows.map((e,t)=>(0,j.jsx)(\`tr\`,{className:\`border-b border-neutral-800/60 hover:bg-neutral-800/30\`,children:s.map(t=>(0,j.jsx)(\`td\`,{className:\`max-w-[360px] truncate px-3 py-1.5 font-mono text-neutral-300\`,children:$r(e[t])},t))},t))})]}),n?.ok&&s.length===0&&(0,j.jsxs)(Kr,{children:[\`Statement executed\`,n.affectedRows==null?\`\`:\` · \${n.affectedRows} rows affected\`,\`.\`]})]})]})}function $r(e){return e==null?(0,j.jsx)(\`span\`,{className:\`text-neutral-600\`,children:\`NULL\`}):typeof e==\`object\`?JSON.stringify(e):String(e)}function ei(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(!0),[i,a]=(0,_.useState)(!1),[o,s]=(0,_.useState)(null);async function c(){t(await A.users())}(0,_.useEffect)(()=>{c().finally(()=>r(!1))},[]);async function l(e){confirm(\`Delete \${e.email||e.id}?\`)&&(await A.deleteUser(e.id),await c())}return n?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(\`span\`,{className:\`text-sm font-semibold\`,children:\`Users\`}),(0,j.jsx)(\`span\`,{className:\`rounded bg-neutral-800 px-1.5 py-0.5 text-[11px] text-neutral-400\`,children:e.length}),(0,j.jsxs)(N,{size:\`xs\`,className:\`ml-auto\`,onClick:()=>a(!0),children:[(0,j.jsx)(de,{size:13}),\` Add user\`]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`sticky top-0 bg-[#1c1c1c]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-1.5 font-medium\`,children:\`Email\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`UID\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`Provider\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`Created\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`Last sign in\`}),(0,j.jsx)(\`th\`,{className:\`w-20\`})]})}),(0,j.jsx)(\`tbody\`,{children:e.map(e=>(0,j.jsxs)(\`tr\`,{className:\`group border-b border-neutral-800/60 hover:bg-neutral-800/30\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5\`,children:e.email||(0,j.jsx)(\`span\`,{className:\`text-neutral-500\`,children:e.is_anonymous?\`anonymous\`:\`—\`})}),(0,j.jsxs)(\`td\`,{className:\`px-3 py-1.5 font-mono text-[11px] text-neutral-500\`,children:[e.id.slice(0,8),\`…\`]}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:e.app_metadata?.provider||\`—\`}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:(e.created_at||\`\`).slice(0,10)}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:(e.last_sign_in_at||\`\`).slice(0,16).replace(\`T\`,\` \`)}),(0,j.jsx)(\`td\`,{className:\`px-3\`,children:(0,j.jsxs)(\`div\`,{className:\`flex gap-0.5 opacity-0 group-hover:opacity-100\`,children:[(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-brand\`,title:\`Reset password\`,onClick:()=>s(e),children:(0,j.jsx)(ue,{size:13})}),(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-red-400\`,onClick:()=>l(e),children:(0,j.jsx)(ge,{size:13})})]})})]},e.id))})]}),e.length===0&&(0,j.jsx)(Kr,{children:\`No users yet.\`})]}),i&&(0,j.jsx)(ti,{onClose:()=>a(!1),onDone:async()=>{a(!1),await c()}}),o&&(0,j.jsx)(ni,{user:o,onClose:()=>s(null),onDone:async()=>{s(null),await c()}})]})}function ti({onClose:e,onDone:t}){let[n,r]=(0,_.useState)(\`\`),[i,a]=(0,_.useState)(\`\`),[o,s]=(0,_.useState)(\`\`),[c,l]=(0,_.useState)(!1);async function u(){l(!0),s(\`\`);try{await A.createUser({email:n,password:i||void 0,email_confirm:!0}),t()}catch(e){s(e.message),l(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:e,title:\`Add user\`,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Email\`}),(0,j.jsx)(Vr,{value:n,onChange:e=>r(e.target.value),placeholder:\`user@example.com\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Password (optional)\`}),(0,j.jsx)(Vr,{type:\`password\`,value:i,onChange:e=>a(e.target.value)})]}),o&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:o}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:e,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:u,disabled:c||!n,children:c?\`Creating…\`:\`Create\`})]})]})})}function ni({user:e,onClose:t,onDone:n}){let[r,i]=(0,_.useState)(\`\`),[a,o]=(0,_.useState)(\`\`),[s,c]=(0,_.useState)(!1);async function l(){c(!0),o(\`\`);try{await A.updateUser(e.id,{password:r}),n()}catch(e){o(e.message),c(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:t,title:\`Reset password · \${e.email||e.id}\`,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`New password\`}),(0,j.jsx)(Vr,{type:\`password\`,value:r,onChange:e=>i(e.target.value)})]}),a&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:a}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:t,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:l,disabled:s||r.length<6,children:s?\`Saving…\`:\`Update\`})]})]})})}function ri(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)(!0),[c,l]=(0,_.useState)(!1),u=(0,_.useRef)(null);async function d(){let e=await A.buckets();t(e),r(t=>t??e[0]?.id??null)}async function f(e){a(await A.listObjects(e))}(0,_.useEffect)(()=>{d().finally(()=>s(!1))},[]),(0,_.useEffect)(()=>{n&&f(n)},[n]);async function p(e){n&&(await A.uploadObject(n,e.name,e),await f(n))}async function m(e){!n||!confirm(\`Delete \${e}?\`)||(await A.removeObject(n,e),await f(n))}async function h(e){if(confirm(\`Delete bucket "\${e}"? It must be empty.\`))try{await A.deleteBucket(e),r(null),await d()}catch(e){alert(e.message)}}return o?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex w-60 shrink-0 flex-col border-r border-neutral-800 bg-[#191919]\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between px-3 py-2.5 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:[\`Buckets\`,(0,j.jsx)(\`button\`,{className:\`text-neutral-400 hover:text-brand\`,onClick:()=>l(!0),children:(0,j.jsx)(de,{size:14})})]}),(0,j.jsxs)(\`div\`,{className:\`flex-1 overflow-auto\`,children:[e.map(e=>(0,j.jsxs)(\`button\`,{onClick:()=>r(e.id),className:\`group flex w-full items-center justify-between px-3 py-1.5 text-left text-[13px] \`+(n===e.id?\`bg-neutral-800 text-neutral-100\`:\`text-neutral-400 hover:bg-neutral-800/50\`),children:[(0,j.jsxs)(\`span\`,{className:\`truncate\`,children:[e.id,e.public&&(0,j.jsx)(\`span\`,{className:\`ml-1.5 text-[10px] text-brand\`,children:\`public\`})]}),(0,j.jsx)(ge,{size:13,className:\`opacity-0 hover:text-red-400 group-hover:opacity-100\`,onClick:t=>{t.stopPropagation(),h(e.id)}})]},e.id)),e.length===0&&(0,j.jsx)(Kr,{children:\`No buckets.\`})]})]}),(0,j.jsx)(\`div\`,{className:\`flex min-w-0 flex-1 flex-col\`,children:n?(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(\`span\`,{className:\`font-mono text-sm\`,children:n}),(0,j.jsx)(\`input\`,{ref:u,type:\`file\`,className:\`hidden\`,onChange:e=>e.target.files?.[0]&&p(e.target.files[0])}),(0,j.jsxs)(N,{size:\`xs\`,className:\`ml-auto\`,onClick:()=>u.current?.click(),children:[(0,j.jsx)(_e,{size:13}),\` Upload\`]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto p-2\`,children:[i.map(e=>(0,j.jsxs)(\`div\`,{className:\`group flex items-center gap-2 rounded-md px-2 py-1.5 text-[13px] hover:bg-neutral-800/40\`,children:[(0,j.jsx)(se,{size:14,className:\`text-neutral-500\`}),(0,j.jsx)(\`span\`,{className:\`font-mono\`,children:e.name}),e.metadata?.size!=null&&(0,j.jsx)(\`span\`,{className:\`text-[11px] text-neutral-500\`,children:ai(e.metadata.size)}),(0,j.jsx)(\`button\`,{className:\`ml-auto p-1 text-neutral-500 opacity-0 hover:text-red-400 group-hover:opacity-100\`,onClick:()=>m(e.name),children:(0,j.jsx)(ge,{size:13})})]},e.name)),i.length===0&&(0,j.jsx)(Kr,{children:\`Empty bucket. Upload a file.\`})]})]}):(0,j.jsx)(Kr,{children:\`Select or create a bucket.\`})}),c&&(0,j.jsx)(ii,{onClose:()=>l(!1),onDone:async()=>{l(!1),await d()}})]})}function ii({onClose:e,onDone:t}){let[n,r]=(0,_.useState)(\`\`),[i,a]=(0,_.useState)(!1),[o,s]=(0,_.useState)(\`\`),[c,l]=(0,_.useState)(!1);async function u(){l(!0),s(\`\`);try{await A.createBucket({id:n,name:n,public:i}),t()}catch(e){s(e.message),l(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:e,title:\`New bucket\`,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Name\`}),(0,j.jsx)(Vr,{value:n,onChange:e=>r(e.target.value),placeholder:\`avatars\`})]}),(0,j.jsxs)(\`label\`,{className:\`flex items-center gap-2 text-[13px] text-neutral-300\`,children:[(0,j.jsx)(\`input\`,{type:\`checkbox\`,checked:i,onChange:e=>a(e.target.checked)}),\`Public bucket (objects readable without auth)\`]}),o&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:o}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:e,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:u,disabled:c||!n,children:c?\`Creating…\`:\`Create\`})]})]})})}function ai(e){return e<1024?\`\${e} B\`:e<1024*1024?\`\${(e/1024).toFixed(1)} KB\`:\`\${(e/1024/1024).toFixed(1)} MB\`}function oi(){let[e,t]=(0,_.useState)(null),[n,r]=(0,_.useState)([]),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)([]),[c,l]=(0,_.useState)(!0);return(0,_.useEffect)(()=>{Promise.all([A.stats(),A.migrations(),A.functions(),A.triggers()]).then(([e,n,i,o])=>{t(e),r(n),a(i),s(o)}).finally(()=>l(!1))},[]),c?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`h-full overflow-auto p-6\`,children:[(0,j.jsx)(\`h1\`,{className:\`text-sm font-semibold text-neutral-300\`,children:\`Database\`}),e&&(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(\`p\`,{className:\`mt-1 font-mono text-xs text-neutral-500\`,children:e.version}),(0,j.jsxs)(\`div\`,{className:\`mt-4 grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6\`,children:[(0,j.jsx)(si,{label:\`Tables\`,value:e.tables}),(0,j.jsx)(si,{label:\`Users\`,value:e.users}),(0,j.jsx)(si,{label:\`Buckets\`,value:e.buckets}),(0,j.jsx)(si,{label:\`Objects\`,value:e.objects}),(0,j.jsx)(si,{label:\`Migrations\`,value:e.migrations}),(0,j.jsx)(si,{label:\`DB size\`,value:e.dbSize})]})]}),(0,j.jsx)(\`h2\`,{className:\`mb-2 mt-8 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:\`Migrations\`}),(0,j.jsxs)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Version\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Name\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Applied\`})]})}),(0,j.jsx)(\`tbody\`,{children:n.map(e=>(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-400\`,children:e.version}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono\`,children:e.name||\`—\`}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:(e.applied_at||\`\`).slice(0,19).replace(\`T\`,\` \`)})]},e.version))})]}),n.length===0&&(0,j.jsx)(Kr,{children:\`No migrations applied.\`})]}),(0,j.jsx)(\`h2\`,{className:\`mb-2 mt-8 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:\`Functions\`}),(0,j.jsxs)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Name\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Arguments\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Returns\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Language\`})]})}),(0,j.jsx)(\`tbody\`,{children:i.map(e=>(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-200\`,children:e.name}),(0,j.jsx)(\`td\`,{className:\`max-w-[280px] truncate px-4 py-1.5 font-mono text-[11px] text-neutral-500\`,children:e.args||\`—\`}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-400\`,children:e.returns}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:e.language})]},e.name))})]}),i.length===0&&(0,j.jsx)(Kr,{children:\`No user functions.\`})]}),(0,j.jsx)(\`h2\`,{className:\`mb-2 mt-8 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:\`Triggers\`}),(0,j.jsxs)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Name\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Table\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Timing\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Events\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Function\`})]})}),(0,j.jsx)(\`tbody\`,{children:o.map(e=>(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-200\`,children:e.name}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-400\`,children:e.table}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:e.timing}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:(e.events||[]).join(\`, \`)}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-[11px] text-neutral-500\`,children:e.function})]},e.table+e.name))})]}),o.length===0&&(0,j.jsx)(Kr,{children:\`No triggers.\`})]})]})}function si({label:e,value:t}){return(0,j.jsxs)(\`div\`,{className:\`rounded-lg border border-neutral-800 bg-[#191919] p-3\`,children:[(0,j.jsx)(\`div\`,{className:\`text-lg font-semibold text-neutral-100\`,children:t}),(0,j.jsx)(\`div\`,{className:\`text-xs text-neutral-500\`,children:e})]})}function ci(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(!0),[i,a]=(0,_.useState)(!1);async function o(){t(await A.policies())}(0,_.useEffect)(()=>{o().finally(()=>r(!1))},[]);async function s(e){confirm(\`Drop policy "\${e.name}" on \${e.table}?\`)&&(await A.dropPolicy(e.table,e.name),await o())}if(n)return(0,j.jsx)(Gr,{});let c=new Map;for(let t of e)c.has(t.table)||c.set(t.table,[]),c.get(t.table).push(t);return(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(me,{size:15,className:\`text-brand\`}),(0,j.jsx)(\`span\`,{className:\`text-sm font-semibold\`,children:\`RLS Policies\`}),(0,j.jsx)(\`span\`,{className:\`rounded bg-neutral-800 px-1.5 py-0.5 text-[11px] text-neutral-400\`,children:e.length}),(0,j.jsxs)(N,{size:\`xs\`,className:\`ml-auto\`,onClick:()=>a(!0),children:[(0,j.jsx)(de,{size:13}),\` New policy\`]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto p-4\`,children:[[...c].map(([e,t])=>(0,j.jsxs)(\`div\`,{className:\`mb-5\`,children:[(0,j.jsx)(\`div\`,{className:\`mb-1.5 font-mono text-[13px] text-neutral-300\`,children:e}),(0,j.jsx)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:(0,j.jsxs)(\`table\`,{className:\`w-full text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919] text-neutral-400\`,children:(0,j.jsxs)(\`tr\`,{children:[(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`Policy\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`Command\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`Roles\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`USING / CHECK\`}),(0,j.jsx)(\`th\`,{className:\`w-10\`})]})}),(0,j.jsx)(\`tbody\`,{children:t.map(e=>(0,j.jsxs)(\`tr\`,{className:\`group border-t border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5\`,children:e.name}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:e.cmd}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 font-mono text-[11px] text-neutral-500\`,children:Array.isArray(e.roles)?e.roles.join(\`, \`):e.roles}),(0,j.jsx)(\`td\`,{className:\`max-w-[360px] truncate px-3 py-1.5 font-mono text-[11px] text-amber-300/70\`,children:[e.using_expr&&\`USING \${e.using_expr}\`,e.with_check&&\`CHECK \${e.with_check}\`].filter(Boolean).join(\` · \`)}),(0,j.jsx)(\`td\`,{className:\`px-2\`,children:(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 opacity-0 hover:text-red-400 group-hover:opacity-100\`,onClick:()=>s(e),children:(0,j.jsx)(ge,{size:13})})})]},e.name))})]})})]},e)),e.length===0&&(0,j.jsx)(Kr,{children:\`No policies. Create one, or enable RLS on a table first.\`})]}),i&&(0,j.jsx)(li,{onClose:()=>a(!1),onDone:async()=>{a(!1),await o()}})]})}function li({onClose:e,onDone:t}){let[n,r]=(0,_.useState)({table:\`\`,name:\`\`,command:\`ALL\`,roles:\`authenticated\`,using:\`\`,check:\`\`}),[i,a]=(0,_.useState)(\`\`),[o,s]=(0,_.useState)(!1),c=(e,t)=>r(n=>({...n,[e]:t}));async function l(){s(!0),a(\`\`);try{let e=await A.createPolicy(n);if(e.error)throw Error(e.error+(e.hint?\` (\${e.hint})\`:\`\`));t()}catch(e){a(e.message),s(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:e,title:\`New RLS policy\`,wide:!0,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{className:\`grid grid-cols-2 gap-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Table\`}),(0,j.jsx)(Vr,{value:n.table,onChange:e=>c(\`table\`,e.target.value),placeholder:\`todos\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Policy name\`}),(0,j.jsx)(Vr,{value:n.name,onChange:e=>c(\`name\`,e.target.value),placeholder:\`own rows\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Command\`}),(0,j.jsx)(\`select\`,{className:\`h-8 w-full rounded-md border border-neutral-700 bg-neutral-900 px-2 text-[13px]\`,value:n.command,onChange:e=>c(\`command\`,e.target.value),children:[\`ALL\`,\`SELECT\`,\`INSERT\`,\`UPDATE\`,\`DELETE\`].map(e=>(0,j.jsx)(\`option\`,{children:e},e))})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Roles\`}),(0,j.jsx)(Vr,{value:n.roles,onChange:e=>c(\`roles\`,e.target.value),placeholder:\`authenticated\`})]})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`USING expression (read/visibility)\`}),(0,j.jsx)(Vr,{value:n.using,onChange:e=>c(\`using\`,e.target.value),placeholder:\`user_id = auth.uid()\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`WITH CHECK expression (writes)\`}),(0,j.jsx)(Vr,{value:n.check,onChange:e=>c(\`check\`,e.target.value),placeholder:\`user_id = auth.uid()\`})]}),i&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:i}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:e,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:l,disabled:o||!n.table||!n.name,children:o?\`Creating…\`:\`Create policy\`})]})]})})}var ui={info:\`text-neutral-500\`,warn:\`text-amber-400\`,error:\`text-red-400\`};function di(){let[e,t]=(0,_.useState)(null),[n,r]=(0,_.useState)(!0),i=(0,_.useRef)(null);async function a(){try{t(await A.logs())}catch{}}return(0,_.useEffect)(()=>{if(a(),n)return i.current=setInterval(a,2e3),()=>{i.current&&clearInterval(i.current)}},[n]),e===null?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between border-b border-neutral-800 px-6 py-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(\`h1\`,{className:\`text-sm font-semibold text-neutral-300\`,children:\`Logs\`}),(0,j.jsx)(\`p\`,{className:\`text-xs text-neutral-500\`,children:\`Recent requests and server events\`})]}),(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2\`,children:[(0,j.jsx)(N,{className:n?\`\`:\`opacity-60\`,onClick:()=>r(e=>!e),title:n?\`Pause auto-refresh\`:\`Resume auto-refresh\`,children:n?\`⏸ Live\`:\`▶ Paused\`}),(0,j.jsx)(N,{onClick:a,children:\`Refresh\`}),(0,j.jsx)(N,{onClick:async()=>{await A.clearLogs(),a()},children:\`Clear\`})]})]}),(0,j.jsx)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto p-3 font-mono text-[12.5px] leading-relaxed\`,children:e.length===0?(0,j.jsx)(Kr,{children:\`No logs yet. Make a request or trigger an email/webhook.\`}):e.map((e,t)=>(0,j.jsxs)(\`div\`,{className:\`flex gap-3 whitespace-pre-wrap break-words px-3 py-0.5 hover:bg-neutral-800/40\`,children:[(0,j.jsx)(\`span\`,{className:\`shrink-0 tabular-nums text-neutral-600\`,children:e.ts.slice(11,23)}),(0,j.jsx)(\`span\`,{className:\`shrink-0 uppercase \`+ui[e.level],children:e.level}),(0,j.jsx)(\`span\`,{className:\`text-neutral-300\`,children:e.msg})]},t))})]})}var fi=[{id:\`table\`,label:\`Table Editor\`,icon:he},{id:\`sql\`,label:\`SQL Editor\`,icon:D},{id:\`auth\`,label:\`Authentication\`,icon:ue},{id:\`policies\`,label:\`RLS Policies\`,icon:me},{id:\`storage\`,label:\`Storage\`,icon:le},{id:\`database\`,label:\`Database\`,icon:ce},{id:\`logs\`,label:\`Logs\`,icon:pe}];function pi({size:e=24}){return(0,j.jsxs)(\`svg\`,{width:e,height:e,viewBox:\`0 0 120 120\`,children:[(0,j.jsx)(\`path\`,{d:\`M24 34v56c0 8.8 16.1 16 36 16s36-7.2 36-16V34\`,fill:\`#2a9d6f\`}),(0,j.jsx)(\`ellipse\`,{cx:\`60\`,cy:\`34\`,rx:\`36\`,ry:\`16\`,fill:\`#3ecf8e\`})]})}function mi(){let[e,t]=(0,_.useState)(!!be()),[n,r]=(0,_.useState)(\`table\`);return(0,_.useEffect)(()=>{be()&&A.ping().catch(()=>{Se(),t(!1)})},[]),e?(0,j.jsxs)(\`div\`,{className:\`flex h-full\`,children:[(0,j.jsxs)(\`nav\`,{className:\`flex w-14 shrink-0 flex-col items-center gap-1 border-r border-neutral-800 bg-[#171717] py-3\`,children:[(0,j.jsx)(\`div\`,{className:\`mb-3\`,children:(0,j.jsx)(pi,{})}),fi.map(e=>{let t=e.icon,i=n===e.id;return(0,j.jsxs)(\`button\`,{title:e.label,onClick:()=>r(e.id),className:\`group relative flex size-9 items-center justify-center rounded-md transition-colors \`+(i?\`bg-neutral-800 text-brand\`:\`text-neutral-500 hover:bg-neutral-800 hover:text-neutral-200\`),children:[(0,j.jsx)(t,{size:18}),(0,j.jsx)(\`span\`,{className:\`pointer-events-none absolute left-11 z-20 hidden whitespace-nowrap rounded-md border border-neutral-700 bg-neutral-900 px-2 py-1 text-xs text-neutral-200 group-hover:block\`,children:e.label})]},e.id)}),(0,j.jsx)(\`button\`,{title:\`Log out\`,onClick:()=>{Se(),t(!1)},className:\`mt-auto flex size-9 items-center justify-center rounded-md text-neutral-600 hover:bg-neutral-800 hover:text-neutral-300\`,children:(0,j.jsx)(oe,{size:18})})]}),(0,j.jsxs)(\`main\`,{className:\`min-w-0 flex-1\`,children:[n===\`table\`&&(0,j.jsx)(Jr,{}),n===\`sql\`&&(0,j.jsx)(Qr,{}),n===\`auth\`&&(0,j.jsx)(ei,{}),n===\`policies\`&&(0,j.jsx)(ci,{}),n===\`storage\`&&(0,j.jsx)(ri,{}),n===\`database\`&&(0,j.jsx)(oi,{}),n===\`logs\`&&(0,j.jsx)(di,{})]})]}):(0,j.jsx)(hi,{onOk:()=>t(!0)})}function hi({onOk:e}){let[t,n]=(0,_.useState)(\`\`),[r,i]=(0,_.useState)(\`\`),[a,o]=(0,_.useState)(!1);async function s(){o(!0),i(\`\`),xe(t.trim());try{await A.ping(),e()}catch(e){Se(),i(\`Invalid service_role key: \`+e.message)}finally{o(!1)}}return(0,j.jsx)(\`div\`,{className:\`flex h-full items-center justify-center\`,children:(0,j.jsxs)(\`div\`,{className:\`w-[400px] text-center\`,children:[(0,j.jsx)(\`div\`,{className:\`mb-4 flex justify-center\`,children:(0,j.jsx)(pi,{size:48})}),(0,j.jsx)(\`h1\`,{className:\`text-lg font-semibold\`,children:\`tinbase studio\`}),(0,j.jsxs)(\`p\`,{className:\`mt-1 text-[13px] text-neutral-500\`,children:[\`Sign in with the \`,(0,j.jsx)(\`span\`,{className:\`text-neutral-300\`,children:\`service_role\`}),\` key printed when tinbase started.\`]}),(0,j.jsxs)(\`div\`,{className:\`mt-5 space-y-3 text-left\`,children:[(0,j.jsx)(Vr,{type:\`password\`,placeholder:\`service_role key (eyJ…)\`,value:t,onChange:e=>n(e.target.value),onKeyDown:e=>e.key===\`Enter\`&&s()}),(0,j.jsx)(N,{className:\`w-full\`,onClick:s,disabled:a||!t.trim(),children:a?\`Checking…\`:\`Continue\`}),r&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:r})]})]})})}(0,v.createRoot)(document.getElementById(\`root\`)).render((0,j.jsx)(_.StrictMode,{children:(0,j.jsx)(mi,{})}));</script>
64
+ \`},Xn=0,Zn=[];function Qn(e){var t=_.useRef([]),n=_.useRef([0,0]),r=_.useRef(),i=_.useState(Xn++)[0],a=_.useState(bn)[0],o=_.useRef(e);_.useEffect(function(){o.current=e},[e]),_.useEffect(function(){if(e.inert){document.body.classList.add(\`block-interactivity-\${i}\`);var t=Jt([e.lockRef.current],(e.shards||[]).map(qn),!0).filter(Boolean);return t.forEach(function(e){return e.classList.add(\`allow-interactivity-\${i}\`)}),function(){document.body.classList.remove(\`block-interactivity-\${i}\`),t.forEach(function(e){return e.classList.remove(\`allow-interactivity-\${i}\`)})}}},[e.inert,e.lockRef.current,e.shards]);var s=_.useCallback(function(e,t){if(\`touches\`in e&&e.touches.length===2||e.type===\`wheel\`&&e.ctrlKey)return!o.current.allowPinchZoom;var i=Gn(e),a=n.current,s=\`deltaX\`in e?e.deltaX:a[0]-i[0],c=\`deltaY\`in e?e.deltaY:a[1]-i[1],l,u=e.target,d=Math.abs(s)>Math.abs(c)?\`h\`:\`v\`;if(\`touches\`in e&&d===\`h\`&&u.type===\`range\`)return!1;var f=window.getSelection(),p=f&&f.anchorNode;if(p&&(p===u||p.contains(u)))return!1;var m=Rn(d,u);if(!m)return!0;if(m?l=d:(l=d===\`v\`?\`h\`:\`v\`,m=Rn(d,u)),!m)return!1;if(!r.current&&\`changedTouches\`in e&&(s||c)&&(r.current=l),!l)return!0;var h=r.current||l;return Wn(h,t,e,h===\`h\`?s:c,!0)},[]),c=_.useCallback(function(e){var n=e;if(!(!Zn.length||Zn[Zn.length-1]!==a)){var r=\`deltaY\`in n?Kn(n):Gn(n),i=t.current.filter(function(e){return e.name===n.type&&(e.target===n.target||n.target===e.shadowParent)&&Jn(e.delta,r)})[0];if(i&&i.should){n.cancelable&&n.preventDefault();return}if(!i){var c=(o.current.shards||[]).map(qn).filter(Boolean).filter(function(e){return e.contains(n.target)});(c.length>0?s(n,c[0]):!o.current.noIsolation)&&n.cancelable&&n.preventDefault()}}},[]),l=_.useCallback(function(e,n,r,i){var a={name:e,delta:n,target:r,should:i,shadowParent:$n(r)};t.current.push(a),setTimeout(function(){t.current=t.current.filter(function(e){return e!==a})},1)},[]),u=_.useCallback(function(e){n.current=Gn(e),r.current=void 0},[]),d=_.useCallback(function(t){l(t.type,Kn(t),t.target,s(t,e.lockRef.current))},[]),f=_.useCallback(function(t){l(t.type,Gn(t),t.target,s(t,e.lockRef.current))},[]);_.useEffect(function(){return Zn.push(a),e.setCallbacks({onScrollCapture:d,onWheelCapture:d,onTouchMoveCapture:f}),document.addEventListener(\`wheel\`,c,Nn),document.addEventListener(\`touchmove\`,c,Nn),document.addEventListener(\`touchstart\`,u,Nn),function(){Zn=Zn.filter(function(e){return e!==a}),document.removeEventListener(\`wheel\`,c,Nn),document.removeEventListener(\`touchmove\`,c,Nn),document.removeEventListener(\`touchstart\`,u,Nn)}},[]);var p=e.removeScrollBar,m=e.inert;return _.createElement(_.Fragment,null,m?_.createElement(a,{styles:Yn(i)}):null,p?_.createElement(An,{noRelative:e.noRelative,gapMode:e.gapMode}):null)}function $n(e){for(var t=null;e!==null;)e instanceof ShadowRoot&&(t=e.host,e=e.host),e=e.parentNode;return t}var er=ln(un,Qn),tr=_.forwardRef(function(e,t){return _.createElement(fn,Kt({},e,{ref:t,sideCar:er}))});tr.classNames=fn.classNames;var nr=function(e){return typeof document>\`u\`?null:(Array.isArray(e)?e[0]:e).ownerDocument.body},rr=new WeakMap,ir=new WeakMap,ar={},or=0,sr=function(e){return e&&(e.host||sr(e.parentNode))},cr=function(e,t){return t.map(function(t){if(e.contains(t))return t;var n=sr(t);return n&&e.contains(n)?n:(console.error(\`aria-hidden\`,t,\`in not contained inside\`,e,\`. Doing nothing\`),null)}).filter(function(e){return!!e})},lr=function(e,t,n,r){var i=cr(t,Array.isArray(e)?e:[e]);ar[n]||(ar[n]=new WeakMap);var a=ar[n],o=[],s=new Set,c=new Set(i),l=function(e){!e||s.has(e)||(s.add(e),l(e.parentNode))};i.forEach(l);var u=function(e){!e||c.has(e)||Array.prototype.forEach.call(e.children,function(e){if(s.has(e))u(e);else try{var t=e.getAttribute(r),i=t!==null&&t!==\`false\`,c=(rr.get(e)||0)+1,l=(a.get(e)||0)+1;rr.set(e,c),a.set(e,l),o.push(e),c===1&&i&&ir.set(e,!0),l===1&&e.setAttribute(n,\`true\`),i||e.setAttribute(r,\`true\`)}catch(t){console.error(\`aria-hidden: cannot operate on \`,e,t)}})};return u(t),s.clear(),or++,function(){o.forEach(function(e){var t=rr.get(e)-1,i=a.get(e)-1;rr.set(e,t),a.set(e,i),t||(ir.has(e)||e.removeAttribute(r),ir.delete(e)),i||e.removeAttribute(n)}),or--,or||(rr=new WeakMap,rr=new WeakMap,ir=new WeakMap,ar={})}},ur=function(e,t,n){n===void 0&&(n=\`data-aria-hidden\`);var r=Array.from(Array.isArray(e)?e:[e]),i=t||nr(e);return i?(r.push.apply(r,Array.from(i.querySelectorAll(\`[aria-live], script\`))),lr(r,i,n,\`aria-hidden\`)):function(){return null}},dr=\`Dialog\`,[fr,pr]=ke(dr),[mr,hr]=fr(dr),gr=e=>{let{__scopeDialog:t,children:n,open:r,defaultOpen:i,onOpenChange:a,modal:o=!0}=e,s=_.useRef(null),c=_.useRef(null),[l,u]=ze({prop:r,defaultProp:i??!1,onChange:a,caller:dr});return(0,j.jsx)(mr,{scope:t,triggerRef:s,contentRef:c,contentId:Pe(),titleId:Pe(),descriptionId:Pe(),open:l,onOpenChange:u,onOpenToggle:_.useCallback(()=>u(e=>!e),[u]),modal:o,children:n})};gr.displayName=dr;var _r=\`DialogTrigger\`,vr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(_r,n),a=De(t,i.triggerRef);return(0,j.jsx)(tt.button,{type:\`button\`,"aria-haspopup":\`dialog\`,"aria-expanded":i.open,"aria-controls":i.open?i.contentId:void 0,"data-state":Rr(i.open),...r,ref:a,onClick:we(e.onClick,i.onOpenToggle)})});vr.displayName=_r;var yr=\`DialogPortal\`,[br,xr]=fr(yr,{forceMount:void 0}),Sr=e=>{let{__scopeDialog:t,forceMount:n,children:r,container:i}=e,a=hr(yr,t);return(0,j.jsx)(br,{scope:t,forceMount:n,children:_.Children.map(r,e=>(0,j.jsx)(It,{present:n||a.open,children:(0,j.jsx)(Pt,{asChild:!0,container:i,children:e})}))})};Sr.displayName=yr;var Cr=\`DialogOverlay\`,wr=_.forwardRef((e,t)=>{let n=xr(Cr,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=hr(Cr,e.__scopeDialog);return a.modal?(0,j.jsx)(It,{present:r||a.open,children:(0,j.jsx)(Er,{...i,ref:t})}):null});wr.displayName=Cr;var Tr=Ue(\`DialogOverlay.RemoveScroll\`),Er=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Cr,n),a=De(t,pt());return(0,j.jsx)(tr,{as:Tr,allowPinchZoom:!0,shards:[i.contentRef],children:(0,j.jsx)(tt.div,{"data-state":Rr(i.open),...r,ref:a,style:{pointerEvents:\`auto\`,...r.style}})})}),Dr=\`DialogContent\`,Or=_.forwardRef((e,t)=>{let n=xr(Dr,e.__scopeDialog),{forceMount:r=n.forceMount,...i}=e,a=hr(Dr,e.__scopeDialog);return(0,j.jsx)(It,{present:r||a.open,children:a.modal?(0,j.jsx)(kr,{...i,ref:t}):(0,j.jsx)(Ar,{...i,ref:t})})});Or.displayName=Dr;var kr=_.forwardRef((e,t)=>{let n=hr(Dr,e.__scopeDialog),r=_.useRef(null),i=De(t,n.contentRef,r);return _.useEffect(()=>{let e=r.current;if(e)return ur(e)},[]),(0,j.jsx)(jr,{...e,ref:i,trapFocus:n.open,disableOutsidePointerEvents:n.open,onCloseAutoFocus:we(e.onCloseAutoFocus,e=>{e.preventDefault(),n.triggerRef.current?.focus()}),onPointerDownOutside:we(e.onPointerDownOutside,e=>{let t=e.detail.originalEvent,n=t.button===0&&t.ctrlKey===!0;(t.button===2||n)&&e.preventDefault()}),onFocusOutside:we(e.onFocusOutside,e=>e.preventDefault())})}),Ar=_.forwardRef((e,t)=>{let n=hr(Dr,e.__scopeDialog),r=_.useRef(!1),i=_.useRef(!1);return(0,j.jsx)(jr,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{e.onCloseAutoFocus?.(t),t.defaultPrevented||(r.current||n.triggerRef.current?.focus(),t.preventDefault()),r.current=!1,i.current=!1},onInteractOutside:t=>{e.onInteractOutside?.(t),t.defaultPrevented||(r.current=!0,t.detail.originalEvent.type===\`pointerdown\`&&(i.current=!0));let a=t.target;n.triggerRef.current?.contains(a)&&t.preventDefault(),t.detail.originalEvent.type===\`focusin\`&&i.current&&t.preventDefault()}})}),jr=_.forwardRef((e,t)=>{let{__scopeDialog:n,trapFocus:r,onOpenAutoFocus:i,onCloseAutoFocus:a,...o}=e,s=hr(Dr,n);return Wt(),(0,j.jsx)(j.Fragment,{children:(0,j.jsx)(St,{asChild:!0,loop:!0,trapped:r,onMountAutoFocus:i,onUnmountAutoFocus:a,children:(0,j.jsx)(ut,{role:\`dialog\`,id:s.contentId,"aria-describedby":s.descriptionId,"aria-labelledby":s.titleId,"data-state":Rr(s.open),...o,ref:t,deferPointerDownOutside:!0,onDismiss:()=>s.onOpenChange(!1)})})})}),Mr=\`DialogTitle\`,Nr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Mr,n);return(0,j.jsx)(tt.h2,{id:i.titleId,...r,ref:t})});Nr.displayName=Mr;var Pr=\`DialogDescription\`,Fr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Pr,n);return(0,j.jsx)(tt.p,{id:i.descriptionId,...r,ref:t})});Fr.displayName=Pr;var Ir=\`DialogClose\`,Lr=_.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=hr(Ir,n);return(0,j.jsx)(tt.button,{type:\`button\`,...r,ref:t,onClick:we(e.onClick,()=>i.onOpenChange(!1))})});Lr.displayName=Ir;function Rr(e){return e?\`open\`:\`closed\`}function zr(e){var t,n,r=\`\`;if(typeof e==\`string\`||typeof e==\`number\`)r+=e;else if(typeof e==\`object\`)if(Array.isArray(e)){var i=e.length;for(t=0;t<i;t++)e[t]&&(n=zr(e[t]))&&(r&&(r+=\` \`),r+=n)}else for(n in e)e[n]&&(r&&(r+=\` \`),r+=n);return r}function Br(){for(var e,t,n=0,r=\`\`,i=arguments.length;n<i;n++)(e=arguments[n])&&(t=zr(e))&&(r&&(r+=\` \`),r+=t);return r}function N({variant:e=\`default\`,size:t=\`sm\`,className:n,...r}){return(0,j.jsx)(\`button\`,{className:Br(\`inline-flex items-center justify-center gap-1.5 rounded-md transition-colors disabled:opacity-50 disabled:pointer-events-none\`,t===\`sm\`?\`h-8 px-3 text-[13px]\`:\`h-6 px-2 text-xs\`,{default:\`bg-emerald-600 text-white hover:bg-emerald-500 font-medium\`,outline:\`border border-neutral-700 text-neutral-200 hover:bg-neutral-800 hover:border-neutral-600\`,ghost:\`text-neutral-300 hover:bg-neutral-800\`,danger:\`border border-red-900/60 text-red-400 hover:bg-red-950/40\`}[e],n),...r})}function Vr({className:e,...t}){return(0,j.jsx)(\`input\`,{className:Br(\`h-8 w-full rounded-md border border-neutral-700 bg-neutral-900 px-2.5 text-[13px] text-neutral-100\`,\`placeholder:text-neutral-600 focus:border-brand focus:outline-none\`,e),...t})}function Hr({className:e,...t}){return(0,j.jsx)(\`textarea\`,{className:Br(\`w-full rounded-md border border-neutral-700 bg-neutral-900 p-3 font-mono text-[13px] text-neutral-100\`,\`placeholder:text-neutral-600 focus:border-brand focus:outline-none\`,e),...t})}function Ur({children:e}){return(0,j.jsx)(\`label\`,{className:\`mb-1 block text-xs font-medium text-neutral-400\`,children:e})}function Wr({open:e,onClose:t,title:n,children:r,wide:i}){return(0,j.jsx)(gr,{open:e,onOpenChange:e=>!e&&t(),children:(0,j.jsxs)(Sr,{children:[(0,j.jsx)(wr,{className:\`fixed inset-0 z-50 bg-black/60 backdrop-blur-sm\`}),(0,j.jsxs)(Or,{className:Br(\`fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2 rounded-lg border border-neutral-700 bg-neutral-850 bg-[#1f1f1f] shadow-2xl\`,\`max-h-[85vh] overflow-auto\`,i?\`w-[640px]\`:\`w-[440px]\`),children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between border-b border-neutral-800 px-4 py-3\`,children:[(0,j.jsx)(Nr,{className:\`text-sm font-semibold\`,children:n}),(0,j.jsx)(Lr,{className:\`text-neutral-500 hover:text-neutral-200\`,children:(0,j.jsx)(ve,{size:16})})]}),(0,j.jsx)(\`div\`,{className:\`p-4\`,children:r})]})]})})}function Gr(){return(0,j.jsx)(\`div\`,{className:\`flex items-center justify-center py-16 text-neutral-500\`,children:(0,j.jsx)(\`div\`,{className:\`size-5 animate-spin rounded-full border-2 border-neutral-700 border-t-brand\`})})}function Kr({children:e}){return(0,j.jsx)(\`div\`,{className:\`py-16 text-center text-[13px] text-neutral-500\`,children:e})}var qr=50;function Jr(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)(0),[c,l]=(0,_.useState)(0),[u,d]=(0,_.useState)(!0),[f,p]=(0,_.useState)(null),[m,h]=(0,_.useState)(!1),[g,v]=(0,_.useState)(\`\`),y=e.find(e=>e.name===n)||null,b=(0,_.useCallback)(async()=>{let e=await A.tables();t(e),r(t=>t??e[0]?.name??null)},[]);(0,_.useEffect)(()=>{b().finally(()=>d(!1))},[b]);let x=(0,_.useCallback)(async()=>{if(!n||!y)return;let e=y.primaryKey[0]?\`\${y.primaryKey[0]}.asc\`:void 0,{rows:t,total:r}=await A.rows(n,{limit:qr,offset:c*qr,order:e});a(t),s(r)},[n,c,y]);(0,_.useEffect)(()=>{x()},[x]);function ee(e){let t={};for(let n of y.primaryKey)t[n]=e[n];return t}async function S(e){if(!y?.primaryKey.length)return alert(\`Cannot delete: table has no primary key\`);if(confirm(\`Delete this row?\`))try{await A.deleteRow(n,ee(e)),await x(),await b()}catch(e){alert(e.message)}}return u?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex w-60 shrink-0 flex-col border-r border-neutral-800 bg-[#191919]\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between px-3 py-2.5 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:[\`Tables \`,(0,j.jsx)(\`span\`,{className:\`text-neutral-600\`,children:e.length})]}),(0,j.jsxs)(\`div\`,{className:\`flex-1 overflow-auto\`,children:[e.map(e=>(0,j.jsxs)(\`button\`,{onClick:()=>{r(e.name),l(0)},className:\`flex w-full items-center justify-between px-3 py-1.5 text-left text-[13px] \`+(n===e.name?\`bg-neutral-800 text-neutral-100\`:\`text-neutral-400 hover:bg-neutral-850 hover:bg-neutral-800/50\`),children:[(0,j.jsx)(\`span\`,{className:\`truncate font-mono\`,children:e.name}),(0,j.jsx)(\`span\`,{className:\`text-[11px] text-neutral-600\`,children:e.rowCount})]},e.name)),e.length===0&&(0,j.jsx)(Kr,{children:\`No tables. Create one in the SQL Editor.\`})]})]}),(0,j.jsx)(\`div\`,{className:\`flex min-w-0 flex-1 flex-col\`,children:y?(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(\`span\`,{className:\`font-mono text-sm\`,children:y.name}),(0,j.jsxs)(\`span\`,{className:\`rounded bg-neutral-800 px-1.5 py-0.5 text-[11px] text-neutral-400\`,children:[o,\` rows\`]}),(0,j.jsxs)(\`div\`,{className:\`ml-auto flex items-center gap-1.5\`,children:[(0,j.jsx)(N,{variant:\`ghost\`,size:\`xs\`,onClick:()=>void x(),children:(0,j.jsx)(fe,{size:13})}),(0,j.jsxs)(N,{size:\`xs\`,onClick:()=>h(!0),children:[(0,j.jsx)(de,{size:13}),\` Insert\`]})]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`sticky top-0 z-10 bg-[#1c1c1c]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800\`,children:[(0,j.jsx)(\`th\`,{className:\`w-16 px-2 py-1.5\`}),y.columns.map(e=>(0,j.jsxs)(\`th\`,{className:\`whitespace-nowrap px-3 py-1.5 text-left font-medium text-neutral-400\`,children:[(0,j.jsx)(\`span\`,{className:\`font-mono text-neutral-200\`,children:e.name}),e.isPrimaryKey&&(0,j.jsx)(\`span\`,{className:\`ml-1 text-[10px] text-brand\`,children:\`PK\`}),(0,j.jsx)(\`span\`,{className:\`ml-1.5 text-[11px] font-normal text-neutral-600\`,children:e.type})]},e.name))]})}),(0,j.jsx)(\`tbody\`,{children:i.map((e,t)=>(0,j.jsxs)(\`tr\`,{className:\`group border-b border-neutral-850 border-neutral-800/60 hover:bg-neutral-800/30\`,children:[(0,j.jsx)(\`td\`,{className:\`px-2\`,children:(0,j.jsxs)(\`div\`,{className:\`flex gap-0.5 opacity-0 group-hover:opacity-100\`,children:[(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-brand\`,onClick:()=>p(e),children:(0,j.jsx)(T,{size:13})}),(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-red-400\`,onClick:()=>S(e),children:(0,j.jsx)(ge,{size:13})})]})}),y.columns.map(t=>(0,j.jsx)(\`td\`,{className:\`max-w-[320px] truncate px-3 py-1.5 font-mono text-neutral-300\`,children:(0,j.jsx)(Yr,{value:e[t.name]})},t.name))]},t))})]}),i.length===0&&(0,j.jsx)(Kr,{children:\`No rows yet.\`})]}),(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-t border-neutral-800 px-4 py-2 text-xs text-neutral-500\`,children:[(0,j.jsx)(N,{variant:\`ghost\`,size:\`xs\`,disabled:c===0,onClick:()=>l(e=>e-1),children:(0,j.jsx)(ie,{size:13})}),(0,j.jsxs)(\`span\`,{children:[o===0?0:c*qr+1,\`–\`,Math.min((c+1)*qr,o),\` of \`,o]}),(0,j.jsx)(N,{variant:\`ghost\`,size:\`xs\`,disabled:(c+1)*qr>=o,onClick:()=>l(e=>e+1),children:(0,j.jsx)(ae,{size:13})})]})]}):(0,j.jsx)(Kr,{children:\`Select a table.\`})}),f&&y&&(0,j.jsx)(Xr,{table:y,initial:f,onClose:()=>p(null),onSave:async e=>{await A.updateRow(n,ee(f),e),p(null),await x()}}),m&&y&&(0,j.jsx)(Xr,{table:y,initial:{},isNew:!0,onClose:()=>h(!1),onSave:async e=>{await A.insertRow(n,e),h(!1),await x(),await b()}}),g&&(0,j.jsx)(\`p\`,{className:\`text-red-400\`,children:g})]})}function Yr({value:e}){return e==null?(0,j.jsx)(\`span\`,{className:\`text-neutral-600\`,children:\`NULL\`}):typeof e==\`boolean\`?(0,j.jsx)(\`span\`,{className:\`text-blue-400\`,children:String(e)}):typeof e==\`object\`?(0,j.jsx)(\`span\`,{className:\`text-amber-300/80\`,children:JSON.stringify(e)}):(0,j.jsx)(j.Fragment,{children:String(e)})}function Xr({table:e,initial:t,isNew:n,onClose:r,onSave:i}){let a=e.columns.filter(e=>!(n&&e.isPrimaryKey&&e.hasDefault)),[o,s]=(0,_.useState)(()=>{let e={};for(let n of a){let r=t[n.name];e[n.name]=r==null?\`\`:typeof r==\`object\`?JSON.stringify(r):String(r)}return e}),[c,l]=(0,_.useState)({}),[u,d]=(0,_.useState)(\`\`),[f,p]=(0,_.useState)(!1);async function m(){p(!0),d(\`\`);let e={};for(let t of a){if(!n&&!c[t.name])continue;let r=o[t.name];if(r===\`\`&&(t.nullable||t.hasDefault)){n||(e[t.name]=null);continue}e[t.name]=Zr(r,t.type)}try{await i(e)}catch(e){d(e.message),p(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:r,title:n?\`Insert into \${e.name}\`:\`Edit row in \${e.name}\`,wide:!0,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[a.map(e=>(0,j.jsxs)(\`div\`,{children:[(0,j.jsxs)(Ur,{children:[e.name,(0,j.jsxs)(\`span\`,{className:\`ml-1.5 font-normal text-neutral-600\`,children:[e.type,e.isPrimaryKey?\` · PK\`:\`\`,!e.nullable&&!e.hasDefault?\` · required\`:\`\`]})]}),(0,j.jsx)(Vr,{value:o[e.name]??\`\`,placeholder:e.hasDefault?\`default\`:e.nullable?\`NULL\`:\`\`,onChange:t=>{s(n=>({...n,[e.name]:t.target.value})),l(t=>({...t,[e.name]:!0}))}})]},e.name)),u&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:u}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2 pt-1\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:r,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:m,disabled:f,children:f?\`Saving…\`:n?\`Insert\`:\`Save\`})]})]})})}function Zr(e,t){if(t===\`bool\`)return e===\`true\`||e===\`t\`||e===\`1\`;if([\`int2\`,\`int4\`,\`int8\`,\`float4\`,\`float8\`,\`numeric\`].includes(t)){let t=Number(e);return Number.isNaN(t)?e:t}if(t===\`json\`||t===\`jsonb\`)try{return JSON.parse(e)}catch{return e}if(t.startsWith(\`_\`))try{return JSON.parse(e)}catch{return e}return e}function Qr(){let[e,t]=(0,_.useState)(\`select * from \`),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)(!1);async function o(){a(!0),r(await A.sql(e)),a(!1)}let s=n?.rows?.[0]?Object.keys(n.rows[0]):[];return(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`border-b border-neutral-800 p-3\`,children:[(0,j.jsx)(Hr,{className:\`h-40\`,value:e,onChange:e=>t(e.target.value),onKeyDown:e=>(e.metaKey||e.ctrlKey)&&e.key===\`Enter\`&&o(),spellCheck:!1,placeholder:\`select * from … (⌘⏎ to run)\`}),(0,j.jsxs)(\`div\`,{className:\`mt-2 flex items-center gap-3\`,children:[(0,j.jsxs)(N,{onClick:o,disabled:i,children:[(0,j.jsx)(E,{size:13}),\` Run\`]}),(0,j.jsx)(\`span\`,{className:\`text-xs text-neutral-500\`,children:\`⌘⏎\`}),n&&(0,j.jsx)(\`span\`,{className:\`ml-auto text-xs text-neutral-500\`,children:n.ok?\`\${n.rowCount} rows · \${n.ms} ms\${n.affectedRows==null?\`\`:\` · \${n.affectedRows} affected\`}\`:\`\`})]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto\`,children:[!n&&(0,j.jsx)(Kr,{children:\`Run a query to see results.\`}),n&&!n.ok&&(0,j.jsxs)(\`div\`,{className:\`m-4 rounded-md border border-red-900/50 bg-red-950/30 p-3 text-[13px] text-red-300\`,children:[(0,j.jsx)(\`div\`,{className:\`font-mono\`,children:n.error}),n.code&&(0,j.jsxs)(\`div\`,{className:\`mt-1 text-xs text-red-400/70\`,children:[\`SQLSTATE \`,n.code]}),n.hint&&(0,j.jsxs)(\`div\`,{className:\`mt-1 text-xs text-neutral-400\`,children:[\`Hint: \`,n.hint]})]}),n?.ok&&s.length>0&&(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`sticky top-0 bg-[#1c1c1c]\`,children:(0,j.jsx)(\`tr\`,{className:\`border-b border-neutral-800\`,children:s.map(e=>(0,j.jsx)(\`th\`,{className:\`whitespace-nowrap px-3 py-1.5 text-left font-mono font-medium text-neutral-300\`,children:e},e))})}),(0,j.jsx)(\`tbody\`,{children:n.rows.map((e,t)=>(0,j.jsx)(\`tr\`,{className:\`border-b border-neutral-800/60 hover:bg-neutral-800/30\`,children:s.map(t=>(0,j.jsx)(\`td\`,{className:\`max-w-[360px] truncate px-3 py-1.5 font-mono text-neutral-300\`,children:$r(e[t])},t))},t))})]}),n?.ok&&s.length===0&&(0,j.jsxs)(Kr,{children:[\`Statement executed\`,n.affectedRows==null?\`\`:\` · \${n.affectedRows} rows affected\`,\`.\`]})]})]})}function $r(e){return e==null?(0,j.jsx)(\`span\`,{className:\`text-neutral-600\`,children:\`NULL\`}):typeof e==\`object\`?JSON.stringify(e):String(e)}function ei(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(!0),[i,a]=(0,_.useState)(!1),[o,s]=(0,_.useState)(null);async function c(){t(await A.users())}(0,_.useEffect)(()=>{c().finally(()=>r(!1))},[]);async function l(e){confirm(\`Delete \${e.email||e.id}?\`)&&(await A.deleteUser(e.id),await c())}return n?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(\`span\`,{className:\`text-sm font-semibold\`,children:\`Users\`}),(0,j.jsx)(\`span\`,{className:\`rounded bg-neutral-800 px-1.5 py-0.5 text-[11px] text-neutral-400\`,children:e.length}),(0,j.jsxs)(N,{size:\`xs\`,className:\`ml-auto\`,onClick:()=>a(!0),children:[(0,j.jsx)(de,{size:13}),\` Add user\`]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`sticky top-0 bg-[#1c1c1c]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-1.5 font-medium\`,children:\`Email\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`UID\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`Provider\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`Created\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 font-medium\`,children:\`Last sign in\`}),(0,j.jsx)(\`th\`,{className:\`w-20\`})]})}),(0,j.jsx)(\`tbody\`,{children:e.map(e=>(0,j.jsxs)(\`tr\`,{className:\`group border-b border-neutral-800/60 hover:bg-neutral-800/30\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5\`,children:e.email||(0,j.jsx)(\`span\`,{className:\`text-neutral-500\`,children:e.is_anonymous?\`anonymous\`:\`—\`})}),(0,j.jsxs)(\`td\`,{className:\`px-3 py-1.5 font-mono text-[11px] text-neutral-500\`,children:[e.id.slice(0,8),\`…\`]}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:e.app_metadata?.provider||\`—\`}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:(e.created_at||\`\`).slice(0,10)}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:(e.last_sign_in_at||\`\`).slice(0,16).replace(\`T\`,\` \`)}),(0,j.jsx)(\`td\`,{className:\`px-3\`,children:(0,j.jsxs)(\`div\`,{className:\`flex gap-0.5 opacity-0 group-hover:opacity-100\`,children:[(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-brand\`,title:\`Reset password\`,onClick:()=>s(e),children:(0,j.jsx)(ue,{size:13})}),(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 hover:text-red-400\`,onClick:()=>l(e),children:(0,j.jsx)(ge,{size:13})})]})})]},e.id))})]}),e.length===0&&(0,j.jsx)(Kr,{children:\`No users yet.\`})]}),i&&(0,j.jsx)(ti,{onClose:()=>a(!1),onDone:async()=>{a(!1),await c()}}),o&&(0,j.jsx)(ni,{user:o,onClose:()=>s(null),onDone:async()=>{s(null),await c()}})]})}function ti({onClose:e,onDone:t}){let[n,r]=(0,_.useState)(\`\`),[i,a]=(0,_.useState)(\`\`),[o,s]=(0,_.useState)(\`\`),[c,l]=(0,_.useState)(!1);async function u(){l(!0),s(\`\`);try{await A.createUser({email:n,password:i||void 0,email_confirm:!0}),t()}catch(e){s(e.message),l(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:e,title:\`Add user\`,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Email\`}),(0,j.jsx)(Vr,{value:n,onChange:e=>r(e.target.value),placeholder:\`user@example.com\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Password (optional)\`}),(0,j.jsx)(Vr,{type:\`password\`,value:i,onChange:e=>a(e.target.value)})]}),o&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:o}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:e,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:u,disabled:c||!n,children:c?\`Creating…\`:\`Create\`})]})]})})}function ni({user:e,onClose:t,onDone:n}){let[r,i]=(0,_.useState)(\`\`),[a,o]=(0,_.useState)(\`\`),[s,c]=(0,_.useState)(!1);async function l(){c(!0),o(\`\`);try{await A.updateUser(e.id,{password:r}),n()}catch(e){o(e.message),c(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:t,title:\`Reset password · \${e.email||e.id}\`,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`New password\`}),(0,j.jsx)(Vr,{type:\`password\`,value:r,onChange:e=>i(e.target.value)})]}),a&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:a}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:t,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:l,disabled:s||r.length<6,children:s?\`Saving…\`:\`Update\`})]})]})})}function ri(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)(!0),[c,l]=(0,_.useState)(!1),u=(0,_.useRef)(null);async function d(){let e=await A.buckets();t(e),r(t=>t??e[0]?.id??null)}async function f(e){a(await A.listObjects(e))}(0,_.useEffect)(()=>{d().finally(()=>s(!1))},[]),(0,_.useEffect)(()=>{n&&f(n)},[n]);async function p(e){n&&(await A.uploadObject(n,e.name,e),await f(n))}async function m(e){!n||!confirm(\`Delete \${e}?\`)||(await A.removeObject(n,e),await f(n))}async function h(e){if(confirm(\`Delete bucket "\${e}"? It must be empty.\`))try{await A.deleteBucket(e),r(null),await d()}catch(e){alert(e.message)}}return o?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex w-60 shrink-0 flex-col border-r border-neutral-800 bg-[#191919]\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between px-3 py-2.5 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:[\`Buckets\`,(0,j.jsx)(\`button\`,{className:\`text-neutral-400 hover:text-brand\`,onClick:()=>l(!0),children:(0,j.jsx)(de,{size:14})})]}),(0,j.jsxs)(\`div\`,{className:\`flex-1 overflow-auto\`,children:[e.map(e=>(0,j.jsxs)(\`button\`,{onClick:()=>r(e.id),className:\`group flex w-full items-center justify-between px-3 py-1.5 text-left text-[13px] \`+(n===e.id?\`bg-neutral-800 text-neutral-100\`:\`text-neutral-400 hover:bg-neutral-800/50\`),children:[(0,j.jsxs)(\`span\`,{className:\`truncate\`,children:[e.id,e.public&&(0,j.jsx)(\`span\`,{className:\`ml-1.5 text-[10px] text-brand\`,children:\`public\`})]}),(0,j.jsx)(ge,{size:13,className:\`opacity-0 hover:text-red-400 group-hover:opacity-100\`,onClick:t=>{t.stopPropagation(),h(e.id)}})]},e.id)),e.length===0&&(0,j.jsx)(Kr,{children:\`No buckets.\`})]})]}),(0,j.jsx)(\`div\`,{className:\`flex min-w-0 flex-1 flex-col\`,children:n?(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(\`span\`,{className:\`font-mono text-sm\`,children:n}),(0,j.jsx)(\`input\`,{ref:u,type:\`file\`,className:\`hidden\`,onChange:e=>e.target.files?.[0]&&p(e.target.files[0])}),(0,j.jsxs)(N,{size:\`xs\`,className:\`ml-auto\`,onClick:()=>u.current?.click(),children:[(0,j.jsx)(_e,{size:13}),\` Upload\`]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto p-2\`,children:[i.map(e=>(0,j.jsxs)(\`div\`,{className:\`group flex items-center gap-2 rounded-md px-2 py-1.5 text-[13px] hover:bg-neutral-800/40\`,children:[(0,j.jsx)(se,{size:14,className:\`text-neutral-500\`}),(0,j.jsx)(\`span\`,{className:\`font-mono\`,children:e.name}),e.metadata?.size!=null&&(0,j.jsx)(\`span\`,{className:\`text-[11px] text-neutral-500\`,children:ai(e.metadata.size)}),(0,j.jsx)(\`button\`,{className:\`ml-auto p-1 text-neutral-500 opacity-0 hover:text-red-400 group-hover:opacity-100\`,onClick:()=>m(e.name),children:(0,j.jsx)(ge,{size:13})})]},e.name)),i.length===0&&(0,j.jsx)(Kr,{children:\`Empty bucket. Upload a file.\`})]})]}):(0,j.jsx)(Kr,{children:\`Select or create a bucket.\`})}),c&&(0,j.jsx)(ii,{onClose:()=>l(!1),onDone:async()=>{l(!1),await d()}})]})}function ii({onClose:e,onDone:t}){let[n,r]=(0,_.useState)(\`\`),[i,a]=(0,_.useState)(!1),[o,s]=(0,_.useState)(\`\`),[c,l]=(0,_.useState)(!1);async function u(){l(!0),s(\`\`);try{await A.createBucket({id:n,name:n,public:i}),t()}catch(e){s(e.message),l(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:e,title:\`New bucket\`,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Name\`}),(0,j.jsx)(Vr,{value:n,onChange:e=>r(e.target.value),placeholder:\`avatars\`})]}),(0,j.jsxs)(\`label\`,{className:\`flex items-center gap-2 text-[13px] text-neutral-300\`,children:[(0,j.jsx)(\`input\`,{type:\`checkbox\`,checked:i,onChange:e=>a(e.target.checked)}),\`Public bucket (objects readable without auth)\`]}),o&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:o}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:e,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:u,disabled:c||!n,children:c?\`Creating…\`:\`Create\`})]})]})})}function ai(e){return e<1024?\`\${e} B\`:e<1024*1024?\`\${(e/1024).toFixed(1)} KB\`:\`\${(e/1024/1024).toFixed(1)} MB\`}function oi(){let[e,t]=(0,_.useState)(null),[n,r]=(0,_.useState)([]),[i,a]=(0,_.useState)([]),[o,s]=(0,_.useState)([]),[c,l]=(0,_.useState)(!0);return(0,_.useEffect)(()=>{Promise.all([A.stats(),A.migrations(),A.functions(),A.triggers()]).then(([e,n,i,o])=>{t(e),r(n),a(i),s(o)}).finally(()=>l(!1))},[]),c?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`h-full overflow-auto p-6\`,children:[(0,j.jsx)(\`h1\`,{className:\`text-sm font-semibold text-neutral-300\`,children:\`Database\`}),e&&(0,j.jsxs)(j.Fragment,{children:[(0,j.jsx)(\`p\`,{className:\`mt-1 font-mono text-xs text-neutral-500\`,children:e.version}),(0,j.jsxs)(\`div\`,{className:\`mt-4 grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6\`,children:[(0,j.jsx)(si,{label:\`Tables\`,value:e.tables}),(0,j.jsx)(si,{label:\`Users\`,value:e.users}),(0,j.jsx)(si,{label:\`Buckets\`,value:e.buckets}),(0,j.jsx)(si,{label:\`Objects\`,value:e.objects}),(0,j.jsx)(si,{label:\`Migrations\`,value:e.migrations}),(0,j.jsx)(si,{label:\`DB size\`,value:e.dbSize})]})]}),(0,j.jsx)(\`h2\`,{className:\`mb-2 mt-8 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:\`Migrations\`}),(0,j.jsxs)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Version\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Name\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Applied\`})]})}),(0,j.jsx)(\`tbody\`,{children:n.map(e=>(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-400\`,children:e.version}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono\`,children:e.name||\`—\`}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:(e.applied_at||\`\`).slice(0,19).replace(\`T\`,\` \`)})]},e.version))})]}),n.length===0&&(0,j.jsx)(Kr,{children:\`No migrations applied.\`})]}),(0,j.jsx)(\`h2\`,{className:\`mb-2 mt-8 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:\`Functions\`}),(0,j.jsxs)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Name\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Arguments\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Returns\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Language\`})]})}),(0,j.jsx)(\`tbody\`,{children:i.map(e=>(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-200\`,children:e.name}),(0,j.jsx)(\`td\`,{className:\`max-w-[280px] truncate px-4 py-1.5 font-mono text-[11px] text-neutral-500\`,children:e.args||\`—\`}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-400\`,children:e.returns}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:e.language})]},e.name))})]}),i.length===0&&(0,j.jsx)(Kr,{children:\`No user functions.\`})]}),(0,j.jsx)(\`h2\`,{className:\`mb-2 mt-8 text-xs font-semibold uppercase tracking-wide text-neutral-500\`,children:\`Triggers\`}),(0,j.jsxs)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:[(0,j.jsxs)(\`table\`,{className:\`w-full border-collapse text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919]\`,children:(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800 text-left text-neutral-400\`,children:[(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Name\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Table\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Timing\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Events\`}),(0,j.jsx)(\`th\`,{className:\`px-4 py-2 font-medium\`,children:\`Function\`})]})}),(0,j.jsx)(\`tbody\`,{children:o.map(e=>(0,j.jsxs)(\`tr\`,{className:\`border-b border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-200\`,children:e.name}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-neutral-400\`,children:e.table}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:e.timing}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 text-neutral-400\`,children:(e.events||[]).join(\`, \`)}),(0,j.jsx)(\`td\`,{className:\`px-4 py-1.5 font-mono text-[11px] text-neutral-500\`,children:e.function})]},e.table+e.name))})]}),o.length===0&&(0,j.jsx)(Kr,{children:\`No triggers.\`})]})]})}function si({label:e,value:t}){return(0,j.jsxs)(\`div\`,{className:\`rounded-lg border border-neutral-800 bg-[#191919] p-3\`,children:[(0,j.jsx)(\`div\`,{className:\`text-lg font-semibold text-neutral-100\`,children:t}),(0,j.jsx)(\`div\`,{className:\`text-xs text-neutral-500\`,children:e})]})}function ci(){let[e,t]=(0,_.useState)([]),[n,r]=(0,_.useState)(!0),[i,a]=(0,_.useState)(!1);async function o(){t(await A.policies())}(0,_.useEffect)(()=>{o().finally(()=>r(!1))},[]);async function s(e){confirm(\`Drop policy "\${e.name}" on \${e.table}?\`)&&(await A.dropPolicy(e.table,e.name),await o())}if(n)return(0,j.jsx)(Gr,{});let c=new Map;for(let t of e)c.has(t.table)||c.set(t.table,[]),c.get(t.table).push(t);return(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2 border-b border-neutral-800 px-4 py-2.5\`,children:[(0,j.jsx)(me,{size:15,className:\`text-brand\`}),(0,j.jsx)(\`span\`,{className:\`text-sm font-semibold\`,children:\`RLS Policies\`}),(0,j.jsx)(\`span\`,{className:\`rounded bg-neutral-800 px-1.5 py-0.5 text-[11px] text-neutral-400\`,children:e.length}),(0,j.jsxs)(N,{size:\`xs\`,className:\`ml-auto\`,onClick:()=>a(!0),children:[(0,j.jsx)(de,{size:13}),\` New policy\`]})]}),(0,j.jsxs)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto p-4\`,children:[[...c].map(([e,t])=>(0,j.jsxs)(\`div\`,{className:\`mb-5\`,children:[(0,j.jsx)(\`div\`,{className:\`mb-1.5 font-mono text-[13px] text-neutral-300\`,children:e}),(0,j.jsx)(\`div\`,{className:\`overflow-hidden rounded-md border border-neutral-800\`,children:(0,j.jsxs)(\`table\`,{className:\`w-full text-[13px]\`,children:[(0,j.jsx)(\`thead\`,{className:\`bg-[#191919] text-neutral-400\`,children:(0,j.jsxs)(\`tr\`,{children:[(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`Policy\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`Command\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`Roles\`}),(0,j.jsx)(\`th\`,{className:\`px-3 py-1.5 text-left font-medium\`,children:\`USING / CHECK\`}),(0,j.jsx)(\`th\`,{className:\`w-10\`})]})}),(0,j.jsx)(\`tbody\`,{children:t.map(e=>(0,j.jsxs)(\`tr\`,{className:\`group border-t border-neutral-800/60\`,children:[(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5\`,children:e.name}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 text-neutral-400\`,children:e.cmd}),(0,j.jsx)(\`td\`,{className:\`px-3 py-1.5 font-mono text-[11px] text-neutral-500\`,children:Array.isArray(e.roles)?e.roles.join(\`, \`):e.roles}),(0,j.jsx)(\`td\`,{className:\`max-w-[360px] truncate px-3 py-1.5 font-mono text-[11px] text-amber-300/70\`,children:[e.using_expr&&\`USING \${e.using_expr}\`,e.with_check&&\`CHECK \${e.with_check}\`].filter(Boolean).join(\` · \`)}),(0,j.jsx)(\`td\`,{className:\`px-2\`,children:(0,j.jsx)(\`button\`,{className:\`p-1 text-neutral-500 opacity-0 hover:text-red-400 group-hover:opacity-100\`,onClick:()=>s(e),children:(0,j.jsx)(ge,{size:13})})})]},e.name))})]})})]},e)),e.length===0&&(0,j.jsx)(Kr,{children:\`No policies. Create one, or enable RLS on a table first.\`})]}),i&&(0,j.jsx)(li,{onClose:()=>a(!1),onDone:async()=>{a(!1),await o()}})]})}function li({onClose:e,onDone:t}){let[n,r]=(0,_.useState)({table:\`\`,name:\`\`,command:\`ALL\`,roles:\`authenticated\`,using:\`\`,check:\`\`}),[i,a]=(0,_.useState)(\`\`),[o,s]=(0,_.useState)(!1),c=(e,t)=>r(n=>({...n,[e]:t}));async function l(){s(!0),a(\`\`);try{let e=await A.createPolicy(n);if(e.error)throw Error(e.error+(e.hint?\` (\${e.hint})\`:\`\`));t()}catch(e){a(e.message),s(!1)}}return(0,j.jsx)(Wr,{open:!0,onClose:e,title:\`New RLS policy\`,wide:!0,children:(0,j.jsxs)(\`div\`,{className:\`space-y-3\`,children:[(0,j.jsxs)(\`div\`,{className:\`grid grid-cols-2 gap-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Table\`}),(0,j.jsx)(Vr,{value:n.table,onChange:e=>c(\`table\`,e.target.value),placeholder:\`todos\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Policy name\`}),(0,j.jsx)(Vr,{value:n.name,onChange:e=>c(\`name\`,e.target.value),placeholder:\`own rows\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Command\`}),(0,j.jsx)(\`select\`,{className:\`h-8 w-full rounded-md border border-neutral-700 bg-neutral-900 px-2 text-[13px]\`,value:n.command,onChange:e=>c(\`command\`,e.target.value),children:[\`ALL\`,\`SELECT\`,\`INSERT\`,\`UPDATE\`,\`DELETE\`].map(e=>(0,j.jsx)(\`option\`,{children:e},e))})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`Roles\`}),(0,j.jsx)(Vr,{value:n.roles,onChange:e=>c(\`roles\`,e.target.value),placeholder:\`authenticated\`})]})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`USING expression (read/visibility)\`}),(0,j.jsx)(Vr,{value:n.using,onChange:e=>c(\`using\`,e.target.value),placeholder:\`user_id = auth.uid()\`})]}),(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(Ur,{children:\`WITH CHECK expression (writes)\`}),(0,j.jsx)(Vr,{value:n.check,onChange:e=>c(\`check\`,e.target.value),placeholder:\`user_id = auth.uid()\`})]}),i&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:i}),(0,j.jsxs)(\`div\`,{className:\`flex justify-end gap-2\`,children:[(0,j.jsx)(N,{variant:\`outline\`,onClick:e,children:\`Cancel\`}),(0,j.jsx)(N,{onClick:l,disabled:o||!n.table||!n.name,children:o?\`Creating…\`:\`Create policy\`})]})]})})}var ui={info:\`text-neutral-500\`,warn:\`text-amber-400\`,error:\`text-red-400\`};function di(){let[e,t]=(0,_.useState)(null),[n,r]=(0,_.useState)(!0),i=(0,_.useRef)(null);async function a(){try{t(await A.logs())}catch{}}return(0,_.useEffect)(()=>{if(a(),n)return i.current=setInterval(a,2e3),()=>{i.current&&clearInterval(i.current)}},[n]),e===null?(0,j.jsx)(Gr,{}):(0,j.jsxs)(\`div\`,{className:\`flex h-full flex-col\`,children:[(0,j.jsxs)(\`div\`,{className:\`flex items-center justify-between border-b border-neutral-800 px-6 py-3\`,children:[(0,j.jsxs)(\`div\`,{children:[(0,j.jsx)(\`h1\`,{className:\`text-sm font-semibold text-neutral-300\`,children:\`Logs\`}),(0,j.jsx)(\`p\`,{className:\`text-xs text-neutral-500\`,children:\`Recent requests and server events\`})]}),(0,j.jsxs)(\`div\`,{className:\`flex items-center gap-2\`,children:[(0,j.jsx)(N,{className:n?\`\`:\`opacity-60\`,onClick:()=>r(e=>!e),title:n?\`Pause auto-refresh\`:\`Resume auto-refresh\`,children:n?\`⏸ Live\`:\`▶ Paused\`}),(0,j.jsx)(N,{onClick:a,children:\`Refresh\`}),(0,j.jsx)(N,{onClick:async()=>{await A.clearLogs(),a()},children:\`Clear\`})]})]}),(0,j.jsx)(\`div\`,{className:\`min-h-0 flex-1 overflow-auto p-3 font-mono text-[12.5px] leading-relaxed\`,children:e.length===0?(0,j.jsx)(Kr,{children:\`No logs yet. Make a request or trigger an email/webhook.\`}):e.map((e,t)=>(0,j.jsxs)(\`div\`,{className:\`flex gap-3 whitespace-pre-wrap break-words px-3 py-0.5 hover:bg-neutral-800/40\`,children:[(0,j.jsx)(\`span\`,{className:\`shrink-0 tabular-nums text-neutral-600\`,children:e.ts.slice(11,23)}),(0,j.jsx)(\`span\`,{className:\`shrink-0 uppercase \`+ui[e.level],children:e.level}),(0,j.jsx)(\`span\`,{className:\`text-neutral-300\`,children:e.msg})]},t))})]})}var fi=[{id:\`table\`,label:\`Table Editor\`,icon:he},{id:\`sql\`,label:\`SQL Editor\`,icon:D},{id:\`auth\`,label:\`Authentication\`,icon:ue},{id:\`policies\`,label:\`RLS Policies\`,icon:me},{id:\`storage\`,label:\`Storage\`,icon:le},{id:\`database\`,label:\`Database\`,icon:ce},{id:\`logs\`,label:\`Logs\`,icon:pe}];function pi({size:e=24}){return(0,j.jsxs)(\`svg\`,{width:e,height:e,viewBox:\`0 0 120 120\`,fill:\`none\`,children:[(0,j.jsxs)(\`defs\`,{children:[(0,j.jsxs)(\`linearGradient\`,{id:\`tbLogoBody\`,x1:\`30\`,y1:\`30\`,x2:\`92\`,y2:\`102\`,gradientUnits:\`userSpaceOnUse\`,children:[(0,j.jsx)(\`stop\`,{stopColor:\`#10b981\`}),(0,j.jsx)(\`stop\`,{offset:\`1\`,stopColor:\`#047857\`})]}),(0,j.jsxs)(\`linearGradient\`,{id:\`tbLogoLid\`,x1:\`26\`,y1:\`19\`,x2:\`94\`,y2:\`49\`,gradientUnits:\`userSpaceOnUse\`,children:[(0,j.jsx)(\`stop\`,{stopColor:\`#6ee7b7\`}),(0,j.jsx)(\`stop\`,{offset:\`1\`,stopColor:\`#34d399\`})]})]}),(0,j.jsx)(\`path\`,{d:\`M26 34v52c0 8.4 15.2 15.2 34 15.2s34-6.8 34-15.2V34Z\`,fill:\`url(#tbLogoBody)\`}),(0,j.jsx)(\`path\`,{d:\`M26 60c0 8.4 15.2 15.2 34 15.2S94 68.4 94 60\`,stroke:\`#6ee7b7\`,strokeWidth:\`3\`,fill:\`none\`}),(0,j.jsx)(\`ellipse\`,{cx:\`60\`,cy:\`34\`,rx:\`34\`,ry:\`15\`,fill:\`url(#tbLogoLid)\`}),(0,j.jsx)(\`ellipse\`,{cx:\`60\`,cy:\`34\`,rx:\`25\`,ry:\`10\`,fill:\`none\`,stroke:\`#059669\`,strokeOpacity:\`0.5\`,strokeWidth:\`2.5\`})]})}function mi(){let[e,t]=(0,_.useState)(!!be()),[n,r]=(0,_.useState)(\`table\`);return(0,_.useEffect)(()=>{be()&&A.ping().catch(()=>{Se(),t(!1)})},[]),e?(0,j.jsxs)(\`div\`,{className:\`flex h-full\`,children:[(0,j.jsxs)(\`nav\`,{className:\`flex w-14 shrink-0 flex-col items-center gap-1 border-r border-neutral-800 bg-[#171717] py-3\`,children:[(0,j.jsx)(\`div\`,{className:\`mb-3\`,children:(0,j.jsx)(pi,{})}),fi.map(e=>{let t=e.icon,i=n===e.id;return(0,j.jsxs)(\`button\`,{title:e.label,onClick:()=>r(e.id),className:\`group relative flex size-9 items-center justify-center rounded-md transition-colors \`+(i?\`bg-neutral-800 text-brand\`:\`text-neutral-500 hover:bg-neutral-800 hover:text-neutral-200\`),children:[(0,j.jsx)(t,{size:18}),(0,j.jsx)(\`span\`,{className:\`pointer-events-none absolute left-11 z-20 hidden whitespace-nowrap rounded-md border border-neutral-700 bg-neutral-900 px-2 py-1 text-xs text-neutral-200 group-hover:block\`,children:e.label})]},e.id)}),(0,j.jsx)(\`button\`,{title:\`Log out\`,onClick:()=>{Se(),t(!1)},className:\`mt-auto flex size-9 items-center justify-center rounded-md text-neutral-600 hover:bg-neutral-800 hover:text-neutral-300\`,children:(0,j.jsx)(oe,{size:18})})]}),(0,j.jsxs)(\`main\`,{className:\`min-w-0 flex-1\`,children:[n===\`table\`&&(0,j.jsx)(Jr,{}),n===\`sql\`&&(0,j.jsx)(Qr,{}),n===\`auth\`&&(0,j.jsx)(ei,{}),n===\`policies\`&&(0,j.jsx)(ci,{}),n===\`storage\`&&(0,j.jsx)(ri,{}),n===\`database\`&&(0,j.jsx)(oi,{}),n===\`logs\`&&(0,j.jsx)(di,{})]})]}):(0,j.jsx)(hi,{onOk:()=>t(!0)})}function hi({onOk:e}){let[t,n]=(0,_.useState)(\`\`),[r,i]=(0,_.useState)(\`\`),[a,o]=(0,_.useState)(!1);async function s(){o(!0),i(\`\`),xe(t.trim());try{await A.ping(),e()}catch(e){Se(),i(\`Invalid service_role key: \`+e.message)}finally{o(!1)}}return(0,j.jsx)(\`div\`,{className:\`flex h-full items-center justify-center\`,children:(0,j.jsxs)(\`div\`,{className:\`w-[400px] text-center\`,children:[(0,j.jsx)(\`div\`,{className:\`mb-4 flex justify-center\`,children:(0,j.jsx)(pi,{size:48})}),(0,j.jsx)(\`h1\`,{className:\`text-lg font-semibold\`,children:\`tinbase studio\`}),(0,j.jsxs)(\`p\`,{className:\`mt-1 text-[13px] text-neutral-500\`,children:[\`Sign in with the \`,(0,j.jsx)(\`span\`,{className:\`text-neutral-300\`,children:\`service_role\`}),\` key printed when tinbase started.\`]}),(0,j.jsxs)(\`div\`,{className:\`mt-5 space-y-3 text-left\`,children:[(0,j.jsx)(Vr,{type:\`password\`,placeholder:\`service_role key (eyJ…)\`,value:t,onChange:e=>n(e.target.value),onKeyDown:e=>e.key===\`Enter\`&&s()}),(0,j.jsx)(N,{className:\`w-full\`,onClick:s,disabled:a||!t.trim(),children:a?\`Checking…\`:\`Continue\`}),r&&(0,j.jsx)(\`p\`,{className:\`text-xs text-red-400\`,children:r})]})]})})}(0,v.createRoot)(document.getElementById(\`root\`)).render((0,j.jsx)(_.StrictMode,{children:(0,j.jsx)(mi,{})}));</script>
65
65
  <style rel="stylesheet" crossorigin>/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
66
66
  @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, -apple-system, sans-serif;--font-mono:ui-monospace, "SF Mono", Menlo, monospace;--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-blue-400:oklch(70.7% .165 254.624);--color-neutral-100:oklch(97% 0 0);--color-neutral-200:oklch(92.2% 0 0);--color-neutral-300:oklch(87% 0 0);--color-neutral-400:oklch(70.8% 0 0);--color-neutral-500:oklch(55.6% 0 0);--color-neutral-600:oklch(43.9% 0 0);--color-neutral-700:oklch(37.1% 0 0);--color-neutral-800:oklch(26.9% 0 0);--color-neutral-900:oklch(20.5% 0 0);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--animate-spin:spin 1s linear infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-brand:#3ecf8e}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.top-0{top:0}.top-1\\/2{top:50%}.left-1\\/2{left:50%}.left-11{left:calc(var(--spacing) * 11)}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.m-4{margin:calc(var(--spacing) * 4)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-auto{margin-top:auto}.mb-1{margin-bottom:var(--spacing)}.mb-1\\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.ml-1{margin-left:var(--spacing)}.ml-1\\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.table{display:table}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-40{height:calc(var(--spacing) * 40)}.h-full{height:100%}.max-h-\\[85vh\\]{max-height:85vh}.min-h-0{min-height:0}.w-10{width:calc(var(--spacing) * 10)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-60{width:calc(var(--spacing) * 60)}.w-\\[400px\\]{width:400px}.w-\\[440px\\]{width:440px}.w-\\[640px\\]{width:640px}.w-full{width:100%}.max-w-\\[280px\\]{max-width:280px}.max-w-\\[320px\\]{max-width:320px}.max-w-\\[360px\\]{max-width:360px}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.-translate-x-1\\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.animate-spin{animation:var(--animate-spin)}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-neutral-700{border-color:var(--color-neutral-700)}.border-neutral-800{border-color:var(--color-neutral-800)}.border-neutral-800\\/60{border-color:#26262699}@supports (color:color-mix(in lab, red, red)){.border-neutral-800\\/60{border-color:color-mix(in oklab, var(--color-neutral-800) 60%, transparent)}}.border-red-900\\/50{border-color:#82181a80}@supports (color:color-mix(in lab, red, red)){.border-red-900\\/50{border-color:color-mix(in oklab, var(--color-red-900) 50%, transparent)}}.border-red-900\\/60{border-color:#82181a99}@supports (color:color-mix(in lab, red, red)){.border-red-900\\/60{border-color:color-mix(in oklab, var(--color-red-900) 60%, transparent)}}.border-t-brand{border-top-color:var(--color-brand)}.bg-\\[\\#1c1c1c\\]{background-color:#1c1c1c}.bg-\\[\\#1f1f1f\\]{background-color:#1f1f1f}.bg-\\[\\#171717\\]{background-color:#171717}.bg-\\[\\#191919\\]{background-color:#191919}.bg-black\\/60{background-color:#0009}@supports (color:color-mix(in lab, red, red)){.bg-black\\/60{background-color:color-mix(in oklab, var(--color-black) 60%, transparent)}}.bg-emerald-600{background-color:var(--color-emerald-600)}.bg-neutral-800{background-color:var(--color-neutral-800)}.bg-neutral-900{background-color:var(--color-neutral-900)}.bg-red-950\\/30{background-color:#4608094d}@supports (color:color-mix(in lab, red, red)){.bg-red-950\\/30{background-color:color-mix(in oklab, var(--color-red-950) 30%, transparent)}}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1\\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-1{padding-top:var(--spacing)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.text-\\[12\\.5px\\]{font-size:12.5px}.text-\\[13px\\]{font-size:13px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-300\\/70{color:#ffd236b3}@supports (color:color-mix(in lab, red, red)){.text-amber-300\\/70{color:color-mix(in oklab, var(--color-amber-300) 70%, transparent)}}.text-amber-300\\/80{color:#ffd236cc}@supports (color:color-mix(in lab, red, red)){.text-amber-300\\/80{color:color-mix(in oklab, var(--color-amber-300) 80%, transparent)}}.text-amber-400{color:var(--color-amber-400)}.text-blue-400{color:var(--color-blue-400)}.text-brand{color:var(--color-brand)}.text-neutral-100{color:var(--color-neutral-100)}.text-neutral-200{color:var(--color-neutral-200)}.text-neutral-300{color:var(--color-neutral-300)}.text-neutral-400{color:var(--color-neutral-400)}.text-neutral-500{color:var(--color-neutral-500)}.text-neutral-600{color:var(--color-neutral-600)}.text-red-300{color:var(--color-red-300)}.text-red-400{color:var(--color-red-400)}.text-red-400\\/70{color:#ff6568b3}@supports (color:color-mix(in lab, red, red)){.text-red-400\\/70{color:color-mix(in oklab, var(--color-red-400) 70%, transparent)}}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.opacity-60{opacity:.6}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.group-hover\\:block:is(:where(.group):hover *){display:block}.group-hover\\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\\:text-neutral-600::placeholder{color:var(--color-neutral-600)}@media (hover:hover){.hover\\:border-neutral-600:hover{border-color:var(--color-neutral-600)}.hover\\:bg-emerald-500:hover{background-color:var(--color-emerald-500)}.hover\\:bg-neutral-800:hover{background-color:var(--color-neutral-800)}.hover\\:bg-neutral-800\\/30:hover{background-color:#2626264d}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-neutral-800\\/30:hover{background-color:color-mix(in oklab, var(--color-neutral-800) 30%, transparent)}}.hover\\:bg-neutral-800\\/40:hover{background-color:#26262666}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-neutral-800\\/40:hover{background-color:color-mix(in oklab, var(--color-neutral-800) 40%, transparent)}}.hover\\:bg-neutral-800\\/50:hover{background-color:#26262680}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-neutral-800\\/50:hover{background-color:color-mix(in oklab, var(--color-neutral-800) 50%, transparent)}}.hover\\:bg-red-950\\/40:hover{background-color:#46080966}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-red-950\\/40:hover{background-color:color-mix(in oklab, var(--color-red-950) 40%, transparent)}}.hover\\:text-brand:hover{color:var(--color-brand)}.hover\\:text-neutral-200:hover{color:var(--color-neutral-200)}.hover\\:text-neutral-300:hover{color:var(--color-neutral-300)}.hover\\:text-red-400:hover{color:var(--color-red-400)}}.focus\\:border-brand:focus{border-color:var(--color-brand)}.focus\\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:opacity-50:disabled{opacity:.5}@media (width>=40rem){.sm\\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (width>=64rem){.lg\\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}}:root{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}html,body,#root{height:100%}body{color:#ededed;-webkit-font-smoothing:antialiased;background:#1c1c1c;margin:0;font-size:13px}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:#3a3a3a;border:2px solid #1c1c1c;border-radius:6px}::-webkit-scrollbar-thumb:hover{background:#4a4a4a}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
67
67
  /*$vite$:1*/</style>
@@ -44,10 +44,35 @@ export declare class AuthHandler {
44
44
  private issueToken;
45
45
  private sendOtp;
46
46
  private sendRecovery;
47
+ /** Max wrong guesses for a one-time code before its tokens are invalidated. */
48
+ private static readonly MAX_OTP_ATTEMPTS;
47
49
  private redeem;
48
50
  private verifyToken;
49
51
  private verifyLink;
50
52
  private admin;
53
+ /**
54
+ * Append a security event to auth.audit_log_entries (GoTrue-compatible
55
+ * payload). Best-effort: a logging failure never breaks the request.
56
+ */
57
+ private audit;
58
+ /**
59
+ * Export everything held about one user across the auth schema, for a GDPR
60
+ * right-of-access / portability request. Credentials (password hash, MFA
61
+ * secrets, raw token values) are deliberately omitted — they are not personal
62
+ * data to hand back and exporting them would leak secrets.
63
+ */
64
+ private exportUser;
65
+ /**
66
+ * Erase a user (GDPR right to erasure). Deletes the user row; auth.identities,
67
+ * refresh_tokens, one_time_tokens, flow_state, and mfa_factors/challenges are
68
+ * removed by their ON DELETE CASCADE foreign keys. Returns a 404 if the user
69
+ * doesn't exist and a summary of what was erased.
70
+ *
71
+ * Note: storage.objects.owner has no FK to auth.users, so object rows/bytes
72
+ * owned by the user are not removed here — see COMPLIANCE.md for the
73
+ * storage-erasure step the operator must run.
74
+ */
75
+ private eraseUser;
51
76
  private enrollFactor;
52
77
  private challengeFactor;
53
78
  private verifyFactor;
@@ -73,7 +73,7 @@ export class AuthHandler {
73
73
  if (path === 'callback' && (method === 'GET' || method === 'POST')) {
74
74
  return await this.oauth.callback(url, (userId) => this.sessionTokensFor(userId));
75
75
  }
76
- if (path.startsWith('admin/users'))
76
+ if (path.startsWith('admin/'))
77
77
  return await this.admin(req, ctx, path, method);
78
78
  return authError(404, 'not_found', `unknown auth endpoint: ${path}`);
79
79
  }
@@ -110,7 +110,9 @@ export class AuthHandler {
110
110
  values ('authenticated', 'authenticated', $1, $2, now(), now(),
111
111
  '{"provider":"email","providers":["email"]}', $3)
112
112
  returning *`, [email, hashed, JSON.stringify(body.data ?? {})]);
113
- return json(200, await this.sessionFor(res.rows[0]));
113
+ const newUser = res.rows[0];
114
+ await this.audit('user_signedup', { actorId: newUser.id, actorEmail: email });
115
+ return json(200, await this.sessionFor(newUser));
114
116
  }
115
117
  async token(req, url) {
116
118
  const grantType = url.searchParams.get('grant_type');
@@ -120,9 +122,11 @@ export class AuthHandler {
120
122
  const res = await this.db.query(`select * from auth.users where email = $1`, [email]);
121
123
  const user = res.rows[0];
122
124
  if (!user || !user.encrypted_password || !(await verifyPassword(body.password ?? '', user.encrypted_password))) {
125
+ await this.audit('login_failed', { actorEmail: email, traits: { grant_type: 'password' } });
123
126
  return authError(400, 'invalid_credentials', 'Invalid login credentials');
124
127
  }
125
128
  await this.db.query(`update auth.users set last_sign_in_at = now() where id = $1`, [user.id]);
129
+ await this.audit('login', { actorId: user.id, actorEmail: user.email, traits: { grant_type: 'password' } });
126
130
  return json(200, await this.sessionFor(user));
127
131
  }
128
132
  if (grantType === 'refresh_token') {
@@ -211,6 +215,7 @@ export class AuthHandler {
211
215
  const user = await this.userFromBearer(req);
212
216
  if (user) {
213
217
  await this.db.query(`update auth.refresh_tokens set revoked = true where user_id = $1`, [user.id]);
218
+ await this.audit('logout', { actorId: user.id, actorEmail: user.email });
214
219
  }
215
220
  return new Response(null, { status: 204 });
216
221
  }
@@ -255,14 +260,27 @@ export class AuthHandler {
255
260
  return authError(400, 'validation_failed', 'email is required');
256
261
  return this.issueToken(body.email, 'recovery', false);
257
262
  }
263
+ /** Max wrong guesses for a one-time code before its tokens are invalidated. */
264
+ static MAX_OTP_ATTEMPTS = 5;
258
265
  async redeem(token, types, email) {
266
+ const normalizedEmail = email?.toLowerCase().trim() ?? null;
259
267
  const res = await this.db.query(`delete from auth.one_time_tokens
260
268
  where token = $1 and token_type = any($2::text[])
261
269
  and ($3::text is null or email = $3) and expires_at > now()
262
- returning user_id, email`, [token, `{${types.join(',')}}`, email?.toLowerCase().trim() ?? null]);
270
+ and attempts < $4
271
+ returning user_id, email`, [token, `{${types.join(',')}}`, normalizedEmail, AuthHandler.MAX_OTP_ATTEMPTS]);
263
272
  const row = res.rows[0];
264
- if (!row)
273
+ if (!row) {
274
+ // Wrong/expired code: count the failed guess against the live tokens for
275
+ // this email, and burn them once the attempt cap is hit (brute-force
276
+ // lockout for the 6-digit OTP). Requires the email to scope the counter.
277
+ if (normalizedEmail) {
278
+ await this.db.query(`update auth.one_time_tokens set attempts = attempts + 1
279
+ where email = $1 and token_type = any($2::text[]) and expires_at > now()`, [normalizedEmail, `{${types.join(',')}}`]);
280
+ await this.db.query(`delete from auth.one_time_tokens where email = $1 and attempts >= $2`, [normalizedEmail, AuthHandler.MAX_OTP_ATTEMPTS]);
281
+ }
265
282
  return null;
283
+ }
266
284
  await this.db.query(`delete from auth.one_time_tokens where email = $1`, [row.email]);
267
285
  const ures = await this.db.query(`update auth.users set email_confirmed_at = coalesce(email_confirmed_at, now()), last_sign_in_at = now()
268
286
  where id = $1 returning *`, [row.user_id]);
@@ -272,7 +290,10 @@ export class AuthHandler {
272
290
  const body = (await req.json().catch(() => ({})));
273
291
  if (!body.token)
274
292
  return authError(400, 'validation_failed', 'token is required');
275
- const types = body.type === 'recovery' ? ['recovery'] : body.type === 'magiclink' ? ['magiclink'] : ['otp', 'magiclink', 'recovery'];
293
+ // A recovery (password-reset) token must be redeemed with type=recovery
294
+ // explicitly — never fold it into the default set, or a guessed login OTP
295
+ // could mint a recovery session.
296
+ const types = body.type === 'recovery' ? ['recovery'] : body.type === 'magiclink' ? ['magiclink'] : ['otp', 'magiclink'];
276
297
  const user = await this.redeem(body.token, types, body.email);
277
298
  if (!user)
278
299
  return authError(403, 'otp_expired', 'Token has expired or is invalid');
@@ -296,6 +317,15 @@ export class AuthHandler {
296
317
  return authError(403, 'insufficient_permissions', 'Admin endpoints require the service_role key');
297
318
  }
298
319
  const idMatch = path.match(/^admin\/users\/([0-9a-f-]{36})$/);
320
+ const exportMatch = path.match(/^admin\/users\/([0-9a-f-]{36})\/export$/);
321
+ if (path === 'admin/audit' && method === 'GET') {
322
+ const res = await this.db.query(`select id, payload, created_at, ip_address from auth.audit_log_entries
323
+ order by created_at desc limit 200`);
324
+ return json(200, { entries: res.rows });
325
+ }
326
+ if (exportMatch && method === 'GET') {
327
+ return await this.exportUser(exportMatch[1]);
328
+ }
299
329
  if (path === 'admin/users' && method === 'GET') {
300
330
  const res = await this.db.query(`select * from auth.users order by created_at desc limit 1000`);
301
331
  return json(200, { users: res.rows.map((u) => this.userJson(u)), aud: 'authenticated' });
@@ -354,11 +384,96 @@ export class AuthHandler {
354
384
  return json(200, this.userJson(res.rows[0]));
355
385
  }
356
386
  if (idMatch && method === 'DELETE') {
357
- await this.db.query(`delete from auth.users where id = $1`, [idMatch[1]]);
358
- return json(200, {});
387
+ return await this.eraseUser(idMatch[1]);
359
388
  }
360
389
  return authError(404, 'not_found', `unknown admin endpoint`);
361
390
  }
391
+ // ── audit trail ───────────────────────────────────────────────────────
392
+ /**
393
+ * Append a security event to auth.audit_log_entries (GoTrue-compatible
394
+ * payload). Best-effort: a logging failure never breaks the request.
395
+ */
396
+ async audit(action, opts = {}) {
397
+ try {
398
+ const payload = {
399
+ action,
400
+ actor_id: opts.actorId ?? null,
401
+ actor_username: opts.actorEmail ?? null,
402
+ log_type: opts.type ?? 'account',
403
+ traits: opts.traits ?? {},
404
+ timestamp: new Date().toISOString(),
405
+ };
406
+ await this.db.query(`insert into auth.audit_log_entries (payload) values ($1::jsonb)`, [JSON.stringify(payload)]);
407
+ }
408
+ catch {
409
+ // audit logging is best-effort
410
+ }
411
+ }
412
+ // ── GDPR: data-subject access (export) ────────────────────────────────
413
+ /**
414
+ * Export everything held about one user across the auth schema, for a GDPR
415
+ * right-of-access / portability request. Credentials (password hash, MFA
416
+ * secrets, raw token values) are deliberately omitted — they are not personal
417
+ * data to hand back and exporting them would leak secrets.
418
+ */
419
+ async exportUser(userId) {
420
+ const ures = await this.db.query(`select * from auth.users where id = $1`, [userId]);
421
+ if (ures.rows.length === 0)
422
+ return authError(404, 'user_not_found', 'User not found');
423
+ const user = ures.rows[0];
424
+ const identities = await this.db.query(`select id, provider, provider_id, identity_data, last_sign_in_at, created_at, updated_at
425
+ from auth.identities where user_id = $1`, [userId]);
426
+ const sessions = await this.db.query(`select id, parent, session_id, revoked, created_at, updated_at
427
+ from auth.refresh_tokens where user_id = $1`, [userId]);
428
+ const factors = await this.db.query(`select id, friendly_name, factor_type, status, created_at, updated_at
429
+ from auth.mfa_factors where user_id = $1`, [userId]);
430
+ // strip credential/token columns from the raw record before returning it
431
+ const SENSITIVE = [
432
+ 'encrypted_password',
433
+ 'confirmation_token',
434
+ 'recovery_token',
435
+ 'email_change_token_new',
436
+ 'email_change_token_current',
437
+ 'phone_change_token',
438
+ 'reauthentication_token',
439
+ ];
440
+ const userSafe = Object.fromEntries(Object.entries(user).filter(([k]) => !SENSITIVE.includes(k)));
441
+ await this.audit('user_data_exported', { actorId: userId, type: 'admin' });
442
+ return json(200, {
443
+ exported_at: new Date().toISOString(),
444
+ user: this.userJson(user),
445
+ user_record: userSafe,
446
+ identities: identities.rows,
447
+ sessions: sessions.rows,
448
+ mfa_factors: factors.rows,
449
+ });
450
+ }
451
+ /**
452
+ * Erase a user (GDPR right to erasure). Deletes the user row; auth.identities,
453
+ * refresh_tokens, one_time_tokens, flow_state, and mfa_factors/challenges are
454
+ * removed by their ON DELETE CASCADE foreign keys. Returns a 404 if the user
455
+ * doesn't exist and a summary of what was erased.
456
+ *
457
+ * Note: storage.objects.owner has no FK to auth.users, so object rows/bytes
458
+ * owned by the user are not removed here — see COMPLIANCE.md for the
459
+ * storage-erasure step the operator must run.
460
+ */
461
+ async eraseUser(userId) {
462
+ const before = await this.db.query(`select
463
+ (select count(*) from auth.identities where user_id = $1)::int as identities,
464
+ (select count(*) from auth.refresh_tokens where user_id = $1)::int as sessions,
465
+ (select count(*) from auth.mfa_factors where user_id = $1)::int as factors`, [userId]);
466
+ const del = await this.db.query(`delete from auth.users where id = $1 returning id`, [userId]);
467
+ if (del.rows.length === 0)
468
+ return authError(404, 'user_not_found', 'User not found');
469
+ const c = before.rows[0];
470
+ await this.audit('user_deleted', { actorId: userId, type: 'admin', traits: { erased: true } });
471
+ return json(200, {
472
+ erased: true,
473
+ user_id: userId,
474
+ cascaded: { identities: c.identities, sessions: c.sessions, mfa_factors: c.factors },
475
+ });
476
+ }
362
477
  // ── MFA (TOTP) ────────────────────────────────────────────────────────
363
478
  async enrollFactor(req) {
364
479
  const user = await this.userFromBearer(req);
@@ -423,13 +538,17 @@ export class AuthHandler {
423
538
  const factor = fr.rows[0];
424
539
  if (!factor)
425
540
  return authError(404, 'mfa_factor_not_found', 'MFA factor not found');
426
- const cr = await this.db.query(`select id, expires_at from auth.mfa_challenges where id = $1 and factor_id = $2`, [body.challenge_id ?? '', factorId]);
541
+ const cr = await this.db.query(`select id, expires_at, verified_at from auth.mfa_challenges where id = $1 and factor_id = $2`, [body.challenge_id ?? '', factorId]);
427
542
  const challenge = cr.rows[0];
428
543
  if (!challenge)
429
544
  return authError(404, 'mfa_challenge_not_found', 'MFA challenge not found');
430
545
  if (new Date(challenge.expires_at).getTime() < Date.now()) {
431
546
  return authError(422, 'mfa_challenge_expired', 'MFA challenge has expired, verify against another one');
432
547
  }
548
+ // a challenge is single-use: once verified it cannot be replayed
549
+ if (challenge.verified_at) {
550
+ return authError(422, 'mfa_verification_failed', 'This challenge has already been verified');
551
+ }
433
552
  if (!(await verifyTotp(factor.secret, body.code ?? ''))) {
434
553
  return authError(422, 'mfa_verification_failed', 'Invalid TOTP code entered');
435
554
  }