@openparachute/vault 0.6.5 → 0.7.0-rc.2

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.
@@ -58,4 +58,4 @@ Error generating stack: `+l.message+`
58
58
  */var Hh="popstate";function Bh(u){return typeof u=="object"&&u!=null&&"pathname"in u&&"search"in u&&"hash"in u&&"state"in u&&"key"in u}function py(u={}){function c(r,d){var p;let h=(p=d.state)==null?void 0:p.masked,{pathname:g,search:S,hash:x}=h||r.location;return ir("",{pathname:g,search:S,hash:x},d.state&&d.state.usr||null,d.state&&d.state.key||"default",h?{pathname:r.location.pathname,search:r.location.search,hash:r.location.hash}:void 0)}function o(r,d){return typeof d=="string"?d:Qa(d)}return yy(c,o,null,u)}function Me(u,c){if(u===!1||u===null||typeof u>"u")throw new Error(c)}function Vt(u,c){if(!u){typeof console<"u"&&console.warn(c);try{throw new Error(c)}catch{}}}function gy(){return Math.random().toString(36).substring(2,10)}function Lh(u,c){return{usr:u.state,key:u.key,idx:c,masked:u.unstable_mask?{pathname:u.pathname,search:u.search,hash:u.hash}:void 0}}function ir(u,c,o=null,r,d){return{pathname:typeof u=="string"?u:u.pathname,search:"",hash:"",...typeof c=="string"?Xl(c):c,state:o,key:c&&c.key||r||gy(),unstable_mask:d}}function Qa({pathname:u="/",search:c="",hash:o=""}){return c&&c!=="?"&&(u+=c.charAt(0)==="?"?c:"?"+c),o&&o!=="#"&&(u+=o.charAt(0)==="#"?o:"#"+o),u}function Xl(u){let c={};if(u){let o=u.indexOf("#");o>=0&&(c.hash=u.substring(o),u=u.substring(0,o));let r=u.indexOf("?");r>=0&&(c.search=u.substring(r),u=u.substring(0,r)),u&&(c.pathname=u)}return c}function yy(u,c,o,r={}){let{window:d=document.defaultView,v5Compat:h=!1}=r,g=d.history,S="POP",x=null,p=E();p==null&&(p=0,g.replaceState({...g.state,idx:p},""));function E(){return(g.state||{idx:null}).idx}function v(){S="POP";let H=E(),q=H==null?null:H-p;p=H,x&&x({action:S,location:k.location,delta:q})}function C(H,q){S="PUSH";let F=Bh(H)?H:ir(k.location,H,q);p=E()+1;let B=Lh(F,p),z=k.createHref(F.unstable_mask||F);try{g.pushState(B,"",z)}catch(Z){if(Z instanceof DOMException&&Z.name==="DataCloneError")throw Z;d.location.assign(z)}h&&x&&x({action:S,location:k.location,delta:1})}function V(H,q){S="REPLACE";let F=Bh(H)?H:ir(k.location,H,q);p=E();let B=Lh(F,p),z=k.createHref(F.unstable_mask||F);g.replaceState(B,"",z),h&&x&&x({action:S,location:k.location,delta:0})}function D(H){return vy(H)}let k={get action(){return S},get location(){return u(d,g)},listen(H){if(x)throw new Error("A history only accepts one active listener");return d.addEventListener(Hh,v),x=H,()=>{d.removeEventListener(Hh,v),x=null}},createHref(H){return c(d,H)},createURL:D,encodeLocation(H){let q=D(H);return{pathname:q.pathname,search:q.search,hash:q.hash}},push:C,replace:V,go(H){return g.go(H)}};return k}function vy(u,c=!1){let o="http://localhost";typeof window<"u"&&(o=window.location.origin!=="null"?window.location.origin:window.location.href),Me(o,"No window.location.(origin|href) available to create URL");let r=typeof u=="string"?u:Qa(u);return r=r.replace(/ $/,"%20"),!c&&r.startsWith("//")&&(r=o+r),new URL(r,o)}function nm(u,c,o="/"){return xy(u,c,o,!1)}function xy(u,c,o,r){let d=typeof c=="string"?Xl(c):c,h=fn(d.pathname||"/",o);if(h==null)return null;let g=lm(u);by(g);let S=null;for(let x=0;S==null&&x<g.length;++x){let p=ky(h);S=Ay(g[x],p,r)}return S}function lm(u,c=[],o=[],r="",d=!1){let h=(g,S,x=d,p)=>{let E={relativePath:p===void 0?g.path||"":p,caseSensitive:g.caseSensitive===!0,childrenIndex:S,route:g};if(E.relativePath.startsWith("/")){if(!E.relativePath.startsWith(r)&&x)return;Me(E.relativePath.startsWith(r),`Absolute route path "${E.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),E.relativePath=E.relativePath.slice(r.length)}let v=Ht([r,E.relativePath]),C=o.concat(E);g.children&&g.children.length>0&&(Me(g.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${v}".`),lm(g.children,c,C,v,x)),!(g.path==null&&!g.index)&&c.push({path:v,score:wy(v,g.index),routesMeta:C})};return u.forEach((g,S)=>{var x;if(g.path===""||!((x=g.path)!=null&&x.includes("?")))h(g,S);else for(let p of am(g.path))h(g,S,!0,p)}),c}function am(u){let c=u.split("/");if(c.length===0)return[];let[o,...r]=c,d=o.endsWith("?"),h=o.replace(/\?$/,"");if(r.length===0)return d?[h,""]:[h];let g=am(r.join("/")),S=[];return S.push(...g.map(x=>x===""?h:[h,x].join("/"))),d&&S.push(...g),S.map(x=>u.startsWith("/")&&x===""?"/":x)}function by(u){u.sort((c,o)=>c.score!==o.score?o.score-c.score:Cy(c.routesMeta.map(r=>r.childrenIndex),o.routesMeta.map(r=>r.childrenIndex)))}var jy=/^:[\w-]+$/,Sy=3,Ey=2,Ty=1,_y=10,Ny=-2,qh=u=>u==="*";function wy(u,c){let o=u.split("/"),r=o.length;return o.some(qh)&&(r+=Ny),c&&(r+=Ey),o.filter(d=>!qh(d)).reduce((d,h)=>d+(jy.test(h)?Sy:h===""?Ty:_y),r)}function Cy(u,c){return u.length===c.length&&u.slice(0,-1).every((r,d)=>r===c[d])?u[u.length-1]-c[c.length-1]:0}function Ay(u,c,o=!1){let{routesMeta:r}=u,d={},h="/",g=[];for(let S=0;S<r.length;++S){let x=r[S],p=S===r.length-1,E=h==="/"?c:c.slice(h.length)||"/",v=ju({path:x.relativePath,caseSensitive:x.caseSensitive,end:p},E),C=x.route;if(!v&&p&&o&&!r[r.length-1].route.index&&(v=ju({path:x.relativePath,caseSensitive:x.caseSensitive,end:!1},E)),!v)return null;Object.assign(d,v.params),g.push({params:d,pathname:Ht([h,v.pathname]),pathnameBase:Dy(Ht([h,v.pathnameBase])),route:C}),v.pathnameBase!=="/"&&(h=Ht([h,v.pathnameBase]))}return g}function ju(u,c){typeof u=="string"&&(u={path:u,caseSensitive:!1,end:!0});let[o,r]=Ry(u.path,u.caseSensitive,u.end),d=c.match(o);if(!d)return null;let h=d[0],g=h.replace(/(.)\/+$/,"$1"),S=d.slice(1);return{params:r.reduce((p,{paramName:E,isOptional:v},C)=>{if(E==="*"){let D=S[C]||"";g=h.slice(0,h.length-D.length).replace(/(.)\/+$/,"$1")}const V=S[C];return v&&!V?p[E]=void 0:p[E]=(V||"").replace(/%2F/g,"/"),p},{}),pathname:h,pathnameBase:g,pattern:u}}function Ry(u,c=!1,o=!0){Vt(u==="*"||!u.endsWith("*")||u.endsWith("/*"),`Route path "${u}" will be treated as if it were "${u.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${u.replace(/\*$/,"/*")}".`);let r=[],d="^"+u.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(g,S,x,p,E)=>{if(r.push({paramName:S,isOptional:x!=null}),x){let v=E.charAt(p+g.length);return v&&v!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return u.endsWith("*")?(r.push({paramName:"*"}),d+=u==="*"||u==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):o?d+="\\/*$":u!==""&&u!=="/"&&(d+="(?:(?=\\/|$))"),[new RegExp(d,c?void 0:"i"),r]}function ky(u){try{return u.split("/").map(c=>decodeURIComponent(c).replace(/\//g,"%2F")).join("/")}catch(c){return Vt(!1,`The URL path "${u}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${c}).`),u}}function fn(u,c){if(c==="/")return u;if(!u.toLowerCase().startsWith(c.toLowerCase()))return null;let o=c.endsWith("/")?c.length-1:c.length,r=u.charAt(o);return r&&r!=="/"?null:u.slice(o)||"/"}var zy=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function My(u,c="/"){let{pathname:o,search:r="",hash:d=""}=typeof u=="string"?Xl(u):u,h;return o?(o=um(o),o.startsWith("/")?h=Gh(o.substring(1),"/"):h=Gh(o,c)):h=c,{pathname:h,search:Uy(r),hash:Hy(d)}}function Gh(u,c){let o=Su(c).split("/");return u.split("/").forEach(d=>{d===".."?o.length>1&&o.pop():d!=="."&&o.push(d)}),o.length>1?o.join("/"):"/"}function Pc(u,c,o,r){return`Cannot include a '${u}' character in a manually specified \`to.${c}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${o}\` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.`}function Oy(u){return u.filter((c,o)=>o===0||c.route.path&&c.route.path.length>0)}function im(u){let c=Oy(u);return c.map((o,r)=>r===c.length-1?o.pathname:o.pathnameBase)}function fr(u,c,o,r=!1){let d;typeof u=="string"?d=Xl(u):(d={...u},Me(!d.pathname||!d.pathname.includes("?"),Pc("?","pathname","search",d)),Me(!d.pathname||!d.pathname.includes("#"),Pc("#","pathname","hash",d)),Me(!d.search||!d.search.includes("#"),Pc("#","search","hash",d)));let h=u===""||d.pathname==="",g=h?"/":d.pathname,S;if(g==null)S=o;else{let v=c.length-1;if(!r&&g.startsWith("..")){let C=g.split("/");for(;C[0]==="..";)C.shift(),v-=1;d.pathname=C.join("/")}S=v>=0?c[v]:"/"}let x=My(d,S),p=g&&g!=="/"&&g.endsWith("/"),E=(h||g===".")&&o.endsWith("/");return!x.pathname.endsWith("/")&&(p||E)&&(x.pathname+="/"),x}var um=u=>u.replace(/\/\/+/g,"/"),Ht=u=>um(u.join("/")),Su=u=>u.replace(/\/+$/,""),Dy=u=>Su(u).replace(/^\/*/,"/"),Uy=u=>!u||u==="?"?"":u.startsWith("?")?u:"?"+u,Hy=u=>!u||u==="#"?"":u.startsWith("#")?u:"#"+u,By=class{constructor(u,c,o,r=!1){this.status=u,this.statusText=c||"",this.internal=r,o instanceof Error?(this.data=o.toString(),this.error=o):this.data=o}};function Ly(u){return u!=null&&typeof u.status=="number"&&typeof u.statusText=="string"&&typeof u.internal=="boolean"&&"data"in u}function qy(u){let c=u.map(o=>o.route.path).filter(Boolean);return Ht(c)||"/"}var sm=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function cm(u,c){let o=u;if(typeof o!="string"||!zy.test(o))return{absoluteURL:void 0,isExternal:!1,to:o};let r=o,d=!1;if(sm)try{let h=new URL(window.location.href),g=o.startsWith("//")?new URL(h.protocol+o):new URL(o),S=fn(g.pathname,c);g.origin===h.origin&&S!=null?o=S+g.search+g.hash:d=!0}catch{Vt(!1,`<Link to="${o}"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:d,to:o}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var rm=["POST","PUT","PATCH","DELETE"];new Set(rm);var Gy=["GET",...rm];new Set(Gy);var Ql=y.createContext(null);Ql.displayName="DataRouter";var Tu=y.createContext(null);Tu.displayName="DataRouterState";var om=y.createContext(!1);function Yy(){return y.useContext(om)}var fm=y.createContext({isTransitioning:!1});fm.displayName="ViewTransition";var Vy=y.createContext(new Map);Vy.displayName="Fetchers";var Xy=y.createContext(null);Xy.displayName="Await";var Mt=y.createContext(null);Mt.displayName="Navigation";var Ja=y.createContext(null);Ja.displayName="Location";var Xt=y.createContext({outlet:null,matches:[],isDataRoute:!1});Xt.displayName="Route";var dr=y.createContext(null);dr.displayName="RouteError";var dm="REACT_ROUTER_ERROR",Qy="REDIRECT",Zy="ROUTE_ERROR_RESPONSE";function Ky(u){if(u.startsWith(`${dm}:${Qy}:{`))try{let c=JSON.parse(u.slice(28));if(typeof c=="object"&&c&&typeof c.status=="number"&&typeof c.statusText=="string"&&typeof c.location=="string"&&typeof c.reloadDocument=="boolean"&&typeof c.replace=="boolean")return c}catch{}}function Jy(u){if(u.startsWith(`${dm}:${Zy}:{`))try{let c=JSON.parse(u.slice(40));if(typeof c=="object"&&c&&typeof c.status=="number"&&typeof c.statusText=="string")return new By(c.status,c.statusText,c.data)}catch{}}function $y(u,{relative:c}={}){Me($a(),"useHref() may be used only in the context of a <Router> component.");let{basename:o,navigator:r}=y.useContext(Mt),{hash:d,pathname:h,search:g}=Fa(u,{relative:c}),S=h;return o!=="/"&&(S=h==="/"?o:Ht([o,h])),r.createHref({pathname:S,search:g,hash:d})}function $a(){return y.useContext(Ja)!=null}function dn(){return Me($a(),"useLocation() may be used only in the context of a <Router> component."),y.useContext(Ja).location}var hm="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function mm(u){y.useContext(Mt).static||y.useLayoutEffect(u)}function Fy(){let{isDataRoute:u}=y.useContext(Xt);return u?rv():Wy()}function Wy(){Me($a(),"useNavigate() may be used only in the context of a <Router> component.");let u=y.useContext(Ql),{basename:c,navigator:o}=y.useContext(Mt),{matches:r}=y.useContext(Xt),{pathname:d}=dn(),h=JSON.stringify(im(r)),g=y.useRef(!1);return mm(()=>{g.current=!0}),y.useCallback((x,p={})=>{if(Vt(g.current,hm),!g.current)return;if(typeof x=="number"){o.go(x);return}let E=fr(x,JSON.parse(h),d,p.relative==="path");u==null&&c!=="/"&&(E.pathname=E.pathname==="/"?c:Ht([c,E.pathname])),(p.replace?o.replace:o.push)(E,p.state,p)},[c,o,h,d,u])}y.createContext(null);function _u(){let{matches:u}=y.useContext(Xt),c=u[u.length-1];return(c==null?void 0:c.params)??{}}function Fa(u,{relative:c}={}){let{matches:o}=y.useContext(Xt),{pathname:r}=dn(),d=JSON.stringify(im(o));return y.useMemo(()=>fr(u,JSON.parse(d),r,c==="path"),[u,d,r,c])}function Iy(u,c){return pm(u,c)}function pm(u,c,o){var H;Me($a(),"useRoutes() may be used only in the context of a <Router> component.");let{navigator:r}=y.useContext(Mt),{matches:d}=y.useContext(Xt),h=d[d.length-1],g=h?h.params:{},S=h?h.pathname:"/",x=h?h.pathnameBase:"/",p=h&&h.route;{let q=p&&p.path||"";ym(S,!p||q.endsWith("*")||q.endsWith("*?"),`You rendered descendant <Routes> (or called \`useRoutes()\`) at "${S}" (under <Route path="${q}">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.
59
59
 
60
60
  Please change the parent <Route path="${q}"> to <Route path="${q==="/"?"*":`${q}/*`}">.`)}let E=dn(),v;if(c){let q=typeof c=="string"?Xl(c):c;Me(x==="/"||((H=q.pathname)==null?void 0:H.startsWith(x)),`When overriding the location using \`<Routes location>\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${x}" but pathname "${q.pathname}" was given in the \`location\` prop.`),v=q}else v=E;let C=v.pathname||"/",V=C;if(x!=="/"){let q=x.replace(/^\//,"").split("/");V="/"+C.replace(/^\//,"").split("/").slice(q.length).join("/")}let D=nm(u,{pathname:V});Vt(p||D!=null,`No routes matched location "${v.pathname}${v.search}${v.hash}" `),Vt(D==null||D[D.length-1].route.element!==void 0||D[D.length-1].route.Component!==void 0||D[D.length-1].route.lazy!==void 0,`Matched leaf route at location "${v.pathname}${v.search}${v.hash}" does not have an element or Component. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.`);let k=lv(D&&D.map(q=>Object.assign({},q,{params:Object.assign({},g,q.params),pathname:Ht([x,r.encodeLocation?r.encodeLocation(q.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:q.pathname]),pathnameBase:q.pathnameBase==="/"?x:Ht([x,r.encodeLocation?r.encodeLocation(q.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:q.pathnameBase])})),d,o);return c&&k?y.createElement(Ja.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",unstable_mask:void 0,...v},navigationType:"POP"}},k):k}function Py(){let u=cv(),c=Ly(u)?`${u.status} ${u.statusText}`:u instanceof Error?u.message:JSON.stringify(u),o=u instanceof Error?u.stack:null,r="rgba(200,200,200, 0.5)",d={padding:"0.5rem",backgroundColor:r},h={padding:"2px 4px",backgroundColor:r},g=null;return console.error("Error handled by React Router default ErrorBoundary:",u),g=y.createElement(y.Fragment,null,y.createElement("p",null,"💿 Hey developer 👋"),y.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",y.createElement("code",{style:h},"ErrorBoundary")," or"," ",y.createElement("code",{style:h},"errorElement")," prop on your route.")),y.createElement(y.Fragment,null,y.createElement("h2",null,"Unexpected Application Error!"),y.createElement("h3",{style:{fontStyle:"italic"}},c),o?y.createElement("pre",{style:d},o):null,g)}var ev=y.createElement(Py,null),gm=class extends y.Component{constructor(u){super(u),this.state={location:u.location,revalidation:u.revalidation,error:u.error}}static getDerivedStateFromError(u){return{error:u}}static getDerivedStateFromProps(u,c){return c.location!==u.location||c.revalidation!=="idle"&&u.revalidation==="idle"?{error:u.error,location:u.location,revalidation:u.revalidation}:{error:u.error!==void 0?u.error:c.error,location:c.location,revalidation:u.revalidation||c.revalidation}}componentDidCatch(u,c){this.props.onError?this.props.onError(u,c):console.error("React Router caught the following error during render",u)}render(){let u=this.state.error;if(this.context&&typeof u=="object"&&u&&"digest"in u&&typeof u.digest=="string"){const o=Jy(u.digest);o&&(u=o)}let c=u!==void 0?y.createElement(Xt.Provider,{value:this.props.routeContext},y.createElement(dr.Provider,{value:u,children:this.props.component})):this.props.children;return this.context?y.createElement(tv,{error:u},c):c}};gm.contextType=om;var er=new WeakMap;function tv({children:u,error:c}){let{basename:o}=y.useContext(Mt);if(typeof c=="object"&&c&&"digest"in c&&typeof c.digest=="string"){let r=Ky(c.digest);if(r){let d=er.get(c);if(d)throw d;let h=cm(r.location,o);if(sm&&!er.get(c))if(h.isExternal||r.reloadDocument)window.location.href=h.absoluteURL||h.to;else{const g=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(h.to,{replace:r.replace}));throw er.set(c,g),g}return y.createElement("meta",{httpEquiv:"refresh",content:`0;url=${h.absoluteURL||h.to}`})}}return u}function nv({routeContext:u,match:c,children:o}){let r=y.useContext(Ql);return r&&r.static&&r.staticContext&&(c.route.errorElement||c.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=c.route.id),y.createElement(Xt.Provider,{value:u},o)}function lv(u,c=[],o){let r=o==null?void 0:o.state;if(u==null){if(!r)return null;if(r.errors)u=r.matches;else if(c.length===0&&!r.initialized&&r.matches.length>0)u=r.matches;else return null}let d=u,h=r==null?void 0:r.errors;if(h!=null){let E=d.findIndex(v=>v.route.id&&(h==null?void 0:h[v.route.id])!==void 0);Me(E>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(h).join(",")}`),d=d.slice(0,Math.min(d.length,E+1))}let g=!1,S=-1;if(o&&r){g=r.renderFallback;for(let E=0;E<d.length;E++){let v=d[E];if((v.route.HydrateFallback||v.route.hydrateFallbackElement)&&(S=E),v.route.id){let{loaderData:C,errors:V}=r,D=v.route.loader&&!C.hasOwnProperty(v.route.id)&&(!V||V[v.route.id]===void 0);if(v.route.lazy||D){o.isStatic&&(g=!0),S>=0?d=d.slice(0,S+1):d=[d[0]];break}}}}let x=o==null?void 0:o.onError,p=r&&x?(E,v)=>{var C,V;x(E,{location:r.location,params:((V=(C=r.matches)==null?void 0:C[0])==null?void 0:V.params)??{},unstable_pattern:qy(r.matches),errorInfo:v})}:void 0;return d.reduceRight((E,v,C)=>{let V,D=!1,k=null,H=null;r&&(V=h&&v.route.id?h[v.route.id]:void 0,k=v.route.errorElement||ev,g&&(S<0&&C===0?(ym("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),D=!0,H=null):S===C&&(D=!0,H=v.route.hydrateFallbackElement||null)));let q=c.concat(d.slice(0,C+1)),F=()=>{let B;return V?B=k:D?B=H:v.route.Component?B=y.createElement(v.route.Component,null):v.route.element?B=v.route.element:B=E,y.createElement(nv,{match:v,routeContext:{outlet:E,matches:q,isDataRoute:r!=null},children:B})};return r&&(v.route.ErrorBoundary||v.route.errorElement||C===0)?y.createElement(gm,{location:r.location,revalidation:r.revalidation,component:k,error:V,children:F(),routeContext:{outlet:null,matches:q,isDataRoute:!0},onError:p}):F()},null)}function hr(u){return`${u} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function av(u){let c=y.useContext(Ql);return Me(c,hr(u)),c}function iv(u){let c=y.useContext(Tu);return Me(c,hr(u)),c}function uv(u){let c=y.useContext(Xt);return Me(c,hr(u)),c}function mr(u){let c=uv(u),o=c.matches[c.matches.length-1];return Me(o.route.id,`${u} can only be used on routes that contain a unique "id"`),o.route.id}function sv(){return mr("useRouteId")}function cv(){var r;let u=y.useContext(dr),c=iv("useRouteError"),o=mr("useRouteError");return u!==void 0?u:(r=c.errors)==null?void 0:r[o]}function rv(){let{router:u}=av("useNavigate"),c=mr("useNavigate"),o=y.useRef(!1);return mm(()=>{o.current=!0}),y.useCallback(async(d,h={})=>{Vt(o.current,hm),o.current&&(typeof d=="number"?await u.navigate(d):await u.navigate(d,{fromRouteId:c,...h}))},[u,c])}var Yh={};function ym(u,c,o){!c&&!Yh[u]&&(Yh[u]=!0,Vt(!1,o))}y.memo(ov);function ov({routes:u,future:c,state:o,isStatic:r,onError:d}){return pm(u,void 0,{state:o,isStatic:r,onError:d})}function ft(u){Me(!1,"A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.")}function fv({basename:u="/",children:c=null,location:o,navigationType:r="POP",navigator:d,static:h=!1,unstable_useTransitions:g}){Me(!$a(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let S=u.replace(/^\/*/,"/"),x=y.useMemo(()=>({basename:S,navigator:d,static:h,unstable_useTransitions:g,future:{}}),[S,d,h,g]);typeof o=="string"&&(o=Xl(o));let{pathname:p="/",search:E="",hash:v="",state:C=null,key:V="default",unstable_mask:D}=o,k=y.useMemo(()=>{let H=fn(p,S);return H==null?null:{location:{pathname:H,search:E,hash:v,state:C,key:V,unstable_mask:D},navigationType:r}},[S,p,E,v,C,V,r,D]);return Vt(k!=null,`<Router basename="${S}"> is not able to match the URL "${p}${E}${v}" because it does not start with the basename, so the <Router> won't render anything.`),k==null?null:y.createElement(Mt.Provider,{value:x},y.createElement(Ja.Provider,{children:c,value:k}))}function tr({children:u,location:c}){return Iy(ur(u),c)}function ur(u,c=[]){let o=[];return y.Children.forEach(u,(r,d)=>{if(!y.isValidElement(r))return;let h=[...c,d];if(r.type===y.Fragment){o.push.apply(o,ur(r.props.children,h));return}Me(r.type===ft,`[${typeof r.type=="string"?r.type:r.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`),Me(!r.props.index||!r.props.children,"An index route cannot have child routes.");let g={id:r.props.id||h.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,middleware:r.props.middleware,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(g.children=ur(r.props.children,h)),o.push(g)}),o}var xu="get",bu="application/x-www-form-urlencoded";function Nu(u){return typeof HTMLElement<"u"&&u instanceof HTMLElement}function dv(u){return Nu(u)&&u.tagName.toLowerCase()==="button"}function hv(u){return Nu(u)&&u.tagName.toLowerCase()==="form"}function mv(u){return Nu(u)&&u.tagName.toLowerCase()==="input"}function pv(u){return!!(u.metaKey||u.altKey||u.ctrlKey||u.shiftKey)}function gv(u,c){return u.button===0&&(!c||c==="_self")&&!pv(u)}var vu=null;function yv(){if(vu===null)try{new FormData(document.createElement("form"),0),vu=!1}catch{vu=!0}return vu}var vv=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function nr(u){return u!=null&&!vv.has(u)?(Vt(!1,`"${u}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${bu}"`),null):u}function xv(u,c){let o,r,d,h,g;if(hv(u)){let S=u.getAttribute("action");r=S?fn(S,c):null,o=u.getAttribute("method")||xu,d=nr(u.getAttribute("enctype"))||bu,h=new FormData(u)}else if(dv(u)||mv(u)&&(u.type==="submit"||u.type==="image")){let S=u.form;if(S==null)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let x=u.getAttribute("formaction")||S.getAttribute("action");if(r=x?fn(x,c):null,o=u.getAttribute("formmethod")||S.getAttribute("method")||xu,d=nr(u.getAttribute("formenctype"))||nr(S.getAttribute("enctype"))||bu,h=new FormData(S,u),!yv()){let{name:p,type:E,value:v}=u;if(E==="image"){let C=p?`${p}.`:"";h.append(`${C}x`,"0"),h.append(`${C}y`,"0")}else p&&h.append(p,v)}}else{if(Nu(u))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');o=xu,r=null,d=bu,g=u}return h&&d==="text/plain"&&(g=h,h=void 0),{action:r,method:o.toLowerCase(),encType:d,formData:h,body:g}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function pr(u,c){if(u===!1||u===null||typeof u>"u")throw new Error(c)}function vm(u,c,o,r){let d=typeof u=="string"?new URL(u,typeof window>"u"?"server://singlefetch/":window.location.origin):u;return o?d.pathname.endsWith("/")?d.pathname=`${d.pathname}_.${r}`:d.pathname=`${d.pathname}.${r}`:d.pathname==="/"?d.pathname=`_root.${r}`:c&&fn(d.pathname,c)==="/"?d.pathname=`${Su(c)}/_root.${r}`:d.pathname=`${Su(d.pathname)}.${r}`,d}async function bv(u,c){if(u.id in c)return c[u.id];try{let o=await import(u.module);return c[u.id]=o,o}catch(o){return console.error(`Error loading route module \`${u.module}\`, reloading page...`),console.error(o),window.__reactRouterContext&&window.__reactRouterContext.isSpaMode,window.location.reload(),new Promise(()=>{})}}function jv(u){return u==null?!1:u.href==null?u.rel==="preload"&&typeof u.imageSrcSet=="string"&&typeof u.imageSizes=="string":typeof u.rel=="string"&&typeof u.href=="string"}async function Sv(u,c,o){let r=await Promise.all(u.map(async d=>{let h=c.routes[d.route.id];if(h){let g=await bv(h,o);return g.links?g.links():[]}return[]}));return Nv(r.flat(1).filter(jv).filter(d=>d.rel==="stylesheet"||d.rel==="preload").map(d=>d.rel==="stylesheet"?{...d,rel:"prefetch",as:"style"}:{...d,rel:"prefetch"}))}function Vh(u,c,o,r,d,h){let g=(x,p)=>o[p]?x.route.id!==o[p].route.id:!0,S=(x,p)=>{var E;return o[p].pathname!==x.pathname||((E=o[p].route.path)==null?void 0:E.endsWith("*"))&&o[p].params["*"]!==x.params["*"]};return h==="assets"?c.filter((x,p)=>g(x,p)||S(x,p)):h==="data"?c.filter((x,p)=>{var v;let E=r.routes[x.route.id];if(!E||!E.hasLoader)return!1;if(g(x,p)||S(x,p))return!0;if(x.route.shouldRevalidate){let C=x.route.shouldRevalidate({currentUrl:new URL(d.pathname+d.search+d.hash,window.origin),currentParams:((v=o[0])==null?void 0:v.params)||{},nextUrl:new URL(u,window.origin),nextParams:x.params,defaultShouldRevalidate:!0});if(typeof C=="boolean")return C}return!0}):[]}function Ev(u,c,{includeHydrateFallback:o}={}){return Tv(u.map(r=>{let d=c.routes[r.route.id];if(!d)return[];let h=[d.module];return d.clientActionModule&&(h=h.concat(d.clientActionModule)),d.clientLoaderModule&&(h=h.concat(d.clientLoaderModule)),o&&d.hydrateFallbackModule&&(h=h.concat(d.hydrateFallbackModule)),d.imports&&(h=h.concat(d.imports)),h}).flat(1))}function Tv(u){return[...new Set(u)]}function _v(u){let c={},o=Object.keys(u).sort();for(let r of o)c[r]=u[r];return c}function Nv(u,c){let o=new Set;return new Set(c),u.reduce((r,d)=>{let h=JSON.stringify(_v(d));return o.has(h)||(o.add(h),r.push({key:h,link:d})),r},[])}function gr(){let u=y.useContext(Ql);return pr(u,"You must render this element inside a <DataRouterContext.Provider> element"),u}function wv(){let u=y.useContext(Tu);return pr(u,"You must render this element inside a <DataRouterStateContext.Provider> element"),u}var yr=y.createContext(void 0);yr.displayName="FrameworkContext";function vr(){let u=y.useContext(yr);return pr(u,"You must render this element inside a <HydratedRouter> element"),u}function Cv(u,c){let o=y.useContext(yr),[r,d]=y.useState(!1),[h,g]=y.useState(!1),{onFocus:S,onBlur:x,onMouseEnter:p,onMouseLeave:E,onTouchStart:v}=c,C=y.useRef(null);y.useEffect(()=>{if(u==="render"&&g(!0),u==="viewport"){let k=q=>{q.forEach(F=>{g(F.isIntersecting)})},H=new IntersectionObserver(k,{threshold:.5});return C.current&&H.observe(C.current),()=>{H.disconnect()}}},[u]),y.useEffect(()=>{if(r){let k=setTimeout(()=>{g(!0)},100);return()=>{clearTimeout(k)}}},[r]);let V=()=>{d(!0)},D=()=>{d(!1),g(!1)};return o?u!=="intent"?[h,C,{}]:[h,C,{onFocus:Ya(S,V),onBlur:Ya(x,D),onMouseEnter:Ya(p,V),onMouseLeave:Ya(E,D),onTouchStart:Ya(v,V)}]:[!1,C,{}]}function Ya(u,c){return o=>{u&&u(o),o.defaultPrevented||c(o)}}function Av({page:u,...c}){let o=Yy(),{router:r}=gr(),d=y.useMemo(()=>nm(r.routes,u,r.basename),[r.routes,u,r.basename]);return d?o?y.createElement(kv,{page:u,matches:d,...c}):y.createElement(zv,{page:u,matches:d,...c}):null}function Rv(u){let{manifest:c,routeModules:o}=vr(),[r,d]=y.useState([]);return y.useEffect(()=>{let h=!1;return Sv(u,c,o).then(g=>{h||d(g)}),()=>{h=!0}},[u,c,o]),r}function kv({page:u,matches:c,...o}){let r=dn(),{future:d}=vr(),{basename:h}=gr(),g=y.useMemo(()=>{if(u===r.pathname+r.search+r.hash)return[];let S=vm(u,h,d.unstable_trailingSlashAwareDataRequests,"rsc"),x=!1,p=[];for(let E of c)typeof E.route.shouldRevalidate=="function"?x=!0:p.push(E.route.id);return x&&p.length>0&&S.searchParams.set("_routes",p.join(",")),[S.pathname+S.search]},[h,d.unstable_trailingSlashAwareDataRequests,u,r,c]);return y.createElement(y.Fragment,null,g.map(S=>y.createElement("link",{key:S,rel:"prefetch",as:"fetch",href:S,...o})))}function zv({page:u,matches:c,...o}){let r=dn(),{future:d,manifest:h,routeModules:g}=vr(),{basename:S}=gr(),{loaderData:x,matches:p}=wv(),E=y.useMemo(()=>Vh(u,c,p,h,r,"data"),[u,c,p,h,r]),v=y.useMemo(()=>Vh(u,c,p,h,r,"assets"),[u,c,p,h,r]),C=y.useMemo(()=>{if(u===r.pathname+r.search+r.hash)return[];let k=new Set,H=!1;if(c.forEach(F=>{var z;let B=h.routes[F.route.id];!B||!B.hasLoader||(!E.some(Z=>Z.route.id===F.route.id)&&F.route.id in x&&((z=g[F.route.id])!=null&&z.shouldRevalidate)||B.hasClientLoader?H=!0:k.add(F.route.id))}),k.size===0)return[];let q=vm(u,S,d.unstable_trailingSlashAwareDataRequests,"data");return H&&k.size>0&&q.searchParams.set("_routes",c.filter(F=>k.has(F.route.id)).map(F=>F.route.id).join(",")),[q.pathname+q.search]},[S,d.unstable_trailingSlashAwareDataRequests,x,r,h,E,c,u,g]),V=y.useMemo(()=>Ev(v,h),[v,h]),D=Rv(v);return y.createElement(y.Fragment,null,C.map(k=>y.createElement("link",{key:k,rel:"prefetch",as:"fetch",href:k,...o})),V.map(k=>y.createElement("link",{key:k,rel:"modulepreload",href:k,...o})),D.map(({key:k,link:H})=>y.createElement("link",{key:k,nonce:o.nonce,...H,crossOrigin:H.crossOrigin??o.crossOrigin})))}function Mv(...u){return c=>{u.forEach(o=>{typeof o=="function"?o(c):o!=null&&(o.current=c)})}}var Ov=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";try{Ov&&(window.__reactRouterVersion="7.14.2")}catch{}function Dv({basename:u,children:c,unstable_useTransitions:o,window:r}){let d=y.useRef();d.current==null&&(d.current=py({window:r,v5Compat:!0}));let h=d.current,[g,S]=y.useState({action:h.action,location:h.location}),x=y.useCallback(p=>{o===!1?S(p):y.startTransition(()=>S(p))},[o]);return y.useLayoutEffect(()=>h.listen(x),[h,x]),y.createElement(fv,{basename:u,children:c,location:g.location,navigationType:g.action,navigator:h,unstable_useTransitions:o})}var xm=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Ze=y.forwardRef(function({onClick:c,discover:o="render",prefetch:r="none",relative:d,reloadDocument:h,replace:g,unstable_mask:S,state:x,target:p,to:E,preventScrollReset:v,viewTransition:C,unstable_defaultShouldRevalidate:V,...D},k){let{basename:H,navigator:q,unstable_useTransitions:F}=y.useContext(Mt),B=typeof E=="string"&&xm.test(E),z=cm(E,H);E=z.to;let Z=$y(E,{relative:d}),K=dn(),X=null;if(S){let ie=fr(S,[],K.unstable_mask?K.unstable_mask.pathname:"/",!0);H!=="/"&&(ie.pathname=ie.pathname==="/"?H:Ht([H,ie.pathname])),X=q.createHref(ie)}let[ee,ce,ze]=Cv(r,D),Oe=Lv(E,{replace:g,unstable_mask:S,state:x,target:p,preventScrollReset:v,relative:d,viewTransition:C,unstable_defaultShouldRevalidate:V,unstable_useTransitions:F});function De(ie){c&&c(ie),ie.defaultPrevented||Oe(ie)}let Ce=!(z.isExternal||h),I=y.createElement("a",{...D,...ze,href:(Ce?X:void 0)||z.absoluteURL||Z,onClick:Ce?De:c,ref:Mv(k,ce),target:p,"data-discover":!B&&o==="render"?"true":void 0});return ee&&!B?y.createElement(y.Fragment,null,I,y.createElement(Av,{page:Z})):I});Ze.displayName="Link";var Uv=y.forwardRef(function({"aria-current":c="page",caseSensitive:o=!1,className:r="",end:d=!1,style:h,to:g,viewTransition:S,children:x,...p},E){let v=Fa(g,{relative:p.relative}),C=dn(),V=y.useContext(Tu),{navigator:D,basename:k}=y.useContext(Mt),H=V!=null&&Xv(v)&&S===!0,q=D.encodeLocation?D.encodeLocation(v).pathname:v.pathname,F=C.pathname,B=V&&V.navigation&&V.navigation.location?V.navigation.location.pathname:null;o||(F=F.toLowerCase(),B=B?B.toLowerCase():null,q=q.toLowerCase()),B&&k&&(B=fn(B,k)||B);const z=q!=="/"&&q.endsWith("/")?q.length-1:q.length;let Z=F===q||!d&&F.startsWith(q)&&F.charAt(z)==="/",K=B!=null&&(B===q||!d&&B.startsWith(q)&&B.charAt(q.length)==="/"),X={isActive:Z,isPending:K,isTransitioning:H},ee=Z?c:void 0,ce;typeof r=="function"?ce=r(X):ce=[r,Z?"active":null,K?"pending":null,H?"transitioning":null].filter(Boolean).join(" ");let ze=typeof h=="function"?h(X):h;return y.createElement(Ze,{...p,"aria-current":ee,className:ce,ref:E,style:ze,to:g,viewTransition:S},typeof x=="function"?x(X):x)});Uv.displayName="NavLink";var Hv=y.forwardRef(({discover:u="render",fetcherKey:c,navigate:o,reloadDocument:r,replace:d,state:h,method:g=xu,action:S,onSubmit:x,relative:p,preventScrollReset:E,viewTransition:v,unstable_defaultShouldRevalidate:C,...V},D)=>{let{unstable_useTransitions:k}=y.useContext(Mt),H=Yv(),q=Vv(S,{relative:p}),F=g.toLowerCase()==="get"?"get":"post",B=typeof S=="string"&&xm.test(S),z=Z=>{if(x&&x(Z),Z.defaultPrevented)return;Z.preventDefault();let K=Z.nativeEvent.submitter,X=(K==null?void 0:K.getAttribute("formmethod"))||g,ee=()=>H(K||Z.currentTarget,{fetcherKey:c,method:X,navigate:o,replace:d,state:h,relative:p,preventScrollReset:E,viewTransition:v,unstable_defaultShouldRevalidate:C});k&&o!==!1?y.startTransition(()=>ee()):ee()};return y.createElement("form",{ref:D,method:F,action:q,onSubmit:r?x:z,...V,"data-discover":!B&&u==="render"?"true":void 0})});Hv.displayName="Form";function Bv(u){return`${u} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function bm(u){let c=y.useContext(Ql);return Me(c,Bv(u)),c}function Lv(u,{target:c,replace:o,unstable_mask:r,state:d,preventScrollReset:h,relative:g,viewTransition:S,unstable_defaultShouldRevalidate:x,unstable_useTransitions:p}={}){let E=Fy(),v=dn(),C=Fa(u,{relative:g});return y.useCallback(V=>{if(gv(V,c)){V.preventDefault();let D=o!==void 0?o:Qa(v)===Qa(C),k=()=>E(u,{replace:D,unstable_mask:r,state:d,preventScrollReset:h,relative:g,viewTransition:S,unstable_defaultShouldRevalidate:x});p?y.startTransition(()=>k()):k()}},[v,E,C,o,r,d,c,u,h,g,S,x,p])}var qv=0,Gv=()=>`__${String(++qv)}__`;function Yv(){let{router:u}=bm("useSubmit"),{basename:c}=y.useContext(Mt),o=sv(),r=u.fetch,d=u.navigate;return y.useCallback(async(h,g={})=>{let{action:S,method:x,encType:p,formData:E,body:v}=xv(h,c);if(g.navigate===!1){let C=g.fetcherKey||Gv();await r(C,o,g.action||S,{unstable_defaultShouldRevalidate:g.unstable_defaultShouldRevalidate,preventScrollReset:g.preventScrollReset,formData:E,body:v,formMethod:g.method||x,formEncType:g.encType||p,flushSync:g.flushSync})}else await d(g.action||S,{unstable_defaultShouldRevalidate:g.unstable_defaultShouldRevalidate,preventScrollReset:g.preventScrollReset,formData:E,body:v,formMethod:g.method||x,formEncType:g.encType||p,replace:g.replace,state:g.state,fromRouteId:o,flushSync:g.flushSync,viewTransition:g.viewTransition})},[r,d,c,o])}function Vv(u,{relative:c}={}){let{basename:o}=y.useContext(Mt),r=y.useContext(Xt);Me(r,"useFormAction must be used inside a RouteContext");let[d]=r.matches.slice(-1),h={...Fa(u||".",{relative:c})},g=dn();if(u==null){h.search=g.search;let S=new URLSearchParams(h.search),x=S.getAll("index");if(x.some(E=>E==="")){S.delete("index"),x.filter(v=>v).forEach(v=>S.append("index",v));let E=S.toString();h.search=E?`?${E}`:""}}return(!u||u===".")&&d.route.index&&(h.search=h.search?h.search.replace(/^\?/,"?index&"):"?index"),o!=="/"&&(h.pathname=h.pathname==="/"?o:Ht([o,h.pathname])),Qa(h)}function Xv(u,{relative:c}={}){let o=y.useContext(fm);Me(o!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:r}=bm("useViewTransitionState"),d=Fa(u,{relative:c});if(!o.isTransitioning)return!1;let h=fn(o.currentLocation.pathname,r)||o.currentLocation.pathname,g=fn(o.nextLocation.pathname,r)||o.nextLocation.pathname;return ju(d.pathname,g)!=null||ju(d.pathname,h)!=null}const jm=/^\/vault\/admin(?=\/|$)/,Sm=/^\/vault\/([^/]+)\/admin(?=\/|$)/;function xr(){return typeof window>"u"?!1:jm.test(window.location.pathname)}function Em(){if(typeof window>"u"||xr())return null;const u=window.location.pathname.match(Sm);if(!u)return null;try{return decodeURIComponent(u[1])}catch{return null}}function Qv(){if(typeof window>"u")return"";const u=window.location.pathname;if(jm.test(u))return"/vault/admin";const c=u.match(Sm);return c?`/vault/${c[1]}/admin`:u==="/admin"||u.startsWith("/admin/")?"/admin":""}let Bn=null,Yt=null,il=null,on=null,Xh=!1;const Zv=.8,Kv=1e3,Jv=3e4;function $v(){if(typeof window>"u")return;const u=window.location.hash;if(!u||u.length<2)return;const c=new URLSearchParams(u.slice(1)),o=c.get("token");if(!o)return;Bn=o,Yt=null,c.delete("token");const r=c.toString(),d=r.length>0?`#${r}`:"",h=`${window.location.pathname}${window.location.search}${d}`;window.history.replaceState(null,"",h)}function br(){return Bn}function Fv(){Bn=null,Yt=null,on=null,wu()}async function Za(u){if(typeof window>"u")return{kind:"network-error",message:"no window"};let c;try{c=await fetch(`/admin/vault-admin-token/${encodeURIComponent(u)}`,{method:"GET",headers:{accept:"application/json"},credentials:"same-origin"})}catch(r){return{kind:"network-error",message:r instanceof Error?r.message:String(r)}}if(c.status===401||c.status===403||c.status===404)return{kind:"auth-required",status:c.status};if(!c.ok)return{kind:"network-error",message:`hub returned ${c.status}`};let o;try{o=await c.json()}catch(r){return{kind:"network-error",message:r instanceof Error?r.message:"could not parse mint response"}}return typeof o.token!="string"||o.token.length===0?{kind:"network-error",message:"mint response missing token"}:(Bn=o.token,Yt=o.expires_at?Wv(o.expires_at):null,on=u,Tm(),e0(),{kind:"ok",token:o.token})}function Wv(u){const c=Date.parse(u);return Number.isNaN(c)?null:c}async function sr(u){if(Bn){if(Yt===null||Yt>Date.now())return{kind:"ok",token:Bn};Bn=null,Yt=null,wu()}return Za(u)}async function Iv(u){typeof window>"u"||Bn||await Za(u).catch(()=>{})}function Tm(){if(wu(),Yt===null||on===null||typeof document<"u"&&document.visibilityState==="hidden")return;const u=Date.now(),c=Yt-u;if(c<=0)return;const o=Math.max(Math.floor(c*Zv),Kv);il=setTimeout(()=>{Pv()},o)}function wu(){il!==null&&(clearTimeout(il),il=null)}async function Pv(){if(il=null,on===null)return;const u=await Za(on);u.kind!=="ok"&&(typeof console<"u"&&console.warn("[vault-admin-spa] proactive token refresh failed; will retry once",u),il=setTimeout(()=>{il=null,on!==null&&Za(on).catch(()=>{})},Jv))}function e0(){Xh||typeof document>"u"||(Xh=!0,document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden"){wu();return}if(on!==null){if(Yt!==null&&Yt<=Date.now()){Za(on).catch(()=>{});return}Tm()}}))}class pe extends Error{constructor(c,o,r){super(o),this.status=c,this.errorType=r,this.name="HttpError"}}async function Ge(u,c,o={}){let r=br();if(!r){const p=await sr(u);if(p.kind!=="ok")throw new pe(401,"no admin token — sign in to the hub to refresh");r=p.token}const{headers:d,...h}=o,g=p=>({accept:"application/json",...d??{},authorization:`Bearer ${p}`}),S=await fetch(c,{...h,headers:g(r)});if(S.status!==401)return S;Fv();const x=await sr(u);return x.kind!=="ok"?S:fetch(c,{...h,headers:g(x.token)})}async function _m(){const u=await fetch("/vaults/list",{headers:{accept:"application/json"}});if(u.status===404)return[];if(!u.ok)throw new pe(u.status,`vaults/list fetch failed: ${u.status}`);return(await u.json()).vaults??[]}async function t0(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/`);if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function n0(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror`);if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function Nm(u,c){const o=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!o.ok)throw new pe(o.status,await St(o));return await o.json()}async function l0(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/run-now`,{method:"POST"});if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function a0(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/push-now`,{method:"POST"});if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function jr(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth`);if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function i0(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth`,{method:"DELETE"});if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function u0(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth/github/device-code`,{method:"POST"});if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function s0(u,c){const o=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth/github/poll`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({polling_id:c})});if(!o.ok&&o.status!==404)throw new pe(o.status,await St(o));return await o.json()}async function c0(u,c){const o=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth/pat`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!o.ok)throw new pe(o.status,await St(o));return await o.json()}async function wm(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth/github/installations`);if(!c.ok){const{message:o,errorType:r}=await Sr(c);throw new pe(c.status,o,r)}return await c.json()}async function Cm(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth/github/repos`);if(!c.ok)throw new pe(c.status,await St(c));return await c.json()}async function r0(u,c){const o=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth/github/create-repo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!o.ok){const{message:r,errorType:d}=await Sr(o);throw new pe(o.status,r,d)}return await o.json()}async function o0(u,c){const o=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/auth/github/select-repo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!o.ok)throw new pe(o.status,await St(o));return await o.json()}async function f0(u,c){const o=await Ge(u,`/vault/${encodeURIComponent(u)}/.parachute/mirror/import`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!o.ok)throw new pe(o.status,await St(o));return await o.json()}async function St(u){return(await Sr(u)).message}async function Sr(u){try{const c=await u.text(),o=JSON.parse(c),r=typeof o.error_type=="string"?o.error_type:void 0;if(o.error_description)return{message:o.error_description,errorType:r};if(o.message)return{message:o.message,errorType:r};if(o.error)return{message:o.error,errorType:r};if(c)return{message:c,errorType:r}}catch{}return{message:`${u.status} ${u.statusText}`}}function Am(u){const c=u.split(".");if(c.length!==3)return null;try{const o=c[1].replace(/-/g,"+").replace(/_/g,"/"),r=o.length%4===0?"":"=".repeat(4-o.length%4),d=atob(o+r),h=JSON.parse(d);return h===null||typeof h!="object"?null:h}catch{return null}}function d0(u){if(!u)return[];const c=Am(u);if(!c)return[];const o=c.scope;if(typeof o=="string"&&o.length>0)return o.split(/\s+/).filter(d=>d.length>0);const r=c.scopes;return Array.isArray(r)?r.filter(d=>typeof d=="string"&&d.length>0):[]}function Er(u){return d0(br()).includes(`vault:${u}:admin`)}function Rm(){const u=br();if(!u)return null;const c=Am(u);if(!c)return null;const o=c.iss;return typeof o!="string"||o.length===0?null:o.replace(/\/$/,"")}let Va=null,Xa=null;function h0(u){const c=Date.parse(u);return Number.isNaN(c)?null:c}async function m0(){if(typeof window>"u")return{kind:"network-error",message:"no window"};let u;try{u=await fetch("/admin/host-admin-token",{method:"GET",headers:{accept:"application/json"},credentials:"same-origin"})}catch(o){return{kind:"network-error",message:o instanceof Error?o.message:String(o)}}if(u.status===403)return{kind:"forbidden"};if(u.status===401||u.status===404)return{kind:"auth-required",status:u.status};if(!u.ok)return{kind:"network-error",message:`hub returned ${u.status}`};let c;try{c=await u.json()}catch(o){return{kind:"network-error",message:o instanceof Error?o.message:"could not parse host-admin mint response"}}return typeof c.token!="string"||c.token.length===0?{kind:"network-error",message:"host-admin mint response missing token"}:(Va=c.token,Xa=c.expires_at?h0(c.expires_at):null,{kind:"ok",token:c.token})}async function Eu(){if(Va){if(Xa===null||Xa>Date.now())return{kind:"ok",token:Va};Va=null,Xa=null}return m0()}function p0(){Va=null,Xa=null}class Ln extends Error{constructor(c,o,r){super(o),this.status=c,this.disposition=r,this.name="HostAdminError"}}async function Wa(u,c={}){let o;const r=await Eu();if(r.kind!=="ok")throw Qh(r);o=r.token;const{headers:d,...h}=c,g=p=>({accept:"application/json",...d??{},authorization:`Bearer ${p}`}),S=await fetch(u,{...h,headers:g(o)});if(S.status!==401)return S;p0();const x=await Eu();if(x.kind!=="ok")throw Qh(x);return fetch(u,{...h,headers:g(x.token)})}function Qh(u){return u.kind==="forbidden"?new Ln(403,"host-admin token mint forbidden — not the hub admin","forbidden"):u.kind==="auth-required"?new Ln(u.status,"no host-admin session — sign in to the hub to manage tokens","auth-required"):new Ln(0,u.message,"network-error")}function Ka(){if(typeof window>"u")return;const u=Rm();window.location.href=u?`${u}/account/`:"/account/"}async function g0(){let u;try{u=await fetch("/.well-known/parachute.json",{headers:{accept:"application/json"}})}catch(d){return{kind:"error",message:d instanceof Error?d.message:String(d)}}if(u.status===404)return{kind:"no-hub"};if(!u.ok)return{kind:"error",message:`well-known fetch failed: ${u.status}`};let c;try{c=await u.json()}catch{return{kind:"no-hub"}}const o=Array.isArray(c.vaults)?c.vaults:[],r=[];for(const d of o){const h=d??{};typeof h.name=="string"&&r.push({name:h.name,url:typeof h.url=="string"?h.url:"",version:typeof h.version=="string"?h.version:"",...typeof h.managementUrl=="string"?{managementUrl:h.managementUrl}:{}})}return{kind:"ok",vaults:r}}async function y0(u){var S,x;const c=await fetch(`/admin/vault-admin-token/${encodeURIComponent(u)}`,{method:"GET",headers:{accept:"application/json"},credentials:"same-origin"});if(!c.ok)throw new Error(`vault-admin-token mint failed: ${c.status}`);const o=await c.json();if(typeof o.token!="string"||o.token.length===0)throw new Error("vault-admin-token mint returned no token");const r=await fetch(`/vault/${encodeURIComponent(u)}/.parachute/usage`,{headers:{accept:"application/json",authorization:`Bearer ${o.token}`}});if(!r.ok)throw new Error(`usage fetch failed: ${r.status}`);const d=await r.json(),h=(S=d.counts)==null?void 0:S.notes,g=(x=d.bytes)==null?void 0:x.total;if(typeof h!="number"||typeof g!="number")throw new Error("usage report malformed");return{notes:h,totalBytes:g}}function v0(u){if(!Number.isFinite(u)||u<0)return"0 B";if(u<1024)return`${Math.round(u)} B`;const c=u/1024;if(c<1024)return`${Math.round(c)} KB`;const o=c/1024;return o<1024?`${o.toFixed(1)} MB`:`${(o/1024).toFixed(1)} GB`}const x0=/^[a-z0-9_-]+$/,b0=new Set(["list","new","assets","admin"]);function j0(u){return u.length===0?null:x0.test(u)?u.length<2||u.length>32?"Vault names must be 2–32 characters long.":b0.has(u)?`"${u}" is a reserved name.`:null:"Lowercase letters, numbers, hyphens, and underscores only."}class cr extends Error{constructor(c,o,r){super(o),this.status=c,this.code=r,this.name="VaultsApiError"}}async function km(u){let c,o=`${u.status}`;try{const r=await u.json();typeof r.error=="string"&&(c=r.error),o=r.error_description??r.error??o}catch{}return new cr(u.status,o,c)}async function S0(u){const c=await Wa("/vaults",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:u})});if(!c.ok)throw await km(c);const o=await c.json(),r={name:o.name,url:o.url,version:o.version,created:c.status===201};return o.token&&(r.token=o.token),o.token_guidance&&(r.tokenGuidance=o.token_guidance),r}async function E0(u){const c=await Wa(`/vaults/${encodeURIComponent(u)}`,{method:"DELETE",headers:{"content-type":"application/json"},body:JSON.stringify({confirm:u})});if(!c.ok)throw await km(c);const o=await c.json();return{name:o.name,cascade:o.cascade,warnings:o.warnings??[]}}const Zh=5e3;function Zl({vaultName:u,status:c,onRecovered:o,ensure:r}){const d=c===403;if(y.useEffect(()=>{if(d)return;let x=!1,p=null;const E=async()=>{if(x||typeof document<"u"&&document.visibilityState!=="visible")return;const C=await(r?r():sr(u??""));if(!x){if(C.kind==="ok"){o();return}p=setTimeout(()=>void E(),Zh)}},v=()=>{typeof document>"u"||document.visibilityState==="visible"&&(p!==null&&(clearTimeout(p),p=null),E())};return p=setTimeout(()=>void E(),Zh),typeof document<"u"&&document.addEventListener("visibilitychange",v),()=>{x=!0,p!==null&&clearTimeout(p),typeof document<"u"&&document.removeEventListener("visibilitychange",v)}},[u,o,d,r]),d)return i.jsxs("div",{className:"warn-banner",role:"status",children:[i.jsxs("p",{style:{margin:"0 0 0.5rem"},children:["You're signed in, but vault management is restricted to the hub admin."," ",i.jsx("a",{href:"/account/",children:"Go to your account →"})]}),i.jsx("p",{className:"dim",style:{margin:0,fontSize:"0.85rem"},children:"Ask the hub admin if you need access to manage this vault."})]});const h=T0(),g=`/login?next=${encodeURIComponent(h)}`,S=c===404?"This hub doesn't host a vault by that name.":"You're not signed in to the hub.";return i.jsxs("div",{className:"warn-banner",role:"status",children:[i.jsxs("p",{style:{margin:"0 0 0.5rem"},children:[S," ",i.jsx("a",{href:g,children:"Sign in to the hub →"})]}),i.jsx("p",{className:"dim",style:{margin:0,fontSize:"0.85rem"},children:"After signing in, this page will refresh automatically."})]})}function T0(){return typeof window>"u"?"/":`${window.location.pathname}${window.location.search}${window.location.hash}`}function _0(){const[u,c]=y.useState({kind:"loading"}),[o,r]=y.useState({kind:"checking"}),[d,h]=y.useState({}),[g,S]=y.useState({kind:"idle"}),[x,p]=y.useState(""),[E,v]=y.useState({kind:"idle"}),[C,V]=y.useState(0);y.useEffect(()=>{let B=!1;return g0().then(async z=>{if(!B){if(z.kind==="ok"){c({kind:"ok",vaults:z.vaults});return}if(z.kind==="no-hub"){const Z=await _m().catch(()=>[]);if(B)return;c({kind:"no-hub",names:Z});return}c({kind:"error",message:z.message})}}),()=>{B=!0}},[C]),y.useEffect(()=>{if(u.kind!=="ok"||o.kind==="ok")return;let B=!1;return Eu().then(z=>{B||(z.kind==="ok"?r({kind:"ok"}):z.kind==="forbidden"?r({kind:"banner",status:403}):z.kind==="auth-required"?r({kind:"banner",status:z.status}):r({kind:"banner",status:null}))}),()=>{B=!0}},[u.kind]),y.useEffect(()=>{if(u.kind!=="ok")return;const B=u.vaults.map(Z=>Z.name);if(B.length===0)return;let z=!1;h(Z=>{const K={...Z};for(const X of B)K[X]||(K[X]={kind:"loading"});return K});for(const Z of B)y0(Z).then(K=>{z||h(X=>({...X,[Z]:{kind:"ok",usage:K}}))}).catch(()=>{z||h(K=>({...K,[Z]:{kind:"error"}}))});return()=>{z=!0}},[u]);const D=y.useCallback(()=>{r({kind:"ok"}),h({}),V(B=>B+1)},[]),k=j0(x);async function H(B){if(B.preventDefault(),!(x.length===0||k)){S({kind:"submitting"});try{const z=await S0(x);S({kind:"created",result:z}),p(""),V(Z=>Z+1)}catch(z){if(z instanceof Ln){if(z.disposition==="forbidden"){Ka();return}r({kind:"banner",status:z.status||null}),S({kind:"idle"});return}const Z=z instanceof cr?`${z.status}: ${z.message}`:z instanceof Error?z.message:String(z);S({kind:"error",message:Z})}}}async function q(B){v({kind:"deleting",name:B});try{const z=await E0(B);v({kind:"done",result:z}),h(Z=>{const K={...Z};return delete K[B],K}),V(Z=>Z+1)}catch(z){if(z instanceof Ln){if(z.disposition==="forbidden"){Ka();return}r({kind:"banner",status:z.status||null}),v({kind:"idle"});return}const Z=z instanceof cr||z instanceof Error?z.message:String(z);v({kind:"error",name:B,message:Z})}}if(u.kind==="loading")return i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsx("p",{className:"muted",children:"Loading…"})]});if(u.kind==="no-hub")return i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsxs("div",{className:"warn-banner",role:"status",children:[i.jsx("p",{style:{margin:"0 0 0.5rem"},children:"This page is being served directly by the vault daemon — there's no hub on this origin, so vault management (create / delete) isn't available here."}),i.jsxs("p",{className:"dim",style:{margin:0,fontSize:"0.85rem"},children:["The hub origin is the front door: open ",i.jsx("code",{children:"/vault/admin/"})," on your hub (port 1939 by default) to manage vaults. Read-only vault names below."]})]}),u.names.length>0?i.jsx("div",{style:{marginTop:"1rem"},children:u.names.map(B=>i.jsxs("a",{href:`/vault/${encodeURIComponent(B)}/admin/`,className:"vault-row",children:[i.jsx("div",{className:"body",children:i.jsx("div",{className:"name",children:i.jsx("code",{children:B})})}),i.jsx("div",{className:"chev",children:"→"})]},B))}):null]});if(u.kind==="error")return i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:u.message})}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>V(B=>B+1),children:"Retry"})]});const F=o.kind==="ok";return i.jsxs("div",{children:[i.jsx("div",{className:"list-header",children:i.jsxs("h2",{children:["Vaults (",u.vaults.length,")"]})}),o.kind==="banner"?i.jsx(Zl,{status:o.status,onRecovered:D,ensure:Eu}):null,i.jsxs("p",{className:"muted",children:["Vaults registered with this hub. ",i.jsx("strong",{children:"Manage"})," opens each vault's own admin page (a full page load — use your browser's back button to return here)."]}),E.kind==="done"?i.jsx(w0,{result:E.result,onDismiss:()=>v({kind:"idle"})}):null,u.vaults.length===0?i.jsxs("div",{className:"empty",children:["No vaults yet",F?" — create your first below.":"."]}):i.jsx("div",{style:{marginTop:"1rem"},children:u.vaults.map(B=>{const z=d[B.name],Z=(z==null?void 0:z.kind)==="ok"?`${z.usage.notes} ${z.usage.notes===1?"note":"notes"} · ${v0(z.usage.totalBytes)}`:(z==null?void 0:z.kind)==="loading"?"…":"—",K=E.kind==="confirming"&&E.name===B.name,X=E.kind==="deleting"&&E.name===B.name,ee=E.kind==="error"&&E.name===B.name?E.message:null;return i.jsxs("div",{className:"vault-row-group",children:[i.jsxs("div",{className:"vault-row",children:[i.jsxs("div",{className:"body",children:[i.jsxs("div",{className:"name",children:[i.jsx("code",{children:B.name}),B.version?i.jsxs("span",{className:"tag muted",title:"Vault version",children:[" ","v",B.version]}):null]}),i.jsx("div",{className:"dim vault-usage","data-testid":`vault-usage-${B.name}`,children:Z}),ee?i.jsx("div",{className:"error-banner",style:{marginTop:"0.5rem"},children:i.jsx("code",{children:ee})}):null]}),i.jsxs("div",{className:"vault-row-actions",children:[i.jsx("a",{href:`/vault/${encodeURIComponent(B.name)}/admin/`,children:i.jsx("button",{type:"button",children:"Manage"})}),F?i.jsx("button",{type:"button",className:"secondary",disabled:X,onClick:()=>v(K?{kind:"idle"}:{kind:"confirming",name:B.name,typed:""}),children:X?"Deleting…":"Delete"}):null]})]}),K&&E.kind==="confirming"?i.jsxs("div",{className:"section",style:{marginTop:"0.5rem"},children:[i.jsxs("p",{style:{margin:"0 0 0.5rem"},children:["Deleting ",i.jsx("code",{children:B.name})," permanently destroys its notes and revokes every token, grant, assignment, and invite naming it. Type the vault name to confirm:"]}),i.jsxs("div",{className:"row",style:{display:"flex",gap:"0.5rem"},children:[i.jsx("input",{type:"text","aria-label":`Type ${B.name} to confirm deletion`,placeholder:B.name,value:E.typed,onChange:ce=>v({kind:"confirming",name:B.name,typed:ce.target.value})}),i.jsx("button",{type:"button",disabled:E.typed!==B.name,onClick:()=>void q(B.name),children:"Delete this vault"}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>v({kind:"idle"}),children:"Cancel"})]})]}):null]},B.name)})}),F?i.jsxs("div",{className:"section",style:{marginTop:"1.5rem"},children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Create a vault"}),g.kind==="created"?i.jsx(N0,{result:g.result,onDone:()=>S({kind:"idle"})}):i.jsxs("form",{onSubmit:B=>void H(B),children:[g.kind==="error"?i.jsxs("div",{className:"error-banner",style:{marginBottom:"0.5rem"},children:["Couldn't create vault: ",i.jsx("code",{children:g.message})]}):null,i.jsxs("div",{className:"row",style:{display:"flex",gap:"0.5rem"},children:[i.jsx("input",{id:"new-vault-name",type:"text","aria-label":"New vault name",value:x,onChange:B=>p(B.target.value),placeholder:"e.g. work, home, scratch",disabled:g.kind==="submitting"}),i.jsx("button",{type:"submit",disabled:x.length===0||!!k||g.kind==="submitting",children:g.kind==="submitting"?"Creating…":"Create vault"})]}),k?i.jsx("div",{className:"field-error",children:k}):i.jsxs("div",{className:"dim",style:{fontSize:"0.85rem",marginTop:"0.35rem"},children:["Lowercase letters, numbers, hyphens, underscores. Becomes the path under"," ",i.jsx("code",{children:"/vault/<name>"}),"."]})]})]}):null]})}function N0({result:u,onDone:c}){const[o,r]=y.useState(!1),d=async()=>{if(u.token)try{await navigator.clipboard.writeText(u.token),r(!0),setTimeout(()=>r(!1),2e3)}catch{}};return u.token?i.jsxs("div",{className:"mint-banner",children:[i.jsxs("h4",{style:{margin:"0 0 0.5rem"},children:["Vault ",i.jsx("code",{children:u.name})," created — access token (shown once)"]}),i.jsxs("p",{className:"muted",children:["A hub-issued JWT scoped ",i.jsxs("code",{children:["vault:",u.name,":admin"]}),". This is the only time it's shown — copy it somewhere safe. You don't need it for the OAuth connect path; for a header-auth token later, mint a scope-narrow one with"," ",i.jsxs("code",{children:["parachute auth mint-token --scope vault:",u.name,":read"]}),"."]}),i.jsxs("div",{className:"token-box",children:[i.jsx("code",{children:u.token}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>void d(),children:o?"Copied":"Copy"})]}),i.jsx("div",{className:"actions",style:{marginTop:"0.5rem"},children:i.jsx("button",{type:"button",onClick:c,children:"Done — I've saved the token"})})]}):u.created?i.jsxs("div",{className:"section",children:[i.jsxs("p",{children:["Vault ",i.jsx("code",{children:u.name})," was created",u.tokenGuidance?i.jsxs(i.Fragment,{children:[" ","— ",i.jsx("span",{className:"muted",children:u.tokenGuidance})]}):i.jsx("span",{className:"muted",children:" (no bootstrap token was minted)"}),". Connect over OAuth (no token needed), or mint a scope-narrow header-auth token with"," ",i.jsxs("code",{children:["parachute auth mint-token --scope vault:",u.name,":read"]}),"."]}),i.jsx("button",{type:"button",onClick:c,children:"Done"})]}):i.jsxs("div",{className:"section",children:[i.jsxs("p",{children:["Vault ",i.jsx("code",{children:u.name})," already existed; nothing new was created."]}),i.jsx("button",{type:"button",onClick:c,children:"Continue"})]})}function w0({result:u,onDismiss:c}){const o=u.cascade;return i.jsxs("div",{className:"section",role:"status",style:{marginTop:"0.75rem"},children:[i.jsxs("h3",{style:{margin:"0 0 0.5rem",fontSize:"1rem",fontWeight:500},children:["Vault ",i.jsx("code",{children:u.name})," deleted"]}),i.jsxs("ul",{style:{margin:"0 0 0.5rem"},children:[i.jsxs("li",{children:[o.tokens_revoked," token(s) revoked"]}),i.jsxs("li",{children:[o.grants_rewritten," grant(s) rewritten, ",o.grants_dropped," dropped"]}),i.jsxs("li",{children:[o.user_vaults_removed," user assignment(s) removed"]}),i.jsxs("li",{children:[o.invites_invalidated," invite(s) invalidated"]}),i.jsxs("li",{children:[o.connections_torn_down," connection(s) torn down"]}),i.jsxs("li",{children:["vault data ",o.vault_removed?"removed":"NOT removed","; module"," ",o.module_restarted?"restarted":"not restarted"]})]}),o.orphaned_channels.length>0?i.jsxs("div",{className:"warn-banner",style:{marginBottom:"0.5rem"},children:["Orphaned channel(s) still reference this vault:"," ",o.orphaned_channels.map((r,d)=>i.jsxs("span",{children:[d>0?", ":"",i.jsx("code",{children:r})]},r))," ","— remove them from the channel module's own admin page."]}):null,u.warnings.length>0?i.jsx("div",{className:"warn-banner",style:{marginBottom:"0.5rem"},children:u.warnings.map(r=>i.jsxs("div",{children:[i.jsx("code",{children:r.step}),": ",r.detail]},r.step))}):null,i.jsx("button",{type:"button",className:"secondary",onClick:c,children:"Dismiss"})]})}const C0="https://parachute.computer/install#connect-mcp-clients";function zm(u,c){return`${u.replace(/\/+$/,"")}/vault/${encodeURIComponent(c)}/mcp`}function A0(u,c){return`claude mcp add --transport http parachute-${c} ${zm(u,c)}`}function R0(){var u;return typeof window>"u"||!((u=window.location)!=null&&u.origin)?null:window.location.origin}function Kh({value:u,label:c="Copy"}){const[o,r]=y.useState(!1);return i.jsx("button",{type:"button",className:"secondary",onClick:()=>{typeof navigator>"u"||!navigator.clipboard||navigator.clipboard.writeText(u).then(()=>{r(!0),setTimeout(()=>r(!1),2e3)})},children:o?"Copied ✓":c})}function k0({vaultName:u,origin:c,tokensHref:o}){const r=c??R0(),d=r?zm(r,u):`/vault/${encodeURIComponent(u)}/mcp`,h=r?A0(r,u):`claude mcp add --transport http parachute-${u} ${d}`;return i.jsxs("div",{className:"mcp-connect-card",children:[i.jsx("h3",{children:"Connect to your AI"}),i.jsxs("p",{className:"muted",children:["Connect an AI client — Claude.ai (add it as a connector), Claude Code, or any MCP client — to the ",i.jsx("code",{children:u})," vault. The client signs in to this hub and reads/writes vault data over MCP."]}),i.jsxs("div",{className:"mcp-field",children:[i.jsx("span",{className:"mcp-field-label",children:"MCP endpoint"}),i.jsxs("div",{className:"token-box",children:[i.jsx("code",{"data-testid":"mcp-endpoint",children:d}),i.jsx(Kh,{value:d})]}),i.jsx("p",{className:"dim",children:"Claude.ai / ChatGPT: add this URL as a custom connector. You'll sign in to this hub and approve access in the browser."})]}),i.jsxs("div",{className:"mcp-field",children:[i.jsx("span",{className:"mcp-field-label",children:"Claude Code"}),i.jsxs("div",{className:"token-box",children:[i.jsx("code",{"data-testid":"mcp-add-command",children:h}),i.jsx(Kh,{value:h})]}),i.jsx("p",{className:"dim",children:"No token needed — the command triggers browser OAuth on first use (you sign in to this hub and approve access)."})]}),i.jsxs("p",{className:"dim",children:["Headless / CI / bearer-token clients that can't do browser OAuth: mint a scope-narrow hub token (",i.jsxs("code",{children:["vault:",u,":read vault:",u,":write"]})," — not admin) on the"," ",o?i.jsx(Ze,{to:o,children:"Tokens page"}):i.jsx("span",{children:"Tokens page"})," and pass it as ",i.jsx("code",{children:'--header "Authorization: Bearer <token>"'}),"."]}),i.jsx("p",{className:"dim mcp-docs-link",children:i.jsx("a",{href:C0,target:"_blank",rel:"noreferrer",children:"Full connect docs →"})})]})}function Jh({vaultName:u}={}){const c=_u(),o=u??c.name,r=u!==void 0,d=r?"/tokens":`/vault/${encodeURIComponent(o??"")}/tokens`,h=r?"/mirror":`/vault/${encodeURIComponent(o??"")}/mirror`,g=r?"/schema":`/vault/${encodeURIComponent(o??"")}/schema`,[S,x]=y.useState({kind:"loading"}),[p,E]=y.useState(0),v=y.useCallback(()=>E(D=>D+1),[]);if(y.useEffect(()=>{let D=!1;if(!o){x({kind:"missing"});return}return x({kind:"loading"}),t0(o).then(k=>{D||x({kind:"ok",vault:k})}).catch(k=>{if(D)return;if(k instanceof pe){if(k.status===401||k.status===403){x({kind:"auth-required",status:k.status});return}if(k.status===404){x({kind:"missing"});return}x({kind:"error",message:`${k.status}: ${k.message}`});return}const H=k instanceof Error?k.message:String(k);x({kind:"error",message:H})}),()=>{D=!0}},[o,p]),S.kind==="loading")return i.jsxs("div",{children:[i.jsx("h2",{children:"Vault"}),i.jsx("p",{className:"muted",children:"Loading…"})]});if(S.kind==="auth-required")return i.jsxs("div",{children:[i.jsxs("h2",{children:["Vault ",i.jsx("code",{children:o})]}),i.jsx(Zl,{vaultName:o??"",status:S.status,onRecovered:v}),r?null:i.jsx(Ze,{to:"/",children:"← Back to vaults"})]});if(S.kind==="missing")return i.jsxs("div",{children:[i.jsx("h2",{children:"Vault not found"}),i.jsxs("p",{className:"muted",children:["No vault named ",i.jsx("code",{children:o})," is registered on this server."]}),r?null:i.jsx(Ze,{to:"/",children:"← Back to vaults"})]});if(S.kind==="error")return i.jsxs("div",{children:[i.jsxs("h2",{children:["Vault ",i.jsx("code",{children:o})]}),i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:S.message})}),r?null:i.jsx(Ze,{to:"/",children:"← Back to vaults"})]});const{vault:C}=S,V=`/vault/${C.name}`;return i.jsxs("div",{children:[i.jsxs("div",{className:"list-header",children:[i.jsxs("h2",{children:["Vault ",i.jsx("code",{children:C.name})]}),r?null:i.jsx(Ze,{to:"/",className:"muted",children:"← All vaults"})]}),i.jsxs("div",{className:"kv section",children:[i.jsx("div",{children:"Name"}),i.jsx("div",{children:i.jsx("code",{children:C.name})}),C.description?i.jsxs(i.Fragment,{children:[i.jsx("div",{children:"Description"}),i.jsx("div",{children:C.description})]}):null,i.jsx("div",{children:"Mount"}),i.jsx("div",{children:i.jsx("code",{children:V})}),C.createdAt?i.jsxs(i.Fragment,{children:[i.jsx("div",{children:"Created"}),i.jsx("div",{children:i.jsx("code",{children:C.createdAt})})]}):null]}),i.jsx("div",{className:"section",children:i.jsx(k0,{vaultName:C.name,tokensHref:d})}),i.jsxs("div",{className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Stats"}),i.jsxs("div",{className:"stats",children:[i.jsxs("div",{className:"stat",children:[i.jsx("div",{className:"label",children:"Notes"}),i.jsx("div",{className:"value",children:C.stats.totalNotes})]}),i.jsxs("div",{className:"stat",children:[i.jsx("div",{className:"label",children:"Tags"}),i.jsx("div",{className:"value",children:C.stats.tagCount})]}),i.jsxs("div",{className:"stat",children:[i.jsx("div",{className:"label",children:"Attachments"}),i.jsx("div",{className:"value",children:C.stats.attachmentCount})]}),i.jsxs("div",{className:"stat",children:[i.jsx("div",{className:"label",children:"Links"}),i.jsx("div",{className:"value",children:C.stats.linkCount})]})]})]}),i.jsxs("div",{className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Manage"}),i.jsxs("ul",{className:"manage-list",children:[i.jsxs("li",{children:[i.jsx(Ze,{to:d,children:"Tokens →"}),i.jsx("span",{className:"dim",children:" mint, list, and revoke hub access tokens (JWTs)"})]}),i.jsxs("li",{children:[i.jsx(Ze,{to:h,children:"Git backup →"}),i.jsx("span",{className:"dim",children:" mirror this vault to a git repository on a schedule, or on demand"})]}),i.jsxs("li",{children:[i.jsx(Ze,{to:g,children:"Schema →"}),i.jsx("span",{className:"dim",children:" edit tag schemas — fields, indexing, hierarchy, strict validation"})]}),i.jsx(z0,{vaultName:C.name})]})]})]})}function z0({vaultName:u}){const c=Rm();if(!c)return i.jsxs("li",{children:[i.jsx("span",{children:"Permissions →"}),i.jsxs("span",{className:"dim",children:[" ","grants are managed on hub (the OAuth issuer); link will be live when hub ships its permissions UI."]})]});const o=`${c}/hub/permissions?vault=${encodeURIComponent(u)}`;return i.jsxs("li",{children:[i.jsx("a",{href:o,children:"Permissions →"}),i.jsxs("span",{className:"dim",children:[" ","grants are managed on hub (the OAuth issuer); link will be live when hub ships its permissions UI."]})]})}const M0=[{value:"events",label:"On change (default)"},{value:"manual",label:"Manual only"}],O0=[{id:"history",label:"History",subtext:"Local audit trail. Hidden under vault data. Events-driven.",apply:u=>({...u,enabled:!0,location:"internal",sync_mode:"events",auto_commit:!0,auto_push:!1})},{id:"live",label:"External folder mirror",subtext:"Visible folder. Open in Obsidian, push to GitHub. Events-driven.",apply:u=>({...u,enabled:!0,location:"external",sync_mode:"events",auto_commit:!0})},{id:"manual",label:"Manual Export",subtext:"Snapshot on demand. No auto-fire.",apply:u=>({...u,enabled:!0,location:"external",sync_mode:"manual",auto_commit:!0,auto_push:!1})}];function $h({vaultName:u}={}){const c=_u(),o=u??c.name,r=u!==void 0,d=r?"/":`/vault/${encodeURIComponent(o??"")}`,[h,g]=y.useState({kind:"loading"}),[S,x]=y.useState(0);y.useEffect(()=>{let E=!1;if(o)return g({kind:"loading"}),n0(o).then(v=>{E||g({kind:"ok",snapshot:v})}).catch(v=>{if(E)return;if(v instanceof pe&&(v.status===401||v.status===403)){g({kind:"auth-required",status:v.status});return}const C=v instanceof Error?v.message:String(v);g({kind:"error",message:C})}),()=>{E=!0}},[o,S]);const p=y.useCallback(()=>x(E=>E+1),[]);return o?i.jsxs("div",{children:[i.jsxs("div",{className:"list-header",children:[i.jsxs("h2",{children:["Backup for ",i.jsx("code",{children:o})]}),i.jsx(Ze,{to:d,className:"muted",children:"← Vault detail"})]}),h.kind==="loading"?i.jsx("p",{className:"muted",children:"Loading…"}):null,h.kind==="auth-required"?i.jsx(Zl,{vaultName:o,status:h.status,onRecovered:p}):null,h.kind==="error"?i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:h.message})}):null,h.kind==="ok"?i.jsx(D0,{vaultName:o,snapshot:h.snapshot,onRefresh:()=>x(E=>E+1),onSnapshot:E=>g({kind:"ok",snapshot:E})}):null]}):i.jsxs("div",{children:[i.jsx("h2",{children:"Mirror"}),i.jsx("p",{className:"muted",children:"Missing vault name."}),r?null:i.jsx(Ze,{to:"/",children:"← Back to vaults"})]})}function D0({vaultName:u,snapshot:c,onRefresh:o,onSnapshot:r}){const d=Er(u),[h,g]=y.useState(null),[S,x]=y.useState(null);y.useEffect(()=>{if(!d)return;let v=!1;return jr(u).then(C=>{v||g(C)}).catch(C=>{v||x(C instanceof Error?C.message:String(C))}),()=>{v=!0}},[u,d]);const[p,E]=y.useState(!1);return i.jsxs(i.Fragment,{children:[i.jsx(U0,{status:c.status,config:c.config,creds:h}),d?null:i.jsxs("div",{className:"warn-banner",children:["You're viewing this page with a read-only token. Saving config + manual run require ",i.jsxs("code",{children:["vault:",u,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin-scoped session to make changes.`]}),d?i.jsx(L0,{vaultName:u,creds:h,credsError:S,onCredsChanged:g,onCredsSaved:()=>{o()},onConfigChanged:o,locationIsExternal:c.config.location==="external"}):null,i.jsxs("div",{className:"section",children:[i.jsx("button",{type:"button",className:"secondary",onClick:()=>E(v=>!v),"aria-expanded":p,children:p?"Hide advanced settings":"Advanced settings"}),p?null:i.jsx("p",{className:"dim",style:{margin:"0.6rem 0 0"},children:"Manual exports, run-now, an external (Obsidian-visible) mirror folder, commit settings, and import-from-a-repo. Most owners never need these."})]}),p?i.jsxs(i.Fragment,{children:[i.jsx(H0,{status:c.status,config:c.config,creds:h,canRun:d&&c.status.enabled,vaultName:u,onSnapshot:r}),i.jsx(B0,{vaultName:u,initial:c.config,readOnly:!d,creds:h,onSaved:v=>{r(v),o()}}),d?i.jsx(Z0,{vaultName:u,creds:h}):null]}):null]})}function U0({status:u,config:c,creds:o}){var g;if(!c.enabled)return i.jsxs("div",{className:"warn-banner",role:"status",children:[i.jsx("strong",{children:"Version history is off."})," This vault isn't saving a local history of changes right now. Open ",i.jsx("strong",{children:"Advanced settings"})," ","below to turn it back on."]});const r=!!(o!=null&&o.active_method),d=c.auto_push&&r,h=(o==null?void 0:o.active_method)==="github_oauth"?(g=o.github_oauth)==null?void 0:g.user_login:void 0;return i.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"1rem"},children:[d?i.jsxs(i.Fragment,{children:[i.jsx("strong",{children:"✓ Version history + backed up off this machine."})," ",h?i.jsxs(i.Fragment,{children:["Every change is saved locally and pushed to GitHub as"," ",i.jsxs("code",{children:["@",h]}),"."]}):i.jsx(i.Fragment,{children:"Every change is saved locally and pushed to your git remote automatically."})]}):i.jsxs(i.Fragment,{children:[i.jsx("strong",{children:"✓ Version history — on."})," Your vault automatically saves a full local history of every change. Want an off-machine copy too? Use ",i.jsx("strong",{children:"Back up to GitHub"})," below."]}),u.last_error?i.jsxs("p",{className:"dim",style:{margin:"0.5rem 0 0"},children:["Heads up — the last backup pass reported an error. See"," ",i.jsx("strong",{children:"Advanced settings"})," below for details."]}):null]})}function H0({status:u,config:c,creds:o,canRun:r,vaultName:d,onSnapshot:h}){const g=c.enabled,[S,x]=y.useState(!1),[p,E]=y.useState(!1),[v,C]=y.useState(null),V=async()=>{x(!0),C(null);try{const q=await l0(d);h(q)}catch(q){C(q instanceof Error?q.message:String(q))}finally{x(!1)}},D=async()=>{E(!0),C(null);try{const q=await a0(d);h(q)}catch(q){C(q instanceof Error?q.message:String(q))}finally{E(!1)}},k=!!(o!=null&&o.active_method)||c.auto_push,H=!r||p||!k;return i.jsxs("div",{className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Status"}),i.jsxs("div",{className:"kv",children:[i.jsx("div",{children:"Enabled"}),i.jsx("div",{children:g?i.jsx("code",{children:"yes"}):i.jsx("code",{children:"no"})}),i.jsx("div",{children:"Watch loop"}),i.jsx("div",{children:u.watch_running?i.jsx("code",{children:"running"}):i.jsx("code",{children:"stopped"})}),i.jsx("div",{children:"Path"}),i.jsx("div",{children:u.mirror_path?i.jsx("code",{children:u.mirror_path}):i.jsx("span",{className:"dim",children:"—"})}),i.jsx("div",{children:"Last export"}),i.jsx("div",{children:u.last_export_at?i.jsxs(i.Fragment,{children:[i.jsx("code",{children:u.last_export_at}),u.last_export_notes_count!==null?i.jsxs("span",{className:"dim",children:[" ","· ",u.last_export_notes_count," note",u.last_export_notes_count===1?"":"s"]}):null]}):i.jsx("span",{className:"dim",children:"never"})}),i.jsx("div",{children:"Last commit"}),i.jsx("div",{children:u.last_commit_sha?i.jsx("code",{children:u.last_commit_sha.slice(0,10)}):i.jsx("span",{className:"dim",children:"—"})}),i.jsx("div",{children:"Last push"}),i.jsx("div",{children:u.last_push_at?i.jsxs(i.Fragment,{children:[i.jsx("code",{children:u.last_push_at}),u.last_push_sha?i.jsxs("span",{className:"dim",children:[" ","· ",i.jsx("code",{children:u.last_push_sha.slice(0,10)})]}):null]}):i.jsx("span",{className:"dim",children:"never"})}),u.commits_unpushed!==null&&u.commits_unpushed>0?i.jsxs(i.Fragment,{children:[i.jsx("div",{}),i.jsxs("div",{className:"dim",children:[u.commits_unpushed," commit",u.commits_unpushed===1?"":"s"," ready to push"]})]}):null]}),u.last_push_error?i.jsxs("div",{className:"error-banner",style:{marginTop:"1rem"},children:[i.jsx("strong",{children:"Last push failed:"})," ",i.jsx("code",{children:u.last_push_error})]}):null,u.last_error?i.jsxs("div",{className:"error-banner",style:{marginTop:"1rem"},children:[i.jsx("strong",{children:"Last error:"})," ",i.jsx("code",{children:u.last_error})]}):null,v?i.jsx("div",{className:"error-banner",style:{marginTop:"1rem"},children:i.jsx("code",{children:v})}):null,i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:V,disabled:!r||S,title:g?r?void 0:"Admin scope required to trigger a manual export.":"Enable the mirror first, then trigger a manual export.",children:S?"Running…":"Run export now"}),i.jsx("button",{type:"button",className:"secondary",onClick:D,disabled:H,title:g?r?k?void 0:"Wire credentials or turn on auto-push to push to a remote.":"Admin scope required to push.":"Enable the mirror first, then push.",children:p?"Pushing…":"Push now"})]})]})}function B0({vaultName:u,initial:c,readOnly:o,creds:r,onSaved:d}){const[h,g]=y.useState(c),[S,x]=y.useState(!1),[p,E]=y.useState(!1),[v,C]=y.useState(null),[V,D]=y.useState(null),[k,H]=y.useState(0);y.useEffect(()=>{g(c)},[c]);const q=z=>{const Z=z.apply(h);g(Z)},F=z=>{g(Z=>({...Z,sync_mode:z}))},B=async z=>{if(z.preventDefault(),!o){E(!0),C(null),D(null);try{const Z=await Nm(u,h);d(Z),H(K=>K+1),setTimeout(()=>H(0),3e3)}catch(Z){if(Z instanceof pe){const K=Z.message;C(K);const X=K.toLowerCase();X.includes("external_path")?D("external_path"):X.includes("commit_template")?D("commit_template"):X.includes("safety_net_seconds")?D("safety_net_seconds"):X.includes("sync_mode")?D("sync_mode"):X.includes("auto_push")?D("auto_push"):X.includes("location")?D("location"):D(null)}else C(Z instanceof Error?Z.message:String(Z))}finally{E(!1)}}};return i.jsxs("form",{className:"section",onSubmit:B,children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Configuration"}),i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:[i.jsx("input",{type:"checkbox",checked:h.enabled,disabled:o,onChange:z=>g(Z=>({...Z,enabled:z.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Enable mirror"]}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"Master switch. When off, no export / commit / push runs."})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{children:"Presets"}),i.jsxs("p",{className:"dim",style:{marginTop:0,marginBottom:"0.5rem",fontSize:"0.9em"},children:[i.jsx("strong",{children:"History"})," is the default every vault ships with — vault manages the history folder under its own data dir, no path to pick, no remote to configure. ",i.jsx("strong",{children:"External folder mirror"})," +"," ",i.jsx("strong",{children:"Manual Export"})," are for operators who want to point at a visible folder (Obsidian, GitHub)."]}),i.jsx("div",{className:"preset-grid",children:O0.map(z=>i.jsxs("button",{type:"button",className:"preset-card",disabled:o,onClick:()=>q(z),"aria-label":`Apply ${z.label} preset`,children:[i.jsx("strong",{children:z.label}),i.jsx("span",{className:"dim",children:z.subtext})]},z.id))})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{children:"Location"}),i.jsxs("div",{children:[i.jsxs("label",{className:"radio-row",children:[i.jsx("input",{type:"radio",name:"location",value:"internal",checked:h.location==="internal",disabled:o,onChange:()=>g(z=>({...z,location:"internal"}))}),i.jsxs("span",{children:["Internal ",i.jsx("span",{className:"dim",children:"— hidden under vault data dir"})]})]}),i.jsxs("label",{className:"radio-row",children:[i.jsx("input",{type:"radio",name:"location",value:"external",checked:h.location==="external",disabled:o,onChange:()=>g(z=>({...z,location:"external"}))}),i.jsxs("span",{children:["External ",i.jsx("span",{className:"dim",children:"— operator-picked path"})]})]})]})]}),h.location==="external"?i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"external-path",children:"External path"}),i.jsx("input",{id:"external-path",type:"text",value:h.external_path??"",disabled:o,onChange:z=>g(Z=>({...Z,external_path:z.target.value.length>0?z.target.value:null})),placeholder:"/Users/you/Documents/vault-mirror","aria-invalid":V==="external_path"}),i.jsxs("div",{className:"warn-banner",style:{marginTop:"0.5rem"},role:"alert",children:["Path must exist AND be a git repo (run ",i.jsx("code",{children:"git init"})," first if needed)."]})]}):null,i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"sync-mode-select",children:"Sync mode"}),i.jsx("select",{id:"sync-mode-select",value:h.sync_mode,disabled:o,onChange:z=>F(z.target.value),children:M0.map(z=>i.jsx("option",{value:z.value,children:z.label},z.value))}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:h.sync_mode==="manual"?'No auto-fire. Exports only run when you click "Run export now" (or run `parachute-vault export` from the CLI).':"Every change to a note, tag, or attachment triggers an export within ~500ms. A background safety check runs hourly to catch anything missed."})]}),i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:[i.jsx("input",{type:"checkbox",checked:h.auto_commit,disabled:o,onChange:z=>g(Z=>({...Z,auto_commit:z.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Commit after each export"]}),h.auto_commit?null:i.jsx("p",{className:"hint",style:{marginTop:"0.25rem",fontSize:"0.85em"},children:"Note: the export cursor still advances after each pass. Subsequent runs only re-export notes written since the last pass — even when triggered manually."})]}),h.location==="external"||r!=null&&r.active_method?i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:[i.jsx("input",{type:"checkbox",checked:h.auto_push,disabled:o,onChange:z=>g(Z=>({...Z,auto_push:z.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Push after each commit"]}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.9em"},children:"When credentials are configured, vault can push the mirror's commits to your remote regardless of whether the mirror folder lives under vault's data dir or somewhere visible."}),h.auto_push?r!=null&&r.active_method?i.jsxs("div",{className:"info-banner",style:{marginTop:"0.5rem"},role:"status",children:[r.active_method==="github_oauth"&&r.github_oauth?i.jsxs(i.Fragment,{children:["Will push to ",i.jsxs("code",{children:["@",r.github_oauth.user_login]})," on GitHub."]}):r.active_method==="pat"&&r.pat?i.jsxs(i.Fragment,{children:["Will push using saved credential: ",i.jsx("code",{children:r.pat.label}),"."]}):i.jsx(i.Fragment,{children:"Will push using saved credential."})," ","Failed pushes are logged but won't crash the export."]}):i.jsxs("div",{className:"warn-banner",style:{marginTop:"0.5rem"},role:"alert",children:["Auto-push needs git credentials. Either connect GitHub in the"," ",i.jsx("strong",{children:"Back up to GitHub"})," section above, or paste a Personal Access Token + remote URL there. Failed pushes are logged but won't crash the export."]}):null]}):null,i.jsx("div",{className:"form-row",children:i.jsxs("button",{type:"button",className:"secondary",onClick:()=>x(z=>!z),children:[S?"Hide":"Show"," advanced"]})}),S?i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"commit-template",children:"Commit template"}),i.jsx("input",{id:"commit-template",type:"text",value:h.commit_template,disabled:o,onChange:z=>g(Z=>({...Z,commit_template:z.target.value})),"aria-invalid":V==="commit_template"}),i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Supports ",i.jsx("code",{children:"{{date}}"}),", ",i.jsx("code",{children:"{{notes_changed}}"}),","," ",i.jsx("code",{children:"{{plural}}"}),", ",i.jsx("code",{children:"{{first_note_title}}"}),","," ",i.jsx("code",{children:"{{vault_name}}"}),"."]})]}):null,v?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:v})}):null,k>0?i.jsx("div",{className:"mint-banner",style:{padding:"0.75rem 1rem",marginBottom:"1rem"},role:"status",children:"Saved."}):null,i.jsx("div",{className:"actions",children:i.jsx("button",{type:"submit",disabled:o||p,children:p?"Saving…":"Save"})})]})}function L0({vaultName:u,creds:c,credsError:o,onCredsChanged:r,onCredsSaved:d,onConfigChanged:h,locationIsExternal:g}){var ye;const[S,x]=y.useState(!1),[p,E]=y.useState(!1),[v,C]=y.useState(!1),[V,D]=y.useState(!1),[k,H]=y.useState(null),[q,F]=y.useState(null),[B,z]=y.useState(null),[Z,K]=y.useState(!1),[X,ee]=y.useState(null),[ce,ze]=y.useState(null),[Oe,De]=y.useState(0),Ce=(c==null?void 0:c.active_method)==="github_oauth"&&!!c.github_oauth;y.useEffect(()=>{if(!Ce){ee(null),ze(null);return}let $=!1;return wm(u).then(j=>{$||(ee(j),ze(null))}).catch(j=>{$||ze(j instanceof Error?j.message:String(j))}),()=>{$=!0}},[u,Ce,Oe]);const I=()=>De($=>$+1),ie=(c==null?void 0:c.active_method)!==null&&(c==null?void 0:c.active_method)!==void 0,M=async()=>{if(confirm("Disconnect git remote credentials? Auto-push will stop working until you reconnect.")){D(!0),H(null);try{const $=await i0(u);r($),z(null)}catch($){H($ instanceof Error?$.message:String($))}finally{D(!1)}}},J=async()=>{K(!0),H(null);try{await Nm(u,{enabled:!0}),z(!0),h()}catch($){H($ instanceof Error?$.message:String($))}finally{K(!1)}},ne=()=>{x(!1),jr(u).then($=>r($)).catch(()=>{})};return i.jsxs("div",{className:"section",id:"git-remote-section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:ie?"Backed up to a git remote":"Back up to GitHub"}),i.jsx("p",{className:"dim",style:{marginTop:0},children:ie?i.jsxs(i.Fragment,{children:["Your vault pushes its history to an off-machine git remote. Credentials are stored on this server with ",i.jsx("code",{children:"0600"})," file permissions — never sent to GitHub or any third party."]}):i.jsxs(i.Fragment,{children:["Keep an off-machine copy: push your vault's history to GitHub (or any HTTPS git host). Credentials are stored on this server with"," ",i.jsx("code",{children:"0600"})," file permissions, never sent to a third party."]})}),!g&&!(c!=null&&c.active_method)?i.jsx("div",{className:"info-banner",style:{marginBottom:"0.75rem"},role:"status",children:"Internal mirrors live under the vault's data directory. To push them to a remote, paste a Personal Access Token + remote URL below — that wires the remote and turns on auto-push automatically."}):null,o?i.jsxs("div",{className:"error-banner",role:"alert",children:["Could not load credential status: ",i.jsx("code",{children:o})]}):null,ie?i.jsxs("div",{className:"kv",style:{marginBottom:"0.75rem"},children:[i.jsx("div",{children:"Status"}),i.jsx("div",{children:(c==null?void 0:c.active_method)==="github_oauth"&&c.github_oauth?i.jsxs(i.Fragment,{children:["Connected to ",i.jsxs("code",{children:["@",c.github_oauth.user_login]})," on GitHub"]}):(c==null?void 0:c.active_method)==="pat"&&c.pat?i.jsxs(i.Fragment,{children:["Custom credential: ",i.jsx("code",{children:c.pat.label})]}):null}),(c==null?void 0:c.active_method)==="github_oauth"&&c.github_oauth?i.jsxs(i.Fragment,{children:[i.jsx("div",{children:"Token"}),i.jsxs("div",{children:[i.jsx("code",{children:c.github_oauth.token_preview})," ",i.jsxs("span",{className:"dim",children:["· scope ",c.github_oauth.scope||"—"," · authorized"," ",c.github_oauth.authorized_at.slice(0,10)]})]})]}):null,(c==null?void 0:c.active_method)==="pat"&&c.pat?i.jsxs(i.Fragment,{children:[i.jsx("div",{children:"Remote"}),i.jsx("div",{children:i.jsx("code",{children:c.pat.remote_url})}),i.jsx("div",{children:"Token"}),i.jsx("div",{children:i.jsx("code",{children:c.pat.token_preview})})]}):null]}):i.jsx("p",{className:"dim",children:"Not connected. Auto-push won't work until you connect. Personal Access Token is the universal path (works with GitHub, GitLab, Gitea, Bitbucket, anything that takes an HTTPS token); the GitHub shortcut just saves a step for GitHub users."}),Ce&&ce?i.jsxs("div",{className:"warn-banner",role:"alert",style:{marginBottom:"0.75rem"},children:["Couldn't check the GitHub App install state:"," ",i.jsx("code",{children:ce})," ",i.jsx("button",{type:"button",className:"secondary",onClick:I,children:"Retry"})]}):null,Ce&&!X&&!ce?i.jsx("p",{className:"dim",children:"Checking GitHub App installation…"}):null,Ce&&X&&!X.installed?i.jsx(Mm,{install:X,onRecheck:I}):null,Ce&&X&&X.installed?i.jsxs("div",{style:{marginBottom:"0.75rem"},children:[i.jsxs("div",{className:"kv",style:{marginBottom:"0.75rem"},children:[i.jsx("div",{children:"App installed on"}),i.jsx("div",{children:X.installations.map($=>i.jsxs("div",{children:[i.jsx("code",{children:$.account_login})," ",i.jsxs("span",{className:"dim",children:["(",$.account_type==="Organization"?"organization":"user"," ·"," ",$.repository_selection==="selected"?"Selected repos only":"All repos",")"]})]},$.id))})]}),i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:()=>E(!0),children:"Choose repository…"}),i.jsx("a",{href:X.install_url,target:"_blank",rel:"noreferrer",className:"dim",style:{alignSelf:"center"},children:"Install on another account or org →"})]})]}):null,k?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:k})}):null,B===!0?i.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"0.75rem"},children:[i.jsx("strong",{children:"History is on ✓"})," — this vault keeps a local git history of every change, ready to push once a repository is wired."," ",i.jsx("button",{type:"button",className:"secondary",onClick:()=>z(null),"aria-label":"Dismiss history note",children:"Dismiss"})]}):null,B==="left_disabled"?i.jsxs("div",{className:"info-banner",role:"status",style:{marginBottom:"0.75rem"},children:[i.jsx("strong",{children:"Version history is still off for this vault"})," (it was switched off earlier, so we didn't flip it behind your back). Backups push the vault's history — turn it on to start recording changes."," ",i.jsx("button",{type:"button",onClick:J,disabled:Z,children:Z?"Turning on…":"Turn on history now"})]}):null,B===!1?i.jsxs("div",{className:"warn-banner",role:"alert",style:{marginBottom:"0.75rem"},children:["We tried to turn on version history for this vault but it didn't start — see ",i.jsx("strong",{children:"Advanced settings → Status"})," for the error."]}):null,q?i.jsxs("div",{className:"mint-banner",style:{marginBottom:"0.75rem"},role:"status",children:[i.jsx("strong",{children:"Credentials saved."})," ",(()=>{const $=q,j=$.initial_push.fired&&$.initial_push.pushed?$.initial_push.sha:void 0,N=$.initial_push.fired&&!$.initial_push.pushed?$.initial_push.error:void 0;return $.auto_push_was_already_enabled?j?i.jsxs(i.Fragment,{children:["Auto-push was already on; just pushed"," ",i.jsx("code",{children:j.slice(0,10)}),"."]}):N?i.jsx(i.Fragment,{children:"Auto-push was already on; the push attempt failed — see Advanced settings → Status for details."}):i.jsx(i.Fragment,{children:"Auto-push was already on; nothing to push right now."}):$.auto_push_enabled?j?i.jsxs(i.Fragment,{children:["Auto-push enabled and the first push landed"," ",i.jsx("code",{children:j.slice(0,10)}),". Your next commit will push to the remote too."]}):N?i.jsx(i.Fragment,{children:"Auto-push enabled. The initial push attempt failed — see Advanced settings → Status for the error."}):i.jsx(i.Fragment,{children:"Auto-push enabled. Your next commit will push to the remote."}):i.jsx(i.Fragment,{children:"Credentials wired. Auto-push remains off; flip it on in Advanced settings → Configuration to push commits automatically."})})()," ",i.jsx("button",{type:"button",className:"secondary",onClick:()=>F(null),style:{marginLeft:"0.5rem"},"aria-label":"Dismiss",children:"Dismiss"})]}):null,i.jsx("div",{className:"actions",children:ie?i.jsx("button",{type:"button",className:"secondary",onClick:M,disabled:V,children:V?"Disconnecting…":"Disconnect"}):i.jsxs(i.Fragment,{children:[i.jsx("button",{type:"button",onClick:()=>C(!0),children:"Use Personal Access Token"}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>x(!0),children:"Connect GitHub (one-click for GitHub users)"})]})}),i.jsx(q0,{install:X}),S?i.jsx(Fh,{vaultName:u,mode:"connect",onClose:ne,onHistory:z,onConnected:($,j)=>{r($),j&&(F(j),d(j)),x(!1)}}):null,p&&Ce?i.jsx(Fh,{vaultName:u,mode:"choose-repo",initialLogin:((ye=c==null?void 0:c.github_oauth)==null?void 0:ye.user_login)??"",onClose:()=>E(!1),onHistory:z,onConnected:($,j)=>{r($),j&&(F(j),d(j)),E(!1)}}):null,v?i.jsx(Q0,{vaultName:u,onClose:()=>C(!1),onSaved:$=>{r($),F($),z($.history_enabled),d($),C(!1)}}):null]})}function Mm({install:u,onRecheck:c}){return i.jsxs("div",{className:"info-banner",role:"status",style:{marginBottom:"0.75rem"},children:[i.jsxs("p",{style:{marginTop:0},children:[i.jsx("strong",{children:"Authorized ✓ — one step left: install the app so it can reach your repos."})," ","Authorizing told GitHub who you are; installing picks which repositories the app may touch. Until then it can't see any of your private repos."]}),i.jsxs("div",{className:"actions",style:{marginBottom:"0.5rem"},children:[i.jsx("a",{href:u.install_url,target:"_blank",rel:"noreferrer",style:{fontWeight:600},children:"Install on GitHub →"}),i.jsx("button",{type:"button",className:"secondary",onClick:c,children:"I've installed it — check again"})]}),i.jsx("p",{className:"dim",style:{marginBottom:0,fontSize:"0.9em"},children:"Keeping vaults in an organization? Install the app on that org too — the same install link works for every account, as many times as you need."})]})}function q0({install:u}){const[c,o]=y.useState(!1);return i.jsxs("div",{style:{marginTop:"1rem"},children:[i.jsxs("p",{className:"dim",style:{marginBottom:"0.5rem",fontSize:"0.9em"},children:[u?u.app.is_shared_default?i.jsxs(i.Fragment,{children:["Using the shared Parachute GitHub App (",i.jsx("code",{children:u.app.slug}),")."]}):i.jsxs(i.Fragment,{children:["Using your own GitHub App (",i.jsx("code",{children:u.app.slug}),")."]}):i.jsx(i.Fragment,{children:'"Connect GitHub" uses the shared Parachute GitHub App by default.'})," ",i.jsx("button",{type:"button",className:"secondary",onClick:()=>o(r=>!r),"aria-expanded":c,children:c?"Hide":"Use your own GitHub App"})]}),c?i.jsxs("div",{className:"info-banner",role:"note",children:[i.jsx("p",{style:{marginTop:0},children:"You don't have to trust the shared app: register your own GitHub App and point this vault at it. Your tokens are then minted by an app only you control — your own rate-limit budget, your own blast radius. Taking responsibility for your own data is the point of self-hosting; this makes it one form away."}),i.jsxs("p",{style:{marginBottom:"0.35rem"},children:[i.jsx("strong",{children:"Register the app"})," (GitHub → Settings → Developer settings → GitHub Apps → New GitHub App):"]}),i.jsxs("ul",{style:{marginTop:0},children:[i.jsxs("li",{children:["Repository permissions: ",i.jsx("strong",{children:"Contents — Read and write"}),". Nothing else."]}),i.jsxs("li",{children:[i.jsx("strong",{children:"Enable Device Flow"}),' (checkbox under "Identifying and authorizing users").']}),i.jsxs("li",{children:[i.jsx("strong",{children:'Uncheck "Expire user authorization tokens"'})," — an unattended backup daemon can't babysit 8-hour tokens."]}),i.jsx("li",{children:"Webhook: inactive. Callback URL: anything (device flow ignores it)."}),i.jsxs("li",{children:[i.jsx("strong",{children:"Don't generate a private key"})," — Parachute never uses one, and an app with no key can't mint installation tokens behind your back. We recommend against creating one at all."]})]}),i.jsxs("p",{style:{marginBottom:"0.35rem"},children:[i.jsx("strong",{children:"Point this vault at it"})," — set both env vars as a pair in the vault's ",i.jsx("code",{children:".env"}),", then restart the vault:"]}),i.jsx("pre",{style:{margin:"0 0 0.5rem"},children:i.jsx("code",{children:`PARACHUTE_GITHUB_CLIENT_ID=<your app's client ID>
61
- PARACHUTE_GITHUB_APP_SLUG=<your app's URL slug>`})}),i.jsx("p",{className:"dim",style:{marginBottom:0,fontSize:"0.9em"},children:"Both together — the client ID mints the tokens, the slug builds the install link; mixing apps breaks the connect flow. Then disconnect and reconnect GitHub here to mint tokens from your app."})]}):null]})}function Fh({vaultName:u,mode:c,initialLogin:o,onClose:r,onConnected:d,onHistory:h}){const[g,S]=y.useState(c==="choose-repo"?{kind:"probing",user:{login:o??""}}:{kind:"starting"}),[x,p]=y.useState(Date.now()),E=y.useRef(!1),v=g.kind==="polling";y.useEffect(()=>{if(!v)return;const k=setInterval(()=>p(Date.now()),1e3);return()=>clearInterval(k)},[v]),y.useEffect(()=>()=>{E.current=!0},[]),y.useEffect(()=>{if(g.kind!=="starting")return;let k=!1;return u0(u).then(H=>{k||S({kind:"polling",code:H,pollIntervalMs:Math.max(H.interval,1)*1e3,startedAt:Date.now()})}).catch(H=>{k||S({kind:"error",message:H instanceof Error?H.message:String(H)})}),()=>{k=!0}},[g.kind,u]),y.useEffect(()=>{if(g.kind!=="polling")return;E.current=!1;const k=g.code;let H=!1,q=null,F=g.pollIntervalMs;const B=async()=>{if(!(H||E.current))try{const z=await s0(u,k.polling_id);if(H)return;if(z.state==="granted"){h(z.history_enabled),S({kind:"probing",user:{login:z.user.login}});return}if(z.state==="denied"){S({kind:"error",message:"Authorization denied."});return}if(z.state==="expired"){S({kind:"error",message:"The device code expired. Try again."});return}z.state==="slow_down"&&(F=z.interval*1e3),q=setTimeout(B,F)}catch(z){if(H)return;S({kind:"error",message:z instanceof Error?z.message:String(z)})}};return q=setTimeout(B,F),()=>{H=!0,q&&clearTimeout(q)}},[g,u,h]),y.useEffect(()=>{if(g.kind!=="probing")return;const k=g.user;let H=!1;return wm(u).then(q=>{H||S(q.installed?{kind:"picker",user:k,install:q}:{kind:"install-needed",user:k,install:q})}).catch(q=>{H||S({kind:"error",message:q instanceof Error?q.message:String(q)})}),()=>{H=!0}},[g,u]);const C=y.useCallback(k=>S({kind:"error",message:k}),[]),V=y.useCallback(()=>{S(k=>k.kind==="picker"?{kind:"probing",user:k.user}:k)},[]),D=async k=>{try{await navigator.clipboard.writeText(k)}catch{}};return i.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:i.jsxs("div",{className:"modal",children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:c==="choose-repo"?"Choose a repository":"Connect GitHub"}),i.jsx("button",{type:"button",className:"secondary",onClick:r,children:"Close"})]}),g.kind==="starting"?i.jsx("p",{className:"muted",children:"Requesting device code from GitHub…"}):null,g.kind==="polling"?i.jsxs(i.Fragment,{children:[i.jsxs("p",{children:[i.jsx("strong",{children:"Step 1."})," Open"," ",i.jsx("a",{href:g.code.verification_uri,target:"_blank",rel:"noreferrer",children:g.code.verification_uri})," ","in your browser."]}),i.jsxs("p",{children:[i.jsx("strong",{children:"Step 2."})," Enter this code:"]}),i.jsxs("div",{className:"device-code-row",children:[i.jsx("code",{className:"device-code",children:g.code.user_code}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>D(g.code.user_code),children:"Copy"})]}),i.jsxs("p",{className:"dim",children:["Waiting for authorization…"," ",G0(g.code.expires_in,g.startedAt,x)]})]}):null,g.kind==="probing"?i.jsx("p",{className:"muted",children:"Checking where the app is installed…"}):null,g.kind==="install-needed"?i.jsx(Mm,{install:g.install,onRecheck:()=>S({kind:"probing",user:g.user})}):null,g.kind==="picker"?i.jsx(V0,{vaultName:u,user:g.user,install:g.install,onPicked:async(k,H)=>{const q=await o0(u,{owner:k,name:H});h(q.history_enabled);const F=await jr(u);d(F,q)},onError:C,onNotInstalled:V}):null,g.kind==="error"?i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:g.message})}),i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:()=>S(c==="choose-repo"?{kind:"probing",user:{login:o??""}}:{kind:"starting"}),children:"Try again"}),i.jsx("button",{type:"button",className:"secondary",onClick:r,children:"Close"})]})]}):null]})})}function G0(u,c,o){const r=Math.floor((o-c)/1e3),d=Math.max(0,u-r),h=Math.floor(d/60),g=d%60;return`${h}:${String(g).padStart(2,"0")} remaining`}function Y0(u){return u.account_type==="Organization"?`https://github.com/organizations/${encodeURIComponent(u.account_login)}/settings/installations/${u.id}`:`https://github.com/settings/installations/${u.id}`}function V0({vaultName:u,user:c,install:o,onPicked:r,onError:d,onNotInstalled:h}){const[g,S]=y.useState(null),[x,p]=y.useState(!1),[E,v]=y.useState(""),[C,V]=y.useState(null),[D,k]=y.useState(!1),[H,q]=y.useState(""),[F,B]=y.useState(!1),[z,Z]=y.useState(!1),[K,X]=y.useState(0);y.useEffect(()=>{let I=!1;return S(null),Cm(u).then(ie=>{if(!I){if(!ie.installed){h();return}S(ie.repos),p(!!ie.truncated)}}).catch(ie=>{I||d(ie instanceof Error?ie.message:String(ie))}),()=>{I=!0}},[u,d,h,K]);const ee=(g??[]).filter(I=>E.length===0?!0:I.full_name.toLowerCase().includes(E.toLowerCase())),ce=[];for(const I of ee){const ie=ce[ce.length-1];if(ie&&ie.login===I.account_login)ie.repos.push(I);else{const M=ce.find(J=>J.login===I.account_login);M?M.repos.push(I):ce.push({login:I.account_login,repos:[I]})}}const ze=I=>o.installations.find(ie=>ie.account_login===I),Oe=async(I,ie)=>{V(`${I}/${ie}`);try{await r(I,ie)}catch(M){d(M instanceof Error?M.message:String(M))}finally{V(null)}},De=async()=>{if(H.trim().length!==0){k(!0);try{const I=await r0(u,{name:H.trim(),description:"Parachute Vault mirror",private:!0});await r(I.owner,I.name)}catch(I){I instanceof pe&&I.errorType==="app_lacks_admin_permission"?Z(!0):d(I instanceof Error?I.message:String(I))}finally{k(!1)}}},Ce=o.app.is_shared_default||z;return i.jsxs(i.Fragment,{children:[i.jsxs("p",{children:["Authorized as ",i.jsxs("code",{children:["@",c.login]}),". Pick a repository to push the mirror to:"]}),i.jsx("div",{className:"form-row",children:i.jsx("input",{type:"search",placeholder:"Filter by name…",value:E,onChange:I=>v(I.target.value)})}),x?i.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos per account. Use the filter above to narrow down — or paste the clone URL directly via Personal Access Token if your repo isn't here."}):null,g===null?i.jsx("p",{className:"muted",children:"Loading repos…"}):null,g!==null?i.jsxs("div",{className:"repo-list",children:[ee.length===0&&E.length>0?i.jsxs("p",{className:"dim",children:['No repos match "',E,'".']}):null,ee.length===0&&E.length===0&&g.length===0?i.jsx("p",{className:"dim",children:`The app installation doesn't include any repos yet — pick some via "Change repo access on GitHub" below, then refresh.`}):null,ce.map(I=>{const ie=ze(I.login);return i.jsxs("div",{children:[i.jsxs("p",{className:"dim",style:{margin:"0.5rem 0 0.25rem"},children:[i.jsx("strong",{children:I.login}),ie?i.jsxs(i.Fragment,{children:[" ","·"," ",ie.account_type==="Organization"?"organization":"user"," ","·"," ",ie.repository_selection==="selected"?"Selected repos only":"All repos"]}):null]}),I.repos.map(M=>i.jsxs("button",{type:"button",className:"repo-row",onClick:()=>Oe(M.owner,M.name),disabled:C!==null,children:[i.jsxs("span",{children:[i.jsx("strong",{children:M.name}),M.private?i.jsx("span",{className:"dim",children:" · private"}):null]}),i.jsx("span",{className:"dim",children:M.updated_at.slice(0,10)})]},M.full_name))]},I.login)})]}):null,i.jsxs("div",{className:"actions",style:{marginTop:"0.75rem"},children:[i.jsx("button",{type:"button",className:"secondary",onClick:()=>X(I=>I+1),children:"Refresh list"}),i.jsx("a",{href:o.install_url,target:"_blank",rel:"noreferrer",className:"dim",style:{alignSelf:"center"},children:"Install on another account or org →"})]}),F?i.jsxs("div",{className:"form-row",style:{marginTop:"0.75rem"},children:[i.jsx("label",{htmlFor:"new-repo-name",children:"New repo name"}),i.jsx("input",{id:"new-repo-name",type:"text",value:H,placeholder:"my-vault-backup",onChange:I=>q(I.target.value)}),Ce?i.jsx(X0,{install:o,suggestedName:H.trim(),onRefresh:()=>X(I=>I+1)}):i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:De,disabled:D||H.trim().length===0,children:D?"Creating…":"Create"}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>B(!1),disabled:D,children:"Cancel"})]})]}):i.jsx("div",{className:"actions",style:{marginTop:"0.75rem"},children:i.jsx("button",{type:"button",className:"secondary",onClick:()=>B(!0),children:"+ Create new private repo"})})]})}function X0({install:u,suggestedName:c,onRefresh:o}){const r=c.length>0?`https://github.com/new?name=${encodeURIComponent(c)}`:"https://github.com/new";return i.jsxs("div",{className:"info-banner",role:"note",style:{marginTop:"0.5rem"},children:[i.jsx("p",{style:{marginTop:0},children:u.app.is_shared_default?i.jsxs(i.Fragment,{children:["The Parachute app deliberately can't create repos for you (it only holds the ",i.jsx("em",{children:"Contents"})," permission — creating repos would need admin powers a backup doesn't deserve). Three quick steps instead:"]}):i.jsxs(i.Fragment,{children:["Your GitHub App doesn't have the ",i.jsx("em",{children:"Administration"})," permission needed to create repos. Three quick steps instead:"]})}),i.jsxs("ol",{style:{marginTop:0,marginBottom:"0.5rem"},children:[i.jsxs("li",{children:[i.jsx("a",{href:r,target:"_blank",rel:"noreferrer",children:"Create a new repo on GitHub →"})," ",i.jsx("span",{className:"dim",children:"(private; leave it empty — no README or .gitignore)"})]}),i.jsxs("li",{children:["Add it to the app's repo access:"," ",u.installations.length>0?u.installations.map((d,h)=>i.jsxs("span",{children:[h>0?" · ":null,i.jsxs("a",{href:Y0(d),target:"_blank",rel:"noreferrer",children:["configure on ",d.account_login," →"]})]},d.id)):i.jsx("a",{href:u.install_url,target:"_blank",rel:"noreferrer",children:"install the app →"})," ",i.jsx("span",{className:"dim",children:'(skip if the installation already grants "All repos")'})]}),i.jsxs("li",{children:["Come back and"," ",i.jsx("button",{type:"button",className:"secondary",onClick:o,children:"Refresh list"})," ","— then pick it."]})]})]})}function Q0({vaultName:u,onClose:c,onSaved:o}){const[r,d]=y.useState(""),[h,g]=y.useState(""),[S,x]=y.useState(""),[p,E]=y.useState(!1),[v,C]=y.useState(null),V=async D=>{D.preventDefault(),E(!0),C(null);try{const k=await c0(u,{token:r.trim(),remote_url:h.trim(),label:S.trim()||void 0});o(k)}catch(k){C(k instanceof Error?k.message:String(k))}finally{E(!1)}};return i.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:i.jsxs("div",{className:"modal",children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:"Use Personal Access Token"}),i.jsx("button",{type:"button",className:"secondary",onClick:c,disabled:p,children:"Close"})]}),i.jsxs("p",{className:"dim",children:["Works for any provider that supports HTTPS push with a token in the URL (GitHub, GitLab, Codeberg, Gitea, …). The token is stored with"," ",i.jsx("code",{children:"0600"})," file perms on this server."]}),i.jsxs("form",{onSubmit:V,children:[i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"pat-token",children:"Token"}),i.jsx("input",{id:"pat-token",type:"password",value:r,autoComplete:"off",onChange:D=>d(D.target.value),placeholder:"ghp_… or glpat-… or similar",required:!0})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"pat-url",children:"Remote URL"}),i.jsx("input",{id:"pat-url",type:"url",value:h,onChange:D=>g(D.target.value),placeholder:"https://github.com/owner/repo.git",required:!0}),i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["We'll embed your token in the URL before saving (using GitHub's"," ",i.jsx("code",{children:"x-access-token"})," convention). The URL you see on disk will carry the token; ensure the file isn't shared."]})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"pat-label",children:"Label (optional)"}),i.jsx("input",{id:"pat-label",type:"text",value:S,onChange:D=>x(D.target.value),placeholder:"GitHub PAT for backup"})]}),v?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:v})}):null,i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"submit",disabled:p,children:p?"Validating…":"Validate & save"}),i.jsx("button",{type:"button",className:"secondary",onClick:c,disabled:p,children:"Cancel"})]})]})]})})}function Z0({vaultName:u,creds:c}){const[o,r]=y.useState(""),[d,h]=y.useState("merge"),[g,S]=y.useState(!1),[x,p]=y.useState(""),[E,v]=y.useState(!0),[C,V]=y.useState({kind:"idle"}),[D,k]=y.useState(""),[H,q]=y.useState(!1),F=(c==null?void 0:c.active_method)==="github_oauth"&&c.github_oauth!==null,B=(c==null?void 0:c.active_method)!==null&&(c==null?void 0:c.active_method)!==void 0,z=d!=="replace"||D.trim()===u,Z=C.kind!=="running"&&o.trim().length>0&&z&&(!g||x.trim().length>0),K=async()=>{V({kind:"running",stage:"cloning"});let ee;g?ee={kind:"pat",token:x.trim()}:B?ee=null:ee={kind:"none"};try{const ce=window.setTimeout(()=>V(Oe=>Oe.kind==="running"?{kind:"running",stage:"importing"}:Oe),1500),ze=await f0(u,{remote_url:o.trim(),mode:d,credentials:ee,enable_sync:E});window.clearTimeout(ce),V({kind:"success",result:ze,remoteUrl:o.trim(),mode:d})}catch(ce){const ze=ce instanceof pe?`${ce.status===409?"Already running. ":""}${ce.message}`:ce instanceof Error?ce.message:String(ce);V({kind:"error",message:ze})}},X=()=>{V({kind:"idle"}),k("")};return i.jsxs("div",{className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Import from a git repo"}),i.jsxs("p",{className:"dim",style:{marginTop:0},children:["Pull a vault state from a remote git repo into ",i.jsx("strong",{children:"this"})," vault. Use this to load a vault someone has been mirroring, or to sync a vault between machines you control. The remote must be a Parachute vault export (created by ",i.jsx("code",{children:"parachute-vault export"})," or the mirror's export flow)."]}),i.jsxs("div",{className:"warn-banner",style:{marginBottom:"1rem"},role:"note",children:[i.jsx("strong",{children:"One vault per remote."})," Multiple vaults pushing to the same git repo isn't a supported shape — the last push wins, and vaults that diverge silently overwrite each other. Today's working pattern is one vault per remote. Active two-way sync is a future direction; for now, do exports from one place and imports as snapshots elsewhere."]}),C.kind==="success"?i.jsx(K0,{vaultName:u,result:C.result,remoteUrl:C.remoteUrl,mode:C.mode,onReset:X}):i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"import-remote-url",children:"Remote URL"}),i.jsx("input",{id:"import-remote-url",type:"text",value:o,placeholder:"https://github.com/aaron/my-vault.git",onChange:ee=>r(ee.target.value),disabled:C.kind==="running"}),F?i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.9em"},children:["Or"," ",i.jsx("button",{type:"button",onClick:()=>q(!0),disabled:C.kind==="running",style:{background:"none",border:"none",padding:0,color:"var(--accent)",textDecoration:"underline",cursor:"pointer",fontSize:"inherit"},children:"pick from your GitHub repos"}),"."]}):null,!B&&!g?i.jsx("p",{className:"hint",style:{marginTop:"0.35rem",fontSize:"0.85em"},children:"No saved git credentials. The import will be unauthenticated — works for public repos; private repos will fail with a clear error. Use the one-time credential toggle below if needed."}):null]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{children:"Mode"}),i.jsxs("label",{className:"radio-row",children:[i.jsx("input",{type:"radio",name:"import-mode",value:"merge",checked:d==="merge",onChange:()=>{h("merge"),k("")},disabled:C.kind==="running"}),i.jsxs("span",{children:[i.jsx("strong",{children:"Merge"})," ",i.jsxs("span",{className:"dim",children:["— upsert by id. Notes in the remote get created/updated; any notes that exist only locally ",i.jsx("strong",{children:"survive"}),"."]})]})]}),i.jsxs("label",{className:"radio-row",children:[i.jsx("input",{type:"radio",name:"import-mode",value:"replace",checked:d==="replace",onChange:()=>h("replace"),disabled:C.kind==="running"}),i.jsxs("span",{children:[i.jsx("strong",{children:"Replace"})," ",i.jsxs("span",{className:"dim",children:["— wipe this vault first, then import. The remote becomes the new source of truth. ",i.jsx("strong",{children:"Destructive."})]})]})]})]}),d==="replace"?i.jsxs("div",{className:"form-row",children:[i.jsxs("div",{className:"error-banner",role:"alert",style:{marginBottom:"0.5rem"},children:[i.jsxs("strong",{children:['Replace will delete every note in vault "',u,'" before importing.']})," To confirm, type the vault name below:"]}),i.jsx("input",{id:"import-confirm-name",type:"text",value:D,placeholder:u,onChange:ee=>k(ee.target.value),disabled:C.kind==="running","aria-label":"Type vault name to confirm"})]}):null,i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:[i.jsx("input",{type:"checkbox",checked:g,onChange:ee=>S(ee.target.checked),disabled:C.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"One-time credential for this import only"]}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.85em"},children:"Use a different Personal Access Token just for this clone, without changing your saved credentials."}),g?i.jsx("input",{id:"import-per-call-pat",type:"password",value:x,placeholder:"ghp_… or similar",onChange:ee=>p(ee.target.value),disabled:C.kind==="running",autoComplete:"off",style:{marginTop:"0.5rem"}}):null]}),i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:[i.jsx("input",{type:"checkbox",checked:E,onChange:ee=>v(ee.target.checked),disabled:C.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"Also sync changes back to this repo"]}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.85em"},children:"Pushes future changes to this repo automatically. Uses the access you provide above."})]}),C.kind==="error"?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:C.message})}):null,i.jsx("div",{className:"actions",children:i.jsx("button",{type:"button",onClick:K,disabled:!Z,title:z?o.trim().length===0?"Provide a remote URL.":g&&x.trim().length===0?"Provide a token for one-time credential.":void 0:"Type the vault name to confirm Replace.",children:C.kind==="running"?C.stage==="cloning"?"Cloning…":"Importing…":"Start import"})})]}),H?i.jsx(J0,{vaultName:u,onClose:()=>q(!1),onPicked:ee=>{r(ee),q(!1)}}):null]})}function K0({vaultName:u,result:c,remoteUrl:o,mode:r,onReset:d}){return i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"0.75rem"},children:[i.jsx("strong",{children:"Import succeeded."})," Imported ",c.notes_imported," note",c.notes_imported===1?"":"s",", ",c.tags_imported," tag schema",c.tags_imported===1?"":"s",", ",c.attachments_imported," ","attachment",c.attachments_imported===1?"":"s",r==="replace"&&c.notes_deleted!==void 0?`, wiped ${c.notes_deleted} pre-existing note${c.notes_deleted===1?"":"s"}`:"","."]}),c.warnings.length>0?i.jsxs("details",{style:{marginBottom:"0.75rem"},children:[i.jsxs("summary",{children:[c.warnings.length," warning",c.warnings.length===1?"":"s"," ","(see details)"]}),i.jsx("ul",{style:{marginTop:"0.5rem"},children:c.warnings.map((h,g)=>i.jsx("li",{children:i.jsx("code",{style:{fontSize:"0.85em"},children:h})},g))})]}):null,c.sync_enabled?i.jsxs("div",{className:"mint-banner",style:{marginBottom:"0.75rem"},role:"status",children:[i.jsx("strong",{children:"Sync enabled."})," Changes to vault ",i.jsx("code",{children:u})," ","now push back to ",i.jsx("code",{children:o})," automatically."]}):c.sync_warning?i.jsxs("div",{className:"info-banner",style:{marginBottom:"0.75rem"},role:"status",children:[i.jsxs("p",{style:{marginTop:0},children:[i.jsx("strong",{children:"Sync not enabled."})," ",c.sync_warning]}),i.jsxs("p",{className:"dim",style:{marginBottom:0,fontSize:"0.9em"},children:["You can still set up Sync from the"," ",i.jsx("button",{type:"button",onClick:()=>{var h;return(h=document.getElementById("git-remote-section"))==null?void 0:h.scrollIntoView({behavior:"smooth",block:"start"})},style:{background:"none",border:"none",padding:0,color:"var(--accent)",textDecoration:"underline",cursor:"pointer",fontSize:"inherit"},children:"Git remote section"})," ","above."]})]}):null,i.jsx("div",{className:"actions",children:i.jsx("button",{type:"button",className:"secondary",onClick:d,children:"Run another import"})})]})}function J0({vaultName:u,onClose:c,onPicked:o}){const[r,d]=y.useState(null),[h,g]=y.useState(!1),[S,x]=y.useState(null),[p,E]=y.useState(""),[v,C]=y.useState(null);y.useEffect(()=>{let D=!1;return Cm(u).then(k=>{if(!D){if(!k.installed){x(k.install_url),d([]);return}d(k.repos),g(!!k.truncated)}}).catch(k=>{D||C(k instanceof Error?k.message:String(k))}),()=>{D=!0}},[u]);const V=(r??[]).filter(D=>p.length===0?!0:D.full_name.toLowerCase().includes(p.toLowerCase()));return i.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:i.jsxs("div",{className:"modal",children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:"Pick a repo to import from"}),i.jsx("button",{type:"button",className:"secondary",onClick:c,children:"Close"})]}),v?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:v})}):null,S?i.jsxs("div",{className:"info-banner",role:"status",children:["The Parachute GitHub App isn't installed on any of your accounts yet, so there are no repos to list."," ",i.jsx("a",{href:S,target:"_blank",rel:"noreferrer",children:"Install it on GitHub →"})," ","then reopen this picker."]}):null,i.jsx("div",{className:"form-row",children:i.jsx("input",{type:"search",placeholder:"Filter by name…",value:p,onChange:D=>E(D.target.value)})}),h?i.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos per account. Use the filter above to narrow down."}):null,r===null&&!v?i.jsx("p",{className:"muted",children:"Loading repos…"}):null,r!==null?i.jsxs("div",{className:"repo-list",children:[V.length===0&&p.length>0?i.jsxs("p",{className:"dim",children:['No repos match "',p,'".']}):null,V.length===0&&p.length===0&&r.length===0&&!S?i.jsx("p",{className:"dim",children:"The app installation doesn't include any repos."}):null,V.map(D=>i.jsxs("button",{type:"button",className:"repo-row",onClick:()=>o(D.clone_url),children:[i.jsxs("span",{children:[i.jsx("strong",{children:D.name}),D.private?i.jsx("span",{className:"dim",children:" · private"}):null]}),i.jsx("span",{className:"dim",children:D.updated_at.slice(0,10)})]},D.full_name))]}):null]})})}const $0=["string","integer","number","boolean","array","object"],rr=new Set(["string","integer","boolean"]),Ia=u=>`/vault/${encodeURIComponent(u)}/api/tags`;async function Pa(u){try{const c=await u.text(),o=JSON.parse(c);return o.message||o.error||c||`${u.status}`}catch{return`${u.status} ${u.statusText}`}}async function F0(u){const c=await Ge(u,`${Ia(u)}?include_schema=true`);if(!c.ok)throw new pe(c.status,await Pa(c));return await c.json()}async function W0(u,c){const o=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}`);if(!o.ok)throw new pe(o.status,await Pa(o));return await o.json()}async function I0(u,c){const o=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}/effective`);if(!o.ok)throw new pe(o.status,await Pa(o));return await o.json()}async function P0(u,c,o){const r=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(o)});if(!r.ok)throw new pe(r.status,await Pa(r));return await r.json()}async function ex(u,c,o){const r=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}/conformance`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({fields:o})});if(!r.ok)throw new pe(r.status,await Pa(r));return await r.json()}function Wh({vaultName:u}={}){const c=_u(),o=u??c.name,d=u!==void 0?"/":`/vault/${encodeURIComponent(o??"")}`,[h,g]=y.useState({kind:"loading"}),[S,x]=y.useState(0),[p,E]=y.useState(null);y.useEffect(()=>{let V=!1;if(o)return g({kind:"loading"}),F0(o).then(D=>{V||g({kind:"ok",tags:D})}).catch(D=>{if(!V){if(D instanceof pe&&(D.status===401||D.status===403)){g({kind:"auth-required",status:D.status});return}g({kind:"error",message:D instanceof Error?D.message:String(D)})}}),()=>{V=!0}},[o,S]);const v=y.useCallback(()=>x(V=>V+1),[]),C=y.useCallback(()=>x(V=>V+1),[]);return o?i.jsxs("div",{children:[i.jsxs("div",{className:"list-header",children:[i.jsxs("h2",{children:["Schema for ",i.jsx("code",{children:o})]}),i.jsx(Ze,{to:d,className:"muted",children:"← Vault detail"})]}),i.jsxs("p",{className:"dim",style:{marginTop:0},children:["Tag schemas declare the metadata fields notes carry, which fields are indexed (queryable), and the tag hierarchy. Edits write the live schema directly — the same data an AI sees through ",i.jsx("code",{children:"update-tag"}),"."]}),h.kind==="loading"?i.jsx("p",{className:"muted",children:"Loading…"}):null,h.kind==="auth-required"?i.jsx(Zl,{vaultName:o,status:h.status,onRecovered:v}):null,h.kind==="error"?i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:h.message})}):null,h.kind==="ok"?i.jsxs("div",{className:"schema-layout",children:[i.jsx(nx,{tags:h.tags,selected:p,onSelect:E}),p?i.jsx(ux,{vaultName:o,tag:p,allTags:h.tags,onSaved:C},p):i.jsx("div",{className:"schema-detail",children:i.jsx("p",{className:"muted",children:"Select a tag to view or edit its schema."})})]}):null]}):i.jsxs("div",{children:[i.jsx("h2",{children:"Schema"}),i.jsx("p",{className:"muted",children:"Missing vault name."})]})}function tx(u){const c=u.fields??{},o=Object.values(c);return{hasSchema:u.description!==null&&u.description!==void 0||o.length>0,indexed:o.filter(r=>r.indexed===!0).length,strict:o.some(r=>r.strict===!0)}}function nx({tags:u,selected:c,onSelect:o}){const r=y.useMemo(()=>[...u].sort((d,h)=>d.name.localeCompare(h.name)),[u]);return i.jsx("div",{className:"schema-taglist",role:"navigation","aria-label":"Tags",children:i.jsxs("ul",{className:"tag-list",children:[r.map(d=>{const h=tx(d);return i.jsx("li",{children:i.jsxs("button",{type:"button",className:`tag-list-item${c===d.name?" selected":""}`,onClick:()=>o(d.name),"aria-current":c===d.name,children:[i.jsx("code",{className:"tag-name",children:d.name}),i.jsxs("span",{className:"tag-meta",children:[i.jsx("span",{className:"dim",children:d.count}),h.hasSchema?i.jsx("span",{className:"badge",children:"schema"}):null,h.indexed>0?i.jsxs("span",{className:"badge",children:[h.indexed," indexed"]}):null,h.strict?i.jsx("span",{className:"badge badge-strict",children:"strict"}):null]})]})},d.name)}),r.length===0?i.jsx("li",{className:"muted",children:"No tags yet."}):null]})})}let lx=0;function Om(){return`row-${lx++}`}function ax(u){return u?Object.entries(u).map(([c,o])=>({key:Om(),name:c,spec:{...o}})):[]}function Ih(u){const c={};for(const o of u){const r=o.name.trim();if(!r)continue;const d={};o.spec.type&&(d.type=o.spec.type),o.spec.enum&&o.spec.enum.length>0&&(d.enum=o.spec.enum),o.spec.required&&(d.required=!0),o.spec.cardinality==="many"&&(d.cardinality="many"),o.spec.indexed&&(d.indexed=!0),o.spec.strict&&(d.strict=!0),o.spec.description&&o.spec.description.trim().length>0&&(d.description=o.spec.description.trim()),c[r]=d}return c}const ix=/^[a-zA-Z_][a-zA-Z0-9_]{0,62}$/;function ux({vaultName:u,tag:c,allTags:o,onSaved:r}){const d=Er(u),[h,g]=y.useState({kind:"loading"}),[S,x]=y.useState(0);y.useEffect(()=>{let E=!1;return g({kind:"loading"}),Promise.all([W0(u,c),I0(u,c)]).then(([v,C])=>{E||g({kind:"ok",record:v,effective:C})}).catch(v=>{if(!E){if(v instanceof pe&&(v.status===401||v.status===403)){g({kind:"auth-required",status:v.status});return}g({kind:"error",message:v instanceof Error?v.message:String(v)})}}),()=>{E=!0}},[u,c,S]);const p=y.useCallback(()=>x(E=>E+1),[]);return h.kind==="loading"?i.jsx("div",{className:"schema-detail",children:i.jsxs("p",{className:"muted",children:["Loading ",c,"…"]})}):h.kind==="auth-required"?i.jsx("div",{className:"schema-detail",children:i.jsx(Zl,{vaultName:u,status:h.status,onRecovered:p})}):h.kind==="error"?i.jsx("div",{className:"schema-detail",children:i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:h.message})})}):i.jsx(sx,{vaultName:u,tag:c,record:h.record,effective:h.effective,allTags:o,isAdmin:d,onSaved:()=>{x(E=>E+1),r()}})}function sx({vaultName:u,tag:c,record:o,effective:r,allTags:d,isAdmin:h,onSaved:g}){const[S,x]=y.useState(o.description??""),[p,E]=y.useState(()=>ax(o.fields)),[v,C]=y.useState(o.parent_names??[]),[V,D]=y.useState(!1),[k,H]=y.useState(null),[q,F]=y.useState(0),[B,z]=y.useState(null),[Z,K]=y.useState(!1),[X,ee]=y.useState(!1),ce=y.useMemo(()=>{const N=new Map;for(const Y of r.indexed_fields)N.set(Y.name,Y);return N},[r.indexed_fields]),ze=y.useMemo(()=>d.map(N=>N.name).filter(N=>N!==c).sort((N,Y)=>N.localeCompare(Y)),[d,c]),Oe=y.useMemo(()=>{var Q;const N=new Map(d.map(le=>[le.name,le])),Y=[];for(const le of v){const ue=N.get(le);(Q=ue==null?void 0:ue.parent_names)!=null&&Q.includes(c)&&Y.push(le)}return Y},[v,d,c]),De=y.useMemo(()=>{const N=new Set(Object.entries(o.fields??{}).filter(([,Q])=>Q.indexed===!0).map(([Q])=>Q)),Y=new Set(p.filter(Q=>Q.spec.indexed&&Q.name.trim()).map(Q=>Q.name.trim()));for(const Q of Y)if(!N.has(Q))return!0;for(const Q of N)if(!Y.has(Q))return!0;return!1},[p,o.fields]),Ce=y.useMemo(()=>dx(p),[p]),I=()=>{z(null),ee(!1)},ie=(N,Y,Q)=>{E(le=>le.map(ue=>ue.key===N?{...ue,name:Q!==void 0?Q:ue.name,spec:{...ue.spec,...Y}}:ue)),I()},M=()=>{E(N=>[...N,{key:Om(),name:"",spec:{type:"string"}}]),I()},J=N=>{E(Y=>Y.filter(Q=>Q.key!==N)),I()},ne=N=>{C(Y=>Y.includes(N)?Y.filter(Q=>Q!==N):[...Y,N]),I()},ye=async()=>{D(!0),H(null);try{const N=Ih(p);await P0(u,c,{description:S.trim().length>0?S.trim():null,fields:Object.keys(N).length>0?N:null,replace_fields:!0,parent_names:v.length>0?v:null}),F(Y=>Y+1),I(),setTimeout(()=>F(0),3e3),g()}catch(N){N instanceof pe?H(N.message):H(N instanceof Error?N.message:String(N))}finally{D(!1)}},$=async N=>{if(N.preventDefault(),!!h){if(Ce.length>0){H(Ce[0]);return}if(H(null),B&&B.violating_notes>0||X){await ye();return}K(!0);try{const Y=Ih(p),Q=await ex(u,c,Y);if(Q.violating_notes>0){z(Q);return}I(),await ye()}catch(Y){H(`Could not check existing notes for conformance (${Y instanceof Error?Y.message:String(Y)}). Click Save again to apply anyway — strict fields are still enforced on write.`),z(null),ee(!0)}finally{K(!1)}}},j=!h;return i.jsxs("form",{className:"schema-detail",onSubmit:$,children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:i.jsx("code",{children:c})}),i.jsxs("span",{className:"dim",children:[o.count," note",o.count===1?"":"s"]})]}),j?i.jsxs("div",{className:"warn-banner",role:"status",children:["You're viewing with a read-only token. Saving requires"," ",i.jsxs("code",{children:["vault:",u,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin session to edit.`]}):null,i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"tag-description",children:"Description"}),i.jsx("textarea",{id:"tag-description",value:S,disabled:j,rows:2,onChange:N=>{x(N.target.value),I()},placeholder:"What this tag means + how to use it (sent to AI clients)."})]}),i.jsxs("fieldset",{className:"schema-fields",children:[i.jsx("legend",{children:"Fields"}),p.length===0?i.jsx("p",{className:"dim",children:"No fields declared. Add one to start a schema."}):null,p.map(N=>{var Y;return i.jsx(cx,{row:N,readOnly:j,coDeclarers:N.spec.indexed?(((Y=ce.get(N.name.trim()))==null?void 0:Y.tags)??[]).filter(Q=>Q!==c):[],onChange:(Q,le)=>ie(N.key,Q,le),onRemove:()=>J(N.key)},N.key)}),j?null:i.jsx("button",{type:"button",className:"secondary",onClick:M,children:"+ Add field"})]}),i.jsxs("fieldset",{className:"schema-parents",children:[i.jsx("legend",{children:"Parents (hierarchy)"}),i.jsxs("p",{className:"dim",style:{marginTop:0},children:["A note on ",i.jsx("code",{children:c})," inherits the fields of every parent (and their ancestors). Queries for a parent also match this tag."]}),ze.length===0?i.jsx("p",{className:"dim",children:"No other tags to pick as parents yet."}):i.jsx("div",{className:"parent-grid",children:ze.map(N=>i.jsxs("label",{className:"parent-chip",children:[i.jsx("input",{type:"checkbox",checked:v.includes(N),disabled:j,onChange:()=>ne(N)}),i.jsx("code",{children:N})]},N))}),Oe.length>0?i.jsxs("div",{className:"warn-banner",role:"alert",style:{marginTop:"0.5rem"},children:["Cycle warning: ",i.jsx("code",{children:Oe.join(", ")})," already list(s) ",i.jsx("code",{children:c})," as a parent. A cycle is tolerated at runtime but is almost always a config bug."]}):null]}),i.jsx(rx,{tag:c,effective:r}),i.jsx(ox,{catalog:r.indexed_fields,tag:c}),Ce.length>0?i.jsxs("div",{className:"warn-banner",role:"alert",children:[i.jsx("strong",{children:"Fix before saving:"}),i.jsx("ul",{style:{margin:"0.4rem 0 0"},children:Ce.map(N=>i.jsx("li",{children:N},N))})]}):null,De&&!j?i.jsxs("div",{className:"info-banner",role:"status",children:["This save changes which fields are indexed. Vault will rebuild the backing column + index (an ",i.jsx("code",{children:"ALTER TABLE"})," / index build) — on a large vault this can take a moment."]}):null,B&&B.violating_notes>0?i.jsx(fx,{report:B,tag:c}):null,k?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:k})}):null,q>0?i.jsx("div",{className:"mint-banner",style:{padding:"0.75rem 1rem",margin:"1rem 0"},role:"status",children:"Saved."}):null,i.jsx("div",{className:"actions",children:i.jsx("button",{type:"submit",disabled:j||V||Z,children:V?"Saving…":Z?"Checking existing notes…":B&&B.violating_notes>0||X?"Save anyway":"Save"})})]})}function cx({row:u,readOnly:c,coDeclarers:o,onChange:r,onRemove:d}){const{name:h,spec:g}=u,S=rr.has(g.type??""),x=(g.enum??[]).join(", ");return i.jsxs("div",{className:"field-row",children:[i.jsxs("div",{className:"field-row-main",children:[i.jsx("input",{"aria-label":"Field name",className:"field-name-input",type:"text",value:h,disabled:c,placeholder:"field_name",onChange:p=>r({},p.target.value)}),i.jsxs("select",{"aria-label":"Field type",value:g.type??"",disabled:c,onChange:p=>{const E=p.target.value||void 0,v={type:E};E&&!rr.has(E)&&(v.indexed=!1),r(v)},children:[i.jsx("option",{value:"",children:"(any)"}),$0.map(p=>i.jsx("option",{value:p,children:p},p))]}),i.jsxs("label",{className:"field-flag",children:[i.jsx("input",{type:"checkbox",checked:g.required===!0,disabled:c,onChange:p=>r({required:p.target.checked})}),"required"]}),i.jsxs("label",{className:"field-flag",children:[i.jsx("input",{type:"checkbox",checked:g.cardinality==="many",disabled:c,onChange:p=>r({cardinality:p.target.checked?"many":"one"})}),"many"]}),i.jsxs("label",{className:"field-flag",title:S?void 0:"Only string / integer / boolean fields can be indexed",children:[i.jsx("input",{type:"checkbox",checked:g.indexed===!0,disabled:c||!S,onChange:p=>r({indexed:p.target.checked})}),"indexed"]}),i.jsxs("label",{className:"field-flag",children:[i.jsx("input",{type:"checkbox",checked:g.strict===!0,disabled:c,onChange:p=>r({strict:p.target.checked})}),"strict"]}),c?null:i.jsx("button",{type:"button",className:"secondary field-remove",onClick:d,"aria-label":`Remove field ${h||"(unnamed)"}`,children:"✕"})]}),i.jsxs("div",{className:"field-row-extra",children:[i.jsx("input",{"aria-label":"Enum values (comma-separated)",type:"text",className:"field-enum-input",value:x,disabled:c,placeholder:"enum values (comma-separated, optional)",onChange:p=>{const E=p.target.value.split(",").map(v=>v.trim()).filter(v=>v.length>0);r({enum:E})}}),i.jsx("input",{"aria-label":"Field description",type:"text",className:"field-desc-input",value:g.description??"",disabled:c,placeholder:"description (optional)",onChange:p=>r({description:p.target.value})})]}),o.length>0?i.jsxs("p",{className:"dim field-codeclarers",children:["Also indexed by: ",o.map(p=>i.jsx("code",{children:p},p)),". Type + indexed are global across all of these — change them together."]}):null]})}function rx({tag:u,effective:c}){const o=new Set(Object.keys(c.fields??{})),r=Object.entries(c.effective_fields);return i.jsxs("div",{className:"schema-effective section",children:[i.jsx("h4",{style:{margin:"0 0 0.5rem"},children:"Effective fields (what a note actually gets)"}),c.effective_parents.length>0?i.jsxs("p",{className:"dim",style:{marginTop:0},children:["Inherits from: ",c.effective_parents.map(d=>i.jsx("code",{children:d},d))]}):i.jsxs("p",{className:"dim",style:{marginTop:0},children:["No parents — effective fields are just ",i.jsx("code",{children:u}),"'s own."]}),r.length===0?i.jsx("p",{className:"dim",children:"No fields (own or inherited)."}):i.jsxs("table",{className:"schema-table",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Field"}),i.jsx("th",{children:"Type"}),i.jsx("th",{children:"Source"}),i.jsx("th",{children:"Flags"})]})}),i.jsx("tbody",{children:r.map(([d,h])=>{const g=!o.has(d),S=[h.required?"required":null,h.cardinality==="many"?"many":null,h.strict?"strict":null,h.enum&&h.enum.length>0?`enum[${h.enum.length}]`:null].filter(Boolean);return i.jsxs("tr",{children:[i.jsx("td",{children:i.jsx("code",{children:d})}),i.jsx("td",{children:h.type??i.jsx("span",{className:"dim",children:"any"})}),i.jsx("td",{children:g?i.jsx("span",{className:"badge",children:"inherited"}):i.jsx("span",{className:"dim",children:"own"})}),i.jsx("td",{children:S.length>0?S.join(", "):i.jsx("span",{className:"dim",children:"—"})})]},d)})})]})]})}function ox({catalog:u,tag:c}){return i.jsxs("div",{className:"schema-catalog section",children:[i.jsx("h4",{style:{margin:"0 0 0.5rem"},children:"Indexed fields (what's queryable)"}),u.length===0?i.jsx("p",{className:"dim",children:"No indexed fields in this vault yet."}):i.jsxs("table",{className:"schema-table",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Field"}),i.jsx("th",{children:"Type"}),i.jsx("th",{children:"Declared by"})]})}),i.jsx("tbody",{children:u.map(o=>i.jsxs("tr",{className:o.tags.includes(c)?"row-this-tag":void 0,children:[i.jsx("td",{children:i.jsx("code",{children:o.name})}),i.jsx("td",{children:o.type}),i.jsx("td",{children:o.tags.map(r=>i.jsx("code",{className:r===c?"tag-self":void 0,children:r},r))})]},o.name))})]})]})}function fx({report:u,tag:c}){return i.jsxs("div",{className:"warn-banner",role:"alert",children:[i.jsxs("strong",{children:[u.violating_notes," existing note",u.violating_notes===1?"":"s"," violate this schema."]})," ","They'll be REJECTED on their next write once you tighten"," ",i.jsx("code",{children:u.checked_fields.join(", ")}),".",i.jsx("p",{style:{margin:"0.5rem 0"},children:"Migrate the existing data first with the CLI:"}),i.jsx("pre",{style:{margin:"0 0 0.5rem",whiteSpace:"pre-wrap"},children:i.jsxs("code",{children:["parachute-vault schema migrate-field ",c," <field> --transform …"]})}),u.sample.length>0?i.jsxs("details",{children:[i.jsxs("summary",{children:["Examples (",u.sample.length," of ",u.violating_notes,")"]}),i.jsx("ul",{style:{margin:"0.4rem 0 0"},children:u.sample.map(o=>i.jsxs("li",{children:[i.jsx("code",{children:o.path??o.id}),": ",o.fields.map(r=>r.reason).join(", ")]},o.id))})]}):null,i.jsxs("p",{className:"dim",style:{margin:"0.5rem 0 0",fontSize:"0.9em"},children:["Click ",i.jsx("strong",{children:"Save anyway"})," to apply the schema regardless — these notes stay readable but reject on edit until migrated."]})]})}function dx(u){const c=[],o=new Set;for(const r of u){const d=r.name.trim();if(d){if(o.has(d)){c.push(`Duplicate field name "${d}".`);continue}o.add(d),r.spec.indexed&&!ix.test(d)&&c.push(`"${d}" can't be indexed — indexed field names must start with a letter or underscore and contain only letters, digits, underscores (max 63 chars).`),r.spec.indexed&&r.spec.type&&!rr.has(r.spec.type)&&c.push(`"${d}" is indexed but type "${r.spec.type}" can't be indexed (use string / integer / boolean).`)}}return c}const hx=[30,90,180,365],Ph=90,mx=1440*60;function px(u){if(!u)return null;const c=u.scoped_tags;if(!Array.isArray(c))return null;const o=c.filter(r=>typeof r=="string"&&r.length>0);return o.length>0?o:null}function gx(u){return{jti:u.jti,label:u.subject,scopes:Array.isArray(u.scopes)?u.scopes:[],scoped_tags:px(u.permissions),expires_at:u.expires_at??null,revoked_at:u.revoked_at??null,created_at:u.created_at}}async function yx(u,c){const o={scope:`vault:${u}:${c.verb}`,expires_in:c.ttlDays*mx,subject:c.label};c.scopedTags.length>0&&(o.permissions={scoped_tags:c.scopedTags});const r=await Wa("/api/auth/mint-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(o)});if(!r.ok)throw new pe(r.status,await Cu(r));const d=await r.json();return{jti:d.jti,token:d.token,scope:d.scope,expires_at:d.expires_at??null}}async function vx(u){const c=`vault:${u}:`,o=[];let r=null;for(let d=0;d<1e3;d++){const h=new URLSearchParams({revoked:"all"});r&&h.set("cursor",r);const g=await Wa(`/api/auth/tokens?${h.toString()}`);if(!g.ok)throw new pe(g.status,await Cu(g));const S=await g.json(),x=Array.isArray(S.tokens)?S.tokens:[];if(o.push(...x),r=S.next_cursor??null,!r)break}return o.filter(d=>Array.isArray(d.scopes)&&d.scopes.some(h=>h.startsWith(c))).map(gx)}async function xx(u){const c=await Wa("/api/auth/revoke-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jti:u})});if(!c.ok)throw new pe(c.status,await Cu(c))}async function bx(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/api/tags`);if(!c.ok)throw new pe(c.status,await Cu(c));const o=await c.json();return Array.isArray(o)?o:[]}async function Cu(u){try{const c=await u.text(),o=JSON.parse(c);if(o.error_description)return o.error_description;if(o.message)return o.message;if(o.error)return o.error;if(c)return c}catch{}return`${u.status} ${u.statusText}`}const jx=["read","write","admin"],Sx={30:"30 days",90:"90 days",180:"180 days",365:"1 year (max)"};function Ex(u){return u instanceof Ln?u.disposition==="forbidden"?(Ka(),{kind:"auth-required",status:403}):u.disposition==="auth-required"?{kind:"auth-required",status:u.status}:{kind:"error",message:u.message}:u instanceof pe&&(u.status===401||u.status===403)?{kind:"auth-required",status:u.status}:{kind:"error",message:u instanceof Error?u.message:String(u)}}function em({vaultName:u}={}){const c=_u(),o=u??c.name,r=u!==void 0,d=r?"/":`/vault/${encodeURIComponent(o??"")}`,[h,g]=y.useState({kind:"loading"}),[S,x]=y.useState(null),[p,E]=y.useState(null),[v,C]=y.useState(0);y.useEffect(()=>{let k=!1;if(o)return g({kind:"loading"}),vx(o).then(H=>{k||g({kind:"ok",tokens:H})}).catch(H=>{k||g(Ex(H))}),()=>{k=!0}},[o,v]);const V=y.useCallback(()=>C(k=>k+1),[]);if(y.useEffect(()=>{if(!S)return;const k=H=>{H.preventDefault(),H.returnValue=""};return window.addEventListener("beforeunload",k),()=>window.removeEventListener("beforeunload",k)},[S]),!o)return i.jsxs("div",{children:[i.jsx("h2",{children:"Tokens"}),i.jsx("p",{className:"muted",children:"Missing vault name."}),r?null:i.jsx(Ze,{to:"/",children:"← Back to vaults"})]});const D=Er(o);return i.jsxs("div",{children:[i.jsxs("div",{className:"list-header",children:[i.jsxs("h2",{children:["Tokens for ",i.jsx("code",{children:o})]}),i.jsx(Ze,{to:d,className:"muted",children:"← Vault detail"})]}),D?null:i.jsxs("div",{className:"warn-banner",children:["You're viewing this page with a read-only token. Mint and revoke require"," ",i.jsxs("code",{children:["vault:",o,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin-scoped session to manage tokens.`]}),S?i.jsx(Tx,{result:S,onDismiss:()=>x(null)}):null,h.kind==="ok"&&D&&!S?i.jsx(_x,{vaultName:o,onMinted:k=>{x(k),C(H=>H+1)}}):null,i.jsxs("div",{className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Existing tokens"}),h.kind==="loading"?i.jsx("p",{className:"muted",children:"Loading…"}):null,h.kind==="auth-required"?i.jsx(Zl,{vaultName:o,status:h.status,onRecovered:V}):null,h.kind==="error"?i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:h.message})}):null,h.kind==="ok"?i.jsx(Nx,{tokens:h.tokens,allowRevoke:D,confirmingJti:p,onAskConfirm:E,onRevoked:()=>{E(null),C(k=>k+1)}}):null]})]})}function Tx({result:u,onDismiss:c}){const[o,r]=y.useState(!1),d=async()=>{try{await navigator.clipboard.writeText(u.token),r(!0),setTimeout(()=>r(!1),2e3)}catch{}};return i.jsxs("div",{className:"mint-banner",children:[i.jsx("h3",{children:"New token (shown once)"}),i.jsx("p",{className:"muted",children:"This is the only time the vault will show this token. Copy it now and store it somewhere safe — a password manager, the operator's notes, paraclaw's secrets store. If you lose it, revoke it and mint a new one."}),i.jsxs("div",{className:"token-box",children:[i.jsx("code",{children:u.token}),i.jsx("button",{type:"button",onClick:d,className:"secondary",children:o?"Copied":"Copy"})]}),i.jsx("p",{className:"warn",children:"⚠ Don't dismiss this banner until you've saved the token."}),i.jsx("div",{className:"actions",children:i.jsx("button",{type:"button",onClick:c,children:"Done — I've saved the token"})})]})}function _x({vaultName:u,onMinted:c}){const[o,r]=y.useState(""),[d,h]=y.useState("admin"),[g,S]=y.useState(Ph),[x,p]=y.useState(!1),[E,v]=y.useState(null),[C,V]=y.useState([]),[D,k]=y.useState(null),[H,q]=y.useState(new Set);y.useEffect(()=>{let K=!1;return bx(u).then(X=>{if(K)return;const ee=X.map(ce=>ce.name).filter(ce=>!ce.includes("/")).sort();V(ee)}).catch(X=>{K||k(X instanceof Error?X.message:String(X))}),()=>{K=!0}},[u]);const F=o.trim(),B=F.length===0,z=K=>{q(X=>{const ee=new Set(X);return ee.has(K)?ee.delete(K):ee.add(K),ee})},Z=async K=>{if(K.preventDefault(),B){v("label required — give the token a recognizable name");return}p(!0),v(null);try{const X=await yx(u,{verb:d,label:F,scopedTags:[...H],ttlDays:g});c(X),r(""),h("admin"),S(Ph),q(new Set)}catch(X){if(X instanceof Ln&&X.disposition==="forbidden"){Ka();return}v(X instanceof Error?X.message:String(X))}finally{p(!1)}};return i.jsxs("form",{onSubmit:Z,className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Mint a token"}),i.jsx("p",{className:"dim",style:{margin:"0 0 0.85rem"},children:"Issues a hub-signed token (JWT) scoped to this vault. Store it like a password — it's shown once and can't be re-displayed."}),E?i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:E})}):null,i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{htmlFor:"mint-label",children:["Label ",i.jsx("span",{className:"dim",children:"(required)"})]}),i.jsx("input",{id:"mint-label",type:"text",value:o,onChange:K=>r(K.target.value),placeholder:"e.g. ci, paraclaw-prod, my-laptop",maxLength:120,required:!0})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"mint-scope",children:"Scope"}),i.jsx("select",{id:"mint-scope",value:d,onChange:K=>h(K.target.value),children:jx.map(K=>i.jsx("option",{value:K,children:K==="read"?"read — query notes only":K==="write"?"write — query + create/update notes":"admin — full control (incl. token mgmt)"},K))}),i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Issued as ",i.jsxs("code",{children:["vault:",u,":",d]}),". Lower scopes inherit narrower powers."]})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"mint-ttl",children:"Expires after"}),i.jsx("select",{id:"mint-ttl",value:g,onChange:K=>S(Number(K.target.value)),children:hx.map(K=>i.jsx("option",{value:K,children:Sx[K]??`${K} days`},K))}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"The token stops working after this. Rotate before it lapses."})]}),i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:["Tag scope ",i.jsx("span",{className:"dim",children:"(optional)"})]}),D?i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Couldn't load tags: ",i.jsx("code",{children:D}),". Token will be unscoped."]}):C.length===0?i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"No root tags in this vault yet — token will see the full vault."}):i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"tag-picker",children:C.map(K=>i.jsxs("label",{className:"tag-checkbox",children:[i.jsx("input",{type:"checkbox",checked:H.has(K),onChange:()=>z(K)}),i.jsx("code",{children:K})]},K))}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:H.size===0?"Nothing selected — token sees the full vault (unscoped).":`Token limited to: ${[...H].join(", ")}. Sub-tags (e.g. health/food) are reachable when their root is selected.`})]})]}),i.jsx("div",{className:"actions",children:i.jsx("button",{type:"submit",disabled:x||B,children:x?"Minting…":"Mint token"})})]})}function Nx({tokens:u,allowRevoke:c,confirmingJti:o,onAskConfirm:r,onRevoked:d}){return u.length===0?i.jsx("p",{className:"muted",children:"No tokens yet. Mint one above to get started."}):i.jsx("div",{className:"token-list",children:u.map(h=>i.jsx(wx,{token:h,allowRevoke:c,confirming:o===h.jti,onAskConfirm:r,onRevoked:d},h.jti))})}function wx({token:u,allowRevoke:c,confirming:o,onAskConfirm:r,onRevoked:d}){const[h,g]=y.useState(!1),[S,x]=y.useState(null),p=u.revoked_at!==null,E=async()=>{g(!0),x(null);try{await xx(u.jti),d()}catch(v){if(v instanceof Ln&&v.disposition==="forbidden"){Ka();return}x(v instanceof Error?v.message:String(v)),g(!1)}};return i.jsxs("div",{className:"token-row",children:[i.jsxs("div",{className:"body",children:[i.jsxs("div",{className:"name",children:[i.jsx("strong",{children:u.label??"(unlabeled)"}),i.jsx("code",{className:"dim",children:u.jti}),p?i.jsx("code",{className:"scope-tag",title:"This token has been revoked and no longer works.",children:"revoked"}):null]}),i.jsxs("div",{className:"meta",children:[i.jsx("span",{className:"dim",children:"scopes:"})," ",u.scopes.length>0?u.scopes.map(v=>i.jsx("code",{className:"scope-tag",children:v},v)):i.jsx("span",{className:"dim",children:"(none)"})]}),u.scoped_tags&&u.scoped_tags.length>0?i.jsxs("div",{className:"meta",children:[i.jsx("span",{className:"dim",children:"tags:"})," ",u.scoped_tags.map(v=>i.jsxs("code",{className:"scope-tag tag-pill",children:["#",v]},v))]}):null,i.jsxs("div",{className:"meta dim",children:["created ",u.created_at,u.expires_at?` · expires ${u.expires_at}`:"",p&&u.revoked_at?` · revoked ${u.revoked_at}`:""]}),S?i.jsx("div",{className:"error-banner",style:{marginTop:"0.5rem"},children:i.jsx("code",{children:S})}):null]}),c&&!p?o?i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:E,disabled:h,children:h?"Revoking…":"Confirm revoke"}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>r(null),disabled:h,children:"Cancel"})]}):i.jsx("button",{type:"button",className:"secondary",onClick:()=>r(u.jti),children:"Revoke"}):null]})}function Cx(){const[u,c]=y.useState({kind:"loading"});return y.useEffect(()=>{let o=!1;return _m().then(r=>{o||c({kind:"ok",vaults:r})}).catch(r=>{if(o)return;const d=r instanceof pe?`${r.status}: ${r.message}`:r instanceof Error?r.message:String(r);c({kind:"error",message:d})}),()=>{o=!0}},[]),u.kind==="loading"?i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsx("p",{className:"muted",children:"Loading…"})]}):u.kind==="error"?i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:u.message})})]}):u.vaults.length===0?i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsxs("div",{className:"empty",children:["No vaults yet. Run ",i.jsx("code",{children:"parachute-vault create <name>"})," on the host to create one."]})]}):i.jsxs("div",{children:[i.jsx("div",{className:"list-header",children:i.jsx("h2",{children:"Vaults"})}),u.vaults.map(o=>i.jsxs(Ze,{to:`/vault/${o}`,className:"vault-row",children:[i.jsx("div",{className:"body",children:i.jsx("div",{className:"name",children:i.jsx("code",{children:o})})}),i.jsx("div",{className:"chev",children:"→"})]},o))]})}function Ax(){const u=xr(),c=u?null:Em();return i.jsxs("div",{className:"page",children:[i.jsxs("nav",{className:"nav",children:[i.jsxs(Ze,{to:"/",className:"brand",children:["Parachute Vault ",i.jsx("span",{className:"sub",children:"admin"})]}),c?i.jsx(Ze,{to:"/",children:i.jsx("code",{children:c})}):i.jsx(Ze,{to:"/",children:"Vaults"})]}),u?i.jsxs(tr,{children:[i.jsx(ft,{path:"/",element:i.jsx(_0,{})}),i.jsx(ft,{path:"*",element:i.jsx(lr,{})})]}):c?i.jsxs(tr,{children:[i.jsx(ft,{path:"/",element:i.jsx(Jh,{vaultName:c})}),i.jsx(ft,{path:"/tokens",element:i.jsx(em,{vaultName:c})}),i.jsx(ft,{path:"/mirror",element:i.jsx($h,{vaultName:c})}),i.jsx(ft,{path:"/schema",element:i.jsx(Wh,{vaultName:c})}),i.jsx(ft,{path:"*",element:i.jsx(lr,{})})]}):i.jsxs(tr,{children:[i.jsx(ft,{path:"/",element:i.jsx(Cx,{})}),i.jsx(ft,{path:"/vault/:name",element:i.jsx(Jh,{})}),i.jsx(ft,{path:"/vault/:name/tokens",element:i.jsx(em,{})}),i.jsx(ft,{path:"/vault/:name/mirror",element:i.jsx($h,{})}),i.jsx(ft,{path:"/vault/:name/schema",element:i.jsx(Wh,{})}),i.jsx(ft,{path:"*",element:i.jsx(lr,{})})]})]})}function lr(){return i.jsxs("div",{className:"empty",children:["404 — back to ",i.jsx(Ze,{to:"/",children:"vault"}),"."]})}$v();const Dm=document.getElementById("root");if(!Dm)throw new Error("#root not found");function ar(){my.createRoot(Dm).render(i.jsx(y.StrictMode,{children:i.jsx(Dv,{basename:Qv(),children:i.jsx(Ax,{})})}))}const tm=Em();!xr()&&tm?Iv(tm).then(ar,ar):ar();
61
+ PARACHUTE_GITHUB_APP_SLUG=<your app's URL slug>`})}),i.jsx("p",{className:"dim",style:{marginBottom:0,fontSize:"0.9em"},children:"Both together — the client ID mints the tokens, the slug builds the install link; mixing apps breaks the connect flow. Then disconnect and reconnect GitHub here to mint tokens from your app."})]}):null]})}function Fh({vaultName:u,mode:c,initialLogin:o,onClose:r,onConnected:d,onHistory:h}){const[g,S]=y.useState(c==="choose-repo"?{kind:"probing",user:{login:o??""}}:{kind:"starting"}),[x,p]=y.useState(Date.now()),E=y.useRef(!1),v=g.kind==="polling";y.useEffect(()=>{if(!v)return;const k=setInterval(()=>p(Date.now()),1e3);return()=>clearInterval(k)},[v]),y.useEffect(()=>()=>{E.current=!0},[]),y.useEffect(()=>{if(g.kind!=="starting")return;let k=!1;return u0(u).then(H=>{k||S({kind:"polling",code:H,pollIntervalMs:Math.max(H.interval,1)*1e3,startedAt:Date.now()})}).catch(H=>{k||S({kind:"error",message:H instanceof Error?H.message:String(H)})}),()=>{k=!0}},[g.kind,u]),y.useEffect(()=>{if(g.kind!=="polling")return;E.current=!1;const k=g.code;let H=!1,q=null,F=g.pollIntervalMs;const B=async()=>{if(!(H||E.current))try{const z=await s0(u,k.polling_id);if(H)return;if(z.state==="granted"){h(z.history_enabled),S({kind:"probing",user:{login:z.user.login}});return}if(z.state==="denied"){S({kind:"error",message:"Authorization denied."});return}if(z.state==="expired"){S({kind:"error",message:"The device code expired. Try again."});return}z.state==="slow_down"&&(F=z.interval*1e3),q=setTimeout(B,F)}catch(z){if(H)return;S({kind:"error",message:z instanceof Error?z.message:String(z)})}};return q=setTimeout(B,F),()=>{H=!0,q&&clearTimeout(q)}},[g,u,h]),y.useEffect(()=>{if(g.kind!=="probing")return;const k=g.user;let H=!1;return wm(u).then(q=>{H||S(q.installed?{kind:"picker",user:k,install:q}:{kind:"install-needed",user:k,install:q})}).catch(q=>{H||S({kind:"error",message:q instanceof Error?q.message:String(q)})}),()=>{H=!0}},[g,u]);const C=y.useCallback(k=>S({kind:"error",message:k}),[]),V=y.useCallback(()=>{S(k=>k.kind==="picker"?{kind:"probing",user:k.user}:k)},[]),D=async k=>{try{await navigator.clipboard.writeText(k)}catch{}};return i.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:i.jsxs("div",{className:"modal",children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:c==="choose-repo"?"Choose a repository":"Connect GitHub"}),i.jsx("button",{type:"button",className:"secondary",onClick:r,children:"Close"})]}),g.kind==="starting"?i.jsx("p",{className:"muted",children:"Requesting device code from GitHub…"}):null,g.kind==="polling"?i.jsxs(i.Fragment,{children:[i.jsxs("p",{children:[i.jsx("strong",{children:"Step 1."})," Open"," ",i.jsx("a",{href:g.code.verification_uri,target:"_blank",rel:"noreferrer",children:g.code.verification_uri})," ","in your browser."]}),i.jsxs("p",{children:[i.jsx("strong",{children:"Step 2."})," Enter this code:"]}),i.jsxs("div",{className:"device-code-row",children:[i.jsx("code",{className:"device-code",children:g.code.user_code}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>D(g.code.user_code),children:"Copy"})]}),i.jsxs("p",{className:"dim",children:["Waiting for authorization…"," ",G0(g.code.expires_in,g.startedAt,x)]})]}):null,g.kind==="probing"?i.jsx("p",{className:"muted",children:"Checking where the app is installed…"}):null,g.kind==="install-needed"?i.jsx(Mm,{install:g.install,onRecheck:()=>S({kind:"probing",user:g.user})}):null,g.kind==="picker"?i.jsx(V0,{vaultName:u,user:g.user,install:g.install,onPicked:async(k,H)=>{const q=await o0(u,{owner:k,name:H});h(q.history_enabled);const F=await jr(u);d(F,q)},onError:C,onNotInstalled:V}):null,g.kind==="error"?i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:g.message})}),i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:()=>S(c==="choose-repo"?{kind:"probing",user:{login:o??""}}:{kind:"starting"}),children:"Try again"}),i.jsx("button",{type:"button",className:"secondary",onClick:r,children:"Close"})]})]}):null]})})}function G0(u,c,o){const r=Math.floor((o-c)/1e3),d=Math.max(0,u-r),h=Math.floor(d/60),g=d%60;return`${h}:${String(g).padStart(2,"0")} remaining`}function Y0(u){return u.account_type==="Organization"?`https://github.com/organizations/${encodeURIComponent(u.account_login)}/settings/installations/${u.id}`:`https://github.com/settings/installations/${u.id}`}function V0({vaultName:u,user:c,install:o,onPicked:r,onError:d,onNotInstalled:h}){const[g,S]=y.useState(null),[x,p]=y.useState(!1),[E,v]=y.useState(""),[C,V]=y.useState(null),[D,k]=y.useState(!1),[H,q]=y.useState(""),[F,B]=y.useState(!1),[z,Z]=y.useState(!1),[K,X]=y.useState(0);y.useEffect(()=>{let I=!1;return S(null),Cm(u).then(ie=>{if(!I){if(!ie.installed){h();return}S(ie.repos),p(!!ie.truncated)}}).catch(ie=>{I||d(ie instanceof Error?ie.message:String(ie))}),()=>{I=!0}},[u,d,h,K]);const ee=(g??[]).filter(I=>E.length===0?!0:I.full_name.toLowerCase().includes(E.toLowerCase())),ce=[];for(const I of ee){const ie=ce[ce.length-1];if(ie&&ie.login===I.account_login)ie.repos.push(I);else{const M=ce.find(J=>J.login===I.account_login);M?M.repos.push(I):ce.push({login:I.account_login,repos:[I]})}}const ze=I=>o.installations.find(ie=>ie.account_login===I),Oe=async(I,ie)=>{V(`${I}/${ie}`);try{await r(I,ie)}catch(M){d(M instanceof Error?M.message:String(M))}finally{V(null)}},De=async()=>{if(H.trim().length!==0){k(!0);try{const I=await r0(u,{name:H.trim(),description:"Parachute Vault mirror",private:!0});await r(I.owner,I.name)}catch(I){I instanceof pe&&I.errorType==="app_lacks_admin_permission"?Z(!0):d(I instanceof Error?I.message:String(I))}finally{k(!1)}}},Ce=o.app.is_shared_default||z;return i.jsxs(i.Fragment,{children:[i.jsxs("p",{children:["Authorized as ",i.jsxs("code",{children:["@",c.login]}),". Pick a repository to push the mirror to:"]}),i.jsx("div",{className:"form-row",children:i.jsx("input",{type:"search",placeholder:"Filter by name…",value:E,onChange:I=>v(I.target.value)})}),x?i.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos per account. Use the filter above to narrow down — or paste the clone URL directly via Personal Access Token if your repo isn't here."}):null,g===null?i.jsx("p",{className:"muted",children:"Loading repos…"}):null,g!==null?i.jsxs("div",{className:"repo-list",children:[ee.length===0&&E.length>0?i.jsxs("p",{className:"dim",children:['No repos match "',E,'".']}):null,ee.length===0&&E.length===0&&g.length===0?i.jsx("p",{className:"dim",children:`The app installation doesn't include any repos yet — pick some via "Change repo access on GitHub" below, then refresh.`}):null,ce.map(I=>{const ie=ze(I.login);return i.jsxs("div",{children:[i.jsxs("p",{className:"dim",style:{margin:"0.5rem 0 0.25rem"},children:[i.jsx("strong",{children:I.login}),ie?i.jsxs(i.Fragment,{children:[" ","·"," ",ie.account_type==="Organization"?"organization":"user"," ","·"," ",ie.repository_selection==="selected"?"Selected repos only":"All repos"]}):null]}),I.repos.map(M=>i.jsxs("button",{type:"button",className:"repo-row",onClick:()=>Oe(M.owner,M.name),disabled:C!==null,children:[i.jsxs("span",{children:[i.jsx("strong",{children:M.name}),M.private?i.jsx("span",{className:"dim",children:" · private"}):null]}),i.jsx("span",{className:"dim",children:M.updated_at.slice(0,10)})]},M.full_name))]},I.login)})]}):null,i.jsxs("div",{className:"actions",style:{marginTop:"0.75rem"},children:[i.jsx("button",{type:"button",className:"secondary",onClick:()=>X(I=>I+1),children:"Refresh list"}),i.jsx("a",{href:o.install_url,target:"_blank",rel:"noreferrer",className:"dim",style:{alignSelf:"center"},children:"Install on another account or org →"})]}),F?i.jsxs("div",{className:"form-row",style:{marginTop:"0.75rem"},children:[i.jsx("label",{htmlFor:"new-repo-name",children:"New repo name"}),i.jsx("input",{id:"new-repo-name",type:"text",value:H,placeholder:"my-vault-backup",onChange:I=>q(I.target.value)}),Ce?i.jsx(X0,{install:o,suggestedName:H.trim(),onRefresh:()=>X(I=>I+1)}):i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:De,disabled:D||H.trim().length===0,children:D?"Creating…":"Create"}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>B(!1),disabled:D,children:"Cancel"})]})]}):i.jsx("div",{className:"actions",style:{marginTop:"0.75rem"},children:i.jsx("button",{type:"button",className:"secondary",onClick:()=>B(!0),children:"+ Create new private repo"})})]})}function X0({install:u,suggestedName:c,onRefresh:o}){const r=c.length>0?`https://github.com/new?name=${encodeURIComponent(c)}`:"https://github.com/new";return i.jsxs("div",{className:"info-banner",role:"note",style:{marginTop:"0.5rem"},children:[i.jsx("p",{style:{marginTop:0},children:u.app.is_shared_default?i.jsxs(i.Fragment,{children:["The Parachute app deliberately can't create repos for you (it only holds the ",i.jsx("em",{children:"Contents"})," permission — creating repos would need admin powers a backup doesn't deserve). Three quick steps instead:"]}):i.jsxs(i.Fragment,{children:["Your GitHub App doesn't have the ",i.jsx("em",{children:"Administration"})," permission needed to create repos. Three quick steps instead:"]})}),i.jsxs("ol",{style:{marginTop:0,marginBottom:"0.5rem"},children:[i.jsxs("li",{children:[i.jsx("a",{href:r,target:"_blank",rel:"noreferrer",children:"Create a new repo on GitHub →"})," ",i.jsx("span",{className:"dim",children:"(private; leave it empty — no README or .gitignore)"})]}),i.jsxs("li",{children:["Add it to the app's repo access:"," ",u.installations.length>0?u.installations.map((d,h)=>i.jsxs("span",{children:[h>0?" · ":null,i.jsxs("a",{href:Y0(d),target:"_blank",rel:"noreferrer",children:["configure on ",d.account_login," →"]})]},d.id)):i.jsx("a",{href:u.install_url,target:"_blank",rel:"noreferrer",children:"install the app →"})," ",i.jsx("span",{className:"dim",children:'(skip if the installation already grants "All repos")'})]}),i.jsxs("li",{children:["Come back and"," ",i.jsx("button",{type:"button",className:"secondary",onClick:o,children:"Refresh list"})," ","— then pick it."]})]})]})}function Q0({vaultName:u,onClose:c,onSaved:o}){const[r,d]=y.useState(""),[h,g]=y.useState(""),[S,x]=y.useState(""),[p,E]=y.useState(!1),[v,C]=y.useState(null),V=async D=>{D.preventDefault(),E(!0),C(null);try{const k=await c0(u,{token:r.trim(),remote_url:h.trim(),label:S.trim()||void 0});o(k)}catch(k){C(k instanceof Error?k.message:String(k))}finally{E(!1)}};return i.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:i.jsxs("div",{className:"modal",children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:"Use Personal Access Token"}),i.jsx("button",{type:"button",className:"secondary",onClick:c,disabled:p,children:"Close"})]}),i.jsxs("p",{className:"dim",children:["Works for any provider that supports HTTPS push with a token in the URL (GitHub, GitLab, Codeberg, Gitea, …). The token is stored with"," ",i.jsx("code",{children:"0600"})," file perms on this server."]}),i.jsxs("form",{onSubmit:V,children:[i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"pat-token",children:"Token"}),i.jsx("input",{id:"pat-token",type:"password",value:r,autoComplete:"off",onChange:D=>d(D.target.value),placeholder:"ghp_… or glpat-… or similar",required:!0})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"pat-url",children:"Remote URL"}),i.jsx("input",{id:"pat-url",type:"url",value:h,onChange:D=>g(D.target.value),placeholder:"https://github.com/owner/repo.git",required:!0}),i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["We'll embed your token in the URL before saving (using GitHub's"," ",i.jsx("code",{children:"x-access-token"})," convention). The URL you see on disk will carry the token; ensure the file isn't shared."]})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"pat-label",children:"Label (optional)"}),i.jsx("input",{id:"pat-label",type:"text",value:S,onChange:D=>x(D.target.value),placeholder:"GitHub PAT for backup"})]}),v?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:v})}):null,i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"submit",disabled:p,children:p?"Validating…":"Validate & save"}),i.jsx("button",{type:"button",className:"secondary",onClick:c,disabled:p,children:"Cancel"})]})]})]})})}function Z0({vaultName:u,creds:c}){const[o,r]=y.useState(""),[d,h]=y.useState("merge"),[g,S]=y.useState(!1),[x,p]=y.useState(""),[E,v]=y.useState(!0),[C,V]=y.useState({kind:"idle"}),[D,k]=y.useState(""),[H,q]=y.useState(!1),F=(c==null?void 0:c.active_method)==="github_oauth"&&c.github_oauth!==null,B=(c==null?void 0:c.active_method)!==null&&(c==null?void 0:c.active_method)!==void 0,z=d!=="replace"||D.trim()===u,Z=C.kind!=="running"&&o.trim().length>0&&z&&(!g||x.trim().length>0),K=async()=>{V({kind:"running",stage:"cloning"});let ee;g?ee={kind:"pat",token:x.trim()}:B?ee=null:ee={kind:"none"};try{const ce=window.setTimeout(()=>V(Oe=>Oe.kind==="running"?{kind:"running",stage:"importing"}:Oe),1500),ze=await f0(u,{remote_url:o.trim(),mode:d,credentials:ee,enable_sync:E});window.clearTimeout(ce),V({kind:"success",result:ze,remoteUrl:o.trim(),mode:d})}catch(ce){const ze=ce instanceof pe?`${ce.status===409?"Already running. ":""}${ce.message}`:ce instanceof Error?ce.message:String(ce);V({kind:"error",message:ze})}},X=()=>{V({kind:"idle"}),k("")};return i.jsxs("div",{className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Import from a git repo"}),i.jsxs("p",{className:"dim",style:{marginTop:0},children:["Pull a vault state from a remote git repo into ",i.jsx("strong",{children:"this"})," vault. Use this to load a vault someone has been mirroring, or to sync a vault between machines you control. The remote must be a Parachute vault export (created by ",i.jsx("code",{children:"parachute-vault export"})," or the mirror's export flow)."]}),i.jsxs("div",{className:"warn-banner",style:{marginBottom:"1rem"},role:"note",children:[i.jsx("strong",{children:"One vault per remote."})," Multiple vaults pushing to the same git repo isn't a supported shape — the last push wins, and vaults that diverge silently overwrite each other. Today's working pattern is one vault per remote. Active two-way sync is a future direction; for now, do exports from one place and imports as snapshots elsewhere."]}),C.kind==="success"?i.jsx(K0,{vaultName:u,result:C.result,remoteUrl:C.remoteUrl,mode:C.mode,onReset:X}):i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"import-remote-url",children:"Remote URL"}),i.jsx("input",{id:"import-remote-url",type:"text",value:o,placeholder:"https://github.com/aaron/my-vault.git",onChange:ee=>r(ee.target.value),disabled:C.kind==="running"}),F?i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.9em"},children:["Or"," ",i.jsx("button",{type:"button",onClick:()=>q(!0),disabled:C.kind==="running",style:{background:"none",border:"none",padding:0,color:"var(--accent)",textDecoration:"underline",cursor:"pointer",fontSize:"inherit"},children:"pick from your GitHub repos"}),"."]}):null,!B&&!g?i.jsx("p",{className:"hint",style:{marginTop:"0.35rem",fontSize:"0.85em"},children:"No saved git credentials. The import will be unauthenticated — works for public repos; private repos will fail with a clear error. Use the one-time credential toggle below if needed."}):null]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{children:"Mode"}),i.jsxs("label",{className:"radio-row",children:[i.jsx("input",{type:"radio",name:"import-mode",value:"merge",checked:d==="merge",onChange:()=>{h("merge"),k("")},disabled:C.kind==="running"}),i.jsxs("span",{children:[i.jsx("strong",{children:"Merge"})," ",i.jsxs("span",{className:"dim",children:["— upsert by id. Notes in the remote get created/updated; any notes that exist only locally ",i.jsx("strong",{children:"survive"}),"."]})]})]}),i.jsxs("label",{className:"radio-row",children:[i.jsx("input",{type:"radio",name:"import-mode",value:"replace",checked:d==="replace",onChange:()=>h("replace"),disabled:C.kind==="running"}),i.jsxs("span",{children:[i.jsx("strong",{children:"Replace"})," ",i.jsxs("span",{className:"dim",children:["— wipe this vault first, then import. The remote becomes the new source of truth. ",i.jsx("strong",{children:"Destructive."})]})]})]})]}),d==="replace"?i.jsxs("div",{className:"form-row",children:[i.jsxs("div",{className:"error-banner",role:"alert",style:{marginBottom:"0.5rem"},children:[i.jsxs("strong",{children:['Replace will delete every note in vault "',u,'" before importing.']})," To confirm, type the vault name below:"]}),i.jsx("input",{id:"import-confirm-name",type:"text",value:D,placeholder:u,onChange:ee=>k(ee.target.value),disabled:C.kind==="running","aria-label":"Type vault name to confirm"})]}):null,i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:[i.jsx("input",{type:"checkbox",checked:g,onChange:ee=>S(ee.target.checked),disabled:C.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"One-time credential for this import only"]}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.85em"},children:"Use a different Personal Access Token just for this clone, without changing your saved credentials."}),g?i.jsx("input",{id:"import-per-call-pat",type:"password",value:x,placeholder:"ghp_… or similar",onChange:ee=>p(ee.target.value),disabled:C.kind==="running",autoComplete:"off",style:{marginTop:"0.5rem"}}):null]}),i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:[i.jsx("input",{type:"checkbox",checked:E,onChange:ee=>v(ee.target.checked),disabled:C.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"Also sync changes back to this repo"]}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.85em"},children:"Pushes future changes to this repo automatically. Uses the access you provide above."})]}),C.kind==="error"?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:C.message})}):null,i.jsx("div",{className:"actions",children:i.jsx("button",{type:"button",onClick:K,disabled:!Z,title:z?o.trim().length===0?"Provide a remote URL.":g&&x.trim().length===0?"Provide a token for one-time credential.":void 0:"Type the vault name to confirm Replace.",children:C.kind==="running"?C.stage==="cloning"?"Cloning…":"Importing…":"Start import"})})]}),H?i.jsx(J0,{vaultName:u,onClose:()=>q(!1),onPicked:ee=>{r(ee),q(!1)}}):null]})}function K0({vaultName:u,result:c,remoteUrl:o,mode:r,onReset:d}){return i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"0.75rem"},children:[i.jsx("strong",{children:"Import succeeded."})," Imported ",c.notes_imported," note",c.notes_imported===1?"":"s",", ",c.tags_imported," tag schema",c.tags_imported===1?"":"s",", ",c.attachments_imported," ","attachment",c.attachments_imported===1?"":"s",r==="replace"&&c.notes_deleted!==void 0?`, wiped ${c.notes_deleted} pre-existing note${c.notes_deleted===1?"":"s"}`:"","."]}),c.warnings.length>0?i.jsxs("details",{style:{marginBottom:"0.75rem"},children:[i.jsxs("summary",{children:[c.warnings.length," warning",c.warnings.length===1?"":"s"," ","(see details)"]}),i.jsx("ul",{style:{marginTop:"0.5rem"},children:c.warnings.map((h,g)=>i.jsx("li",{children:i.jsx("code",{style:{fontSize:"0.85em"},children:h})},g))})]}):null,c.sync_enabled?i.jsxs("div",{className:"mint-banner",style:{marginBottom:"0.75rem"},role:"status",children:[i.jsx("strong",{children:"Sync enabled."})," Changes to vault ",i.jsx("code",{children:u})," ","now push back to ",i.jsx("code",{children:o})," automatically."]}):c.sync_warning?i.jsxs("div",{className:"info-banner",style:{marginBottom:"0.75rem"},role:"status",children:[i.jsxs("p",{style:{marginTop:0},children:[i.jsx("strong",{children:"Sync not enabled."})," ",c.sync_warning]}),i.jsxs("p",{className:"dim",style:{marginBottom:0,fontSize:"0.9em"},children:["You can still set up Sync from the"," ",i.jsx("button",{type:"button",onClick:()=>{var h;return(h=document.getElementById("git-remote-section"))==null?void 0:h.scrollIntoView({behavior:"smooth",block:"start"})},style:{background:"none",border:"none",padding:0,color:"var(--accent)",textDecoration:"underline",cursor:"pointer",fontSize:"inherit"},children:"Git remote section"})," ","above."]})]}):null,i.jsx("div",{className:"actions",children:i.jsx("button",{type:"button",className:"secondary",onClick:d,children:"Run another import"})})]})}function J0({vaultName:u,onClose:c,onPicked:o}){const[r,d]=y.useState(null),[h,g]=y.useState(!1),[S,x]=y.useState(null),[p,E]=y.useState(""),[v,C]=y.useState(null);y.useEffect(()=>{let D=!1;return Cm(u).then(k=>{if(!D){if(!k.installed){x(k.install_url),d([]);return}d(k.repos),g(!!k.truncated)}}).catch(k=>{D||C(k instanceof Error?k.message:String(k))}),()=>{D=!0}},[u]);const V=(r??[]).filter(D=>p.length===0?!0:D.full_name.toLowerCase().includes(p.toLowerCase()));return i.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:i.jsxs("div",{className:"modal",children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:"Pick a repo to import from"}),i.jsx("button",{type:"button",className:"secondary",onClick:c,children:"Close"})]}),v?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:v})}):null,S?i.jsxs("div",{className:"info-banner",role:"status",children:["The Parachute GitHub App isn't installed on any of your accounts yet, so there are no repos to list."," ",i.jsx("a",{href:S,target:"_blank",rel:"noreferrer",children:"Install it on GitHub →"})," ","then reopen this picker."]}):null,i.jsx("div",{className:"form-row",children:i.jsx("input",{type:"search",placeholder:"Filter by name…",value:p,onChange:D=>E(D.target.value)})}),h?i.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos per account. Use the filter above to narrow down."}):null,r===null&&!v?i.jsx("p",{className:"muted",children:"Loading repos…"}):null,r!==null?i.jsxs("div",{className:"repo-list",children:[V.length===0&&p.length>0?i.jsxs("p",{className:"dim",children:['No repos match "',p,'".']}):null,V.length===0&&p.length===0&&r.length===0&&!S?i.jsx("p",{className:"dim",children:"The app installation doesn't include any repos."}):null,V.map(D=>i.jsxs("button",{type:"button",className:"repo-row",onClick:()=>o(D.clone_url),children:[i.jsxs("span",{children:[i.jsx("strong",{children:D.name}),D.private?i.jsx("span",{className:"dim",children:" · private"}):null]}),i.jsx("span",{className:"dim",children:D.updated_at.slice(0,10)})]},D.full_name))]}):null]})})}const $0=["string","integer","number","boolean","array","object"],rr=new Set(["string","integer","boolean"]),Ia=u=>`/vault/${encodeURIComponent(u)}/api/tags`;async function Pa(u){try{const c=await u.text(),o=JSON.parse(c);return o.message||o.error||c||`${u.status}`}catch{return`${u.status} ${u.statusText}`}}async function F0(u){const c=await Ge(u,`${Ia(u)}?include_schema=true`);if(!c.ok)throw new pe(c.status,await Pa(c));return await c.json()}async function W0(u,c){const o=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}`);if(o.status===404)return null;if(!o.ok)throw new pe(o.status,await Pa(o));return await o.json()}async function I0(u,c){const o=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}/effective`);if(!o.ok)throw new pe(o.status,await Pa(o));return await o.json()}async function P0(u,c,o){const r=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(o)});if(!r.ok)throw new pe(r.status,await Pa(r));return await r.json()}async function ex(u,c,o){const r=await Ge(u,`${Ia(u)}/${encodeURIComponent(c)}/conformance`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({fields:o})});if(!r.ok)throw new pe(r.status,await Pa(r));return await r.json()}function Wh({vaultName:u}={}){const c=_u(),o=u??c.name,d=u!==void 0?"/":`/vault/${encodeURIComponent(o??"")}`,[h,g]=y.useState({kind:"loading"}),[S,x]=y.useState(0),[p,E]=y.useState(null);y.useEffect(()=>{let V=!1;if(o)return g({kind:"loading"}),F0(o).then(D=>{V||g({kind:"ok",tags:D})}).catch(D=>{if(!V){if(D instanceof pe&&(D.status===401||D.status===403)){g({kind:"auth-required",status:D.status});return}g({kind:"error",message:D instanceof Error?D.message:String(D)})}}),()=>{V=!0}},[o,S]);const v=y.useCallback(()=>x(V=>V+1),[]),C=y.useCallback(()=>x(V=>V+1),[]);return o?i.jsxs("div",{children:[i.jsxs("div",{className:"list-header",children:[i.jsxs("h2",{children:["Schema for ",i.jsx("code",{children:o})]}),i.jsx(Ze,{to:d,className:"muted",children:"← Vault detail"})]}),i.jsxs("p",{className:"dim",style:{marginTop:0},children:["Tag schemas declare the metadata fields notes carry, which fields are indexed (queryable), and the tag hierarchy. Edits write the live schema directly — the same data an AI sees through ",i.jsx("code",{children:"update-tag"}),"."]}),h.kind==="loading"?i.jsx("p",{className:"muted",children:"Loading…"}):null,h.kind==="auth-required"?i.jsx(Zl,{vaultName:o,status:h.status,onRecovered:v}):null,h.kind==="error"?i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:h.message})}):null,h.kind==="ok"?i.jsxs("div",{className:"schema-layout",children:[i.jsx(nx,{tags:h.tags,selected:p,onSelect:E}),p?i.jsx(ux,{vaultName:o,tag:p,allTags:h.tags,onSaved:C},p):i.jsx("div",{className:"schema-detail",children:i.jsx("p",{className:"muted",children:"Select a tag to view or edit its schema."})})]}):null]}):i.jsxs("div",{children:[i.jsx("h2",{children:"Schema"}),i.jsx("p",{className:"muted",children:"Missing vault name."})]})}function tx(u){const c=u.fields??{},o=Object.values(c);return{hasSchema:u.description!==null&&u.description!==void 0||o.length>0,indexed:o.filter(r=>r.indexed===!0).length,strict:o.some(r=>r.strict===!0)}}function nx({tags:u,selected:c,onSelect:o}){const r=y.useMemo(()=>[...u].sort((d,h)=>d.name.localeCompare(h.name)),[u]);return i.jsx("div",{className:"schema-taglist",role:"navigation","aria-label":"Tags",children:i.jsxs("ul",{className:"tag-list",children:[r.map(d=>{const h=tx(d);return i.jsx("li",{children:i.jsxs("button",{type:"button",className:`tag-list-item${c===d.name?" selected":""}`,onClick:()=>o(d.name),"aria-current":c===d.name,children:[i.jsx("code",{className:"tag-name",children:d.name}),i.jsxs("span",{className:"tag-meta",children:[i.jsx("span",{className:"dim",children:d.count}),h.hasSchema?i.jsx("span",{className:"badge",children:"schema"}):null,h.indexed>0?i.jsxs("span",{className:"badge",children:[h.indexed," indexed"]}):null,h.strict?i.jsx("span",{className:"badge badge-strict",children:"strict"}):null]})]})},d.name)}),r.length===0?i.jsx("li",{className:"muted",children:"No tags yet."}):null]})})}let lx=0;function Om(){return`row-${lx++}`}function ax(u){return u?Object.entries(u).map(([c,o])=>({key:Om(),name:c,spec:{...o}})):[]}function Ih(u){const c={};for(const o of u){const r=o.name.trim();if(!r)continue;const d={};o.spec.type&&(d.type=o.spec.type),o.spec.enum&&o.spec.enum.length>0&&(d.enum=o.spec.enum),o.spec.required&&(d.required=!0),o.spec.cardinality==="many"&&(d.cardinality="many"),o.spec.indexed&&(d.indexed=!0),o.spec.strict&&(d.strict=!0),o.spec.description&&o.spec.description.trim().length>0&&(d.description=o.spec.description.trim()),c[r]=d}return c}const ix=/^[a-zA-Z_][a-zA-Z0-9_]{0,62}$/;function ux({vaultName:u,tag:c,allTags:o,onSaved:r}){const d=Er(u),[h,g]=y.useState({kind:"loading"}),[S,x]=y.useState(0);y.useEffect(()=>{let E=!1;return g({kind:"loading"}),Promise.all([W0(u,c),I0(u,c)]).then(([v,C])=>{if(E)return;g({kind:"ok",record:v??{name:c,count:0,description:null,fields:null,relationships:null,parent_names:null,created_at:null,updated_at:null},effective:C})}).catch(v=>{if(!E){if(v instanceof pe&&(v.status===401||v.status===403)){g({kind:"auth-required",status:v.status});return}g({kind:"error",message:v instanceof Error?v.message:String(v)})}}),()=>{E=!0}},[u,c,S]);const p=y.useCallback(()=>x(E=>E+1),[]);return h.kind==="loading"?i.jsx("div",{className:"schema-detail",children:i.jsxs("p",{className:"muted",children:["Loading ",c,"…"]})}):h.kind==="auth-required"?i.jsx("div",{className:"schema-detail",children:i.jsx(Zl,{vaultName:u,status:h.status,onRecovered:p})}):h.kind==="error"?i.jsx("div",{className:"schema-detail",children:i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:h.message})})}):i.jsx(sx,{vaultName:u,tag:c,record:h.record,effective:h.effective,allTags:o,isAdmin:d,onSaved:()=>{x(E=>E+1),r()}})}function sx({vaultName:u,tag:c,record:o,effective:r,allTags:d,isAdmin:h,onSaved:g}){const[S,x]=y.useState(o.description??""),[p,E]=y.useState(()=>ax(o.fields)),[v,C]=y.useState(o.parent_names??[]),[V,D]=y.useState(!1),[k,H]=y.useState(null),[q,F]=y.useState(0),[B,z]=y.useState(null),[Z,K]=y.useState(!1),[X,ee]=y.useState(!1),ce=y.useMemo(()=>{const N=new Map;for(const Y of r.indexed_fields)N.set(Y.name,Y);return N},[r.indexed_fields]),ze=y.useMemo(()=>d.map(N=>N.name).filter(N=>N!==c).sort((N,Y)=>N.localeCompare(Y)),[d,c]),Oe=y.useMemo(()=>{var Q;const N=new Map(d.map(le=>[le.name,le])),Y=[];for(const le of v){const ue=N.get(le);(Q=ue==null?void 0:ue.parent_names)!=null&&Q.includes(c)&&Y.push(le)}return Y},[v,d,c]),De=y.useMemo(()=>{const N=new Set(Object.entries(o.fields??{}).filter(([,Q])=>Q.indexed===!0).map(([Q])=>Q)),Y=new Set(p.filter(Q=>Q.spec.indexed&&Q.name.trim()).map(Q=>Q.name.trim()));for(const Q of Y)if(!N.has(Q))return!0;for(const Q of N)if(!Y.has(Q))return!0;return!1},[p,o.fields]),Ce=y.useMemo(()=>dx(p),[p]),I=()=>{z(null),ee(!1)},ie=(N,Y,Q)=>{E(le=>le.map(ue=>ue.key===N?{...ue,name:Q!==void 0?Q:ue.name,spec:{...ue.spec,...Y}}:ue)),I()},M=()=>{E(N=>[...N,{key:Om(),name:"",spec:{type:"string"}}]),I()},J=N=>{E(Y=>Y.filter(Q=>Q.key!==N)),I()},ne=N=>{C(Y=>Y.includes(N)?Y.filter(Q=>Q!==N):[...Y,N]),I()},ye=async()=>{D(!0),H(null);try{const N=Ih(p);await P0(u,c,{description:S.trim().length>0?S.trim():null,fields:Object.keys(N).length>0?N:null,replace_fields:!0,parent_names:v.length>0?v:null}),F(Y=>Y+1),I(),setTimeout(()=>F(0),3e3),g()}catch(N){N instanceof pe?H(N.message):H(N instanceof Error?N.message:String(N))}finally{D(!1)}},$=async N=>{if(N.preventDefault(),!!h){if(Ce.length>0){H(Ce[0]);return}if(H(null),B&&B.violating_notes>0||X){await ye();return}K(!0);try{const Y=Ih(p),Q=await ex(u,c,Y);if(Q.violating_notes>0){z(Q);return}I(),await ye()}catch(Y){H(`Could not check existing notes for conformance (${Y instanceof Error?Y.message:String(Y)}). Click Save again to apply anyway — strict fields are still enforced on write.`),z(null),ee(!0)}finally{K(!1)}}},j=!h;return i.jsxs("form",{className:"schema-detail",onSubmit:$,children:[i.jsxs("div",{className:"list-header",children:[i.jsx("h3",{style:{margin:0},children:i.jsx("code",{children:c})}),i.jsxs("span",{className:"dim",children:[o.count," note",o.count===1?"":"s"]})]}),j?i.jsxs("div",{className:"warn-banner",role:"status",children:["You're viewing with a read-only token. Saving requires"," ",i.jsxs("code",{children:["vault:",u,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin session to edit.`]}):null,i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"tag-description",children:"Description"}),i.jsx("textarea",{id:"tag-description",value:S,disabled:j,rows:2,onChange:N=>{x(N.target.value),I()},placeholder:"What this tag means + how to use it (sent to AI clients)."})]}),i.jsxs("fieldset",{className:"schema-fields",children:[i.jsx("legend",{children:"Fields"}),p.length===0?i.jsx("p",{className:"dim",children:"No fields declared. Add one to start a schema."}):null,p.map(N=>{var Y;return i.jsx(cx,{row:N,readOnly:j,coDeclarers:N.spec.indexed?(((Y=ce.get(N.name.trim()))==null?void 0:Y.tags)??[]).filter(Q=>Q!==c):[],onChange:(Q,le)=>ie(N.key,Q,le),onRemove:()=>J(N.key)},N.key)}),j?null:i.jsx("button",{type:"button",className:"secondary",onClick:M,children:"+ Add field"})]}),i.jsxs("fieldset",{className:"schema-parents",children:[i.jsx("legend",{children:"Parents (hierarchy)"}),i.jsxs("p",{className:"dim",style:{marginTop:0},children:["A note on ",i.jsx("code",{children:c})," inherits the fields of every parent (and their ancestors). Queries for a parent also match this tag."]}),ze.length===0?i.jsx("p",{className:"dim",children:"No other tags to pick as parents yet."}):i.jsx("div",{className:"parent-grid",children:ze.map(N=>i.jsxs("label",{className:"parent-chip",children:[i.jsx("input",{type:"checkbox",checked:v.includes(N),disabled:j,onChange:()=>ne(N)}),i.jsx("code",{children:N})]},N))}),Oe.length>0?i.jsxs("div",{className:"warn-banner",role:"alert",style:{marginTop:"0.5rem"},children:["Cycle warning: ",i.jsx("code",{children:Oe.join(", ")})," already list(s) ",i.jsx("code",{children:c})," as a parent. A cycle is tolerated at runtime but is almost always a config bug."]}):null]}),i.jsx(rx,{tag:c,effective:r}),i.jsx(ox,{catalog:r.indexed_fields,tag:c}),Ce.length>0?i.jsxs("div",{className:"warn-banner",role:"alert",children:[i.jsx("strong",{children:"Fix before saving:"}),i.jsx("ul",{style:{margin:"0.4rem 0 0"},children:Ce.map(N=>i.jsx("li",{children:N},N))})]}):null,De&&!j?i.jsxs("div",{className:"info-banner",role:"status",children:["This save changes which fields are indexed. Vault will rebuild the backing column + index (an ",i.jsx("code",{children:"ALTER TABLE"})," / index build) — on a large vault this can take a moment."]}):null,B&&B.violating_notes>0?i.jsx(fx,{report:B,tag:c}):null,k?i.jsx("div",{className:"error-banner",role:"alert",children:i.jsx("code",{children:k})}):null,q>0?i.jsx("div",{className:"mint-banner",style:{padding:"0.75rem 1rem",margin:"1rem 0"},role:"status",children:"Saved."}):null,i.jsx("div",{className:"actions",children:i.jsx("button",{type:"submit",disabled:j||V||Z,children:V?"Saving…":Z?"Checking existing notes…":B&&B.violating_notes>0||X?"Save anyway":"Save"})})]})}function cx({row:u,readOnly:c,coDeclarers:o,onChange:r,onRemove:d}){const{name:h,spec:g}=u,S=rr.has(g.type??""),x=(g.enum??[]).join(", ");return i.jsxs("div",{className:"field-row",children:[i.jsxs("div",{className:"field-row-main",children:[i.jsx("input",{"aria-label":"Field name",className:"field-name-input",type:"text",value:h,disabled:c,placeholder:"field_name",onChange:p=>r({},p.target.value)}),i.jsxs("select",{"aria-label":"Field type",value:g.type??"",disabled:c,onChange:p=>{const E=p.target.value||void 0,v={type:E};E&&!rr.has(E)&&(v.indexed=!1),r(v)},children:[i.jsx("option",{value:"",children:"(any)"}),$0.map(p=>i.jsx("option",{value:p,children:p},p))]}),i.jsxs("label",{className:"field-flag",children:[i.jsx("input",{type:"checkbox",checked:g.required===!0,disabled:c,onChange:p=>r({required:p.target.checked})}),"required"]}),i.jsxs("label",{className:"field-flag",children:[i.jsx("input",{type:"checkbox",checked:g.cardinality==="many",disabled:c,onChange:p=>r({cardinality:p.target.checked?"many":"one"})}),"many"]}),i.jsxs("label",{className:"field-flag",title:S?void 0:"Only string / integer / boolean fields can be indexed",children:[i.jsx("input",{type:"checkbox",checked:g.indexed===!0,disabled:c||!S,onChange:p=>r({indexed:p.target.checked})}),"indexed"]}),i.jsxs("label",{className:"field-flag",children:[i.jsx("input",{type:"checkbox",checked:g.strict===!0,disabled:c,onChange:p=>r({strict:p.target.checked})}),"strict"]}),c?null:i.jsx("button",{type:"button",className:"secondary field-remove",onClick:d,"aria-label":`Remove field ${h||"(unnamed)"}`,children:"✕"})]}),i.jsxs("div",{className:"field-row-extra",children:[i.jsx("input",{"aria-label":"Enum values (comma-separated)",type:"text",className:"field-enum-input",value:x,disabled:c,placeholder:"enum values (comma-separated, optional)",onChange:p=>{const E=p.target.value.split(",").map(v=>v.trim()).filter(v=>v.length>0);r({enum:E})}}),i.jsx("input",{"aria-label":"Field description",type:"text",className:"field-desc-input",value:g.description??"",disabled:c,placeholder:"description (optional)",onChange:p=>r({description:p.target.value})})]}),o.length>0?i.jsxs("p",{className:"dim field-codeclarers",children:["Also indexed by: ",o.map(p=>i.jsx("code",{children:p},p)),". Type + indexed are global across all of these — change them together."]}):null]})}function rx({tag:u,effective:c}){const o=new Set(Object.keys(c.fields??{})),r=Object.entries(c.effective_fields);return i.jsxs("div",{className:"schema-effective section",children:[i.jsx("h4",{style:{margin:"0 0 0.5rem"},children:"Effective fields (what a note actually gets)"}),c.effective_parents.length>0?i.jsxs("p",{className:"dim",style:{marginTop:0},children:["Inherits from: ",c.effective_parents.map(d=>i.jsx("code",{children:d},d))]}):i.jsxs("p",{className:"dim",style:{marginTop:0},children:["No parents — effective fields are just ",i.jsx("code",{children:u}),"'s own."]}),r.length===0?i.jsx("p",{className:"dim",children:"No fields (own or inherited)."}):i.jsxs("table",{className:"schema-table",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Field"}),i.jsx("th",{children:"Type"}),i.jsx("th",{children:"Source"}),i.jsx("th",{children:"Flags"})]})}),i.jsx("tbody",{children:r.map(([d,h])=>{const g=!o.has(d),S=[h.required?"required":null,h.cardinality==="many"?"many":null,h.strict?"strict":null,h.enum&&h.enum.length>0?`enum[${h.enum.length}]`:null].filter(Boolean);return i.jsxs("tr",{children:[i.jsx("td",{children:i.jsx("code",{children:d})}),i.jsx("td",{children:h.type??i.jsx("span",{className:"dim",children:"any"})}),i.jsx("td",{children:g?i.jsx("span",{className:"badge",children:"inherited"}):i.jsx("span",{className:"dim",children:"own"})}),i.jsx("td",{children:S.length>0?S.join(", "):i.jsx("span",{className:"dim",children:"—"})})]},d)})})]})]})}function ox({catalog:u,tag:c}){return i.jsxs("div",{className:"schema-catalog section",children:[i.jsx("h4",{style:{margin:"0 0 0.5rem"},children:"Indexed fields (what's queryable)"}),u.length===0?i.jsx("p",{className:"dim",children:"No indexed fields in this vault yet."}):i.jsxs("table",{className:"schema-table",children:[i.jsx("thead",{children:i.jsxs("tr",{children:[i.jsx("th",{children:"Field"}),i.jsx("th",{children:"Type"}),i.jsx("th",{children:"Declared by"})]})}),i.jsx("tbody",{children:u.map(o=>i.jsxs("tr",{className:o.tags.includes(c)?"row-this-tag":void 0,children:[i.jsx("td",{children:i.jsx("code",{children:o.name})}),i.jsx("td",{children:o.type}),i.jsx("td",{children:o.tags.map(r=>i.jsx("code",{className:r===c?"tag-self":void 0,children:r},r))})]},o.name))})]})]})}function fx({report:u,tag:c}){return i.jsxs("div",{className:"warn-banner",role:"alert",children:[i.jsxs("strong",{children:[u.violating_notes," existing note",u.violating_notes===1?"":"s"," violate this schema."]})," ","They'll be REJECTED on their next write once you tighten"," ",i.jsx("code",{children:u.checked_fields.join(", ")}),".",i.jsx("p",{style:{margin:"0.5rem 0"},children:"Migrate the existing data first with the CLI:"}),i.jsx("pre",{style:{margin:"0 0 0.5rem",whiteSpace:"pre-wrap"},children:i.jsxs("code",{children:["parachute-vault schema migrate-field ",c," <field> --transform …"]})}),u.sample.length>0?i.jsxs("details",{children:[i.jsxs("summary",{children:["Examples (",u.sample.length," of ",u.violating_notes,")"]}),i.jsx("ul",{style:{margin:"0.4rem 0 0"},children:u.sample.map(o=>i.jsxs("li",{children:[i.jsx("code",{children:o.path??o.id}),": ",o.fields.map(r=>r.reason).join(", ")]},o.id))})]}):null,i.jsxs("p",{className:"dim",style:{margin:"0.5rem 0 0",fontSize:"0.9em"},children:["Click ",i.jsx("strong",{children:"Save anyway"})," to apply the schema regardless — these notes stay readable but reject on edit until migrated."]})]})}function dx(u){const c=[],o=new Set;for(const r of u){const d=r.name.trim();if(d){if(o.has(d)){c.push(`Duplicate field name "${d}".`);continue}o.add(d),r.spec.indexed&&!ix.test(d)&&c.push(`"${d}" can't be indexed — indexed field names must start with a letter or underscore and contain only letters, digits, underscores (max 63 chars).`),r.spec.indexed&&r.spec.type&&!rr.has(r.spec.type)&&c.push(`"${d}" is indexed but type "${r.spec.type}" can't be indexed (use string / integer / boolean).`)}}return c}const hx=[30,90,180,365],Ph=90,mx=1440*60;function px(u){if(!u)return null;const c=u.scoped_tags;if(!Array.isArray(c))return null;const o=c.filter(r=>typeof r=="string"&&r.length>0);return o.length>0?o:null}function gx(u){return{jti:u.jti,label:u.subject,scopes:Array.isArray(u.scopes)?u.scopes:[],scoped_tags:px(u.permissions),expires_at:u.expires_at??null,revoked_at:u.revoked_at??null,created_at:u.created_at}}async function yx(u,c){const o={scope:`vault:${u}:${c.verb}`,expires_in:c.ttlDays*mx,subject:c.label};c.scopedTags.length>0&&(o.permissions={scoped_tags:c.scopedTags});const r=await Wa("/api/auth/mint-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(o)});if(!r.ok)throw new pe(r.status,await Cu(r));const d=await r.json();return{jti:d.jti,token:d.token,scope:d.scope,expires_at:d.expires_at??null}}async function vx(u){const c=`vault:${u}:`,o=[];let r=null;for(let d=0;d<1e3;d++){const h=new URLSearchParams({revoked:"all"});r&&h.set("cursor",r);const g=await Wa(`/api/auth/tokens?${h.toString()}`);if(!g.ok)throw new pe(g.status,await Cu(g));const S=await g.json(),x=Array.isArray(S.tokens)?S.tokens:[];if(o.push(...x),r=S.next_cursor??null,!r)break}return o.filter(d=>Array.isArray(d.scopes)&&d.scopes.some(h=>h.startsWith(c))).map(gx)}async function xx(u){const c=await Wa("/api/auth/revoke-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jti:u})});if(!c.ok)throw new pe(c.status,await Cu(c))}async function bx(u){const c=await Ge(u,`/vault/${encodeURIComponent(u)}/api/tags`);if(!c.ok)throw new pe(c.status,await Cu(c));const o=await c.json();return Array.isArray(o)?o:[]}async function Cu(u){try{const c=await u.text(),o=JSON.parse(c);if(o.error_description)return o.error_description;if(o.message)return o.message;if(o.error)return o.error;if(c)return c}catch{}return`${u.status} ${u.statusText}`}const jx=["read","write","admin"],Sx={30:"30 days",90:"90 days",180:"180 days",365:"1 year (max)"};function Ex(u){return u instanceof Ln?u.disposition==="forbidden"?(Ka(),{kind:"auth-required",status:403}):u.disposition==="auth-required"?{kind:"auth-required",status:u.status}:{kind:"error",message:u.message}:u instanceof pe&&(u.status===401||u.status===403)?{kind:"auth-required",status:u.status}:{kind:"error",message:u instanceof Error?u.message:String(u)}}function em({vaultName:u}={}){const c=_u(),o=u??c.name,r=u!==void 0,d=r?"/":`/vault/${encodeURIComponent(o??"")}`,[h,g]=y.useState({kind:"loading"}),[S,x]=y.useState(null),[p,E]=y.useState(null),[v,C]=y.useState(0);y.useEffect(()=>{let k=!1;if(o)return g({kind:"loading"}),vx(o).then(H=>{k||g({kind:"ok",tokens:H})}).catch(H=>{k||g(Ex(H))}),()=>{k=!0}},[o,v]);const V=y.useCallback(()=>C(k=>k+1),[]);if(y.useEffect(()=>{if(!S)return;const k=H=>{H.preventDefault(),H.returnValue=""};return window.addEventListener("beforeunload",k),()=>window.removeEventListener("beforeunload",k)},[S]),!o)return i.jsxs("div",{children:[i.jsx("h2",{children:"Tokens"}),i.jsx("p",{className:"muted",children:"Missing vault name."}),r?null:i.jsx(Ze,{to:"/",children:"← Back to vaults"})]});const D=Er(o);return i.jsxs("div",{children:[i.jsxs("div",{className:"list-header",children:[i.jsxs("h2",{children:["Tokens for ",i.jsx("code",{children:o})]}),i.jsx(Ze,{to:d,className:"muted",children:"← Vault detail"})]}),D?null:i.jsxs("div",{className:"warn-banner",children:["You're viewing this page with a read-only token. Mint and revoke require"," ",i.jsxs("code",{children:["vault:",o,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin-scoped session to manage tokens.`]}),S?i.jsx(Tx,{result:S,onDismiss:()=>x(null)}):null,h.kind==="ok"&&D&&!S?i.jsx(_x,{vaultName:o,onMinted:k=>{x(k),C(H=>H+1)}}):null,i.jsxs("div",{className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Existing tokens"}),h.kind==="loading"?i.jsx("p",{className:"muted",children:"Loading…"}):null,h.kind==="auth-required"?i.jsx(Zl,{vaultName:o,status:h.status,onRecovered:V}):null,h.kind==="error"?i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:h.message})}):null,h.kind==="ok"?i.jsx(Nx,{tokens:h.tokens,allowRevoke:D,confirmingJti:p,onAskConfirm:E,onRevoked:()=>{E(null),C(k=>k+1)}}):null]})]})}function Tx({result:u,onDismiss:c}){const[o,r]=y.useState(!1),d=async()=>{try{await navigator.clipboard.writeText(u.token),r(!0),setTimeout(()=>r(!1),2e3)}catch{}};return i.jsxs("div",{className:"mint-banner",children:[i.jsx("h3",{children:"New token (shown once)"}),i.jsx("p",{className:"muted",children:"This is the only time the vault will show this token. Copy it now and store it somewhere safe — a password manager, the operator's notes, paraclaw's secrets store. If you lose it, revoke it and mint a new one."}),i.jsxs("div",{className:"token-box",children:[i.jsx("code",{children:u.token}),i.jsx("button",{type:"button",onClick:d,className:"secondary",children:o?"Copied":"Copy"})]}),i.jsx("p",{className:"warn",children:"⚠ Don't dismiss this banner until you've saved the token."}),i.jsx("div",{className:"actions",children:i.jsx("button",{type:"button",onClick:c,children:"Done — I've saved the token"})})]})}function _x({vaultName:u,onMinted:c}){const[o,r]=y.useState(""),[d,h]=y.useState("admin"),[g,S]=y.useState(Ph),[x,p]=y.useState(!1),[E,v]=y.useState(null),[C,V]=y.useState([]),[D,k]=y.useState(null),[H,q]=y.useState(new Set);y.useEffect(()=>{let K=!1;return bx(u).then(X=>{if(K)return;const ee=X.map(ce=>ce.name).filter(ce=>!ce.includes("/")).sort();V(ee)}).catch(X=>{K||k(X instanceof Error?X.message:String(X))}),()=>{K=!0}},[u]);const F=o.trim(),B=F.length===0,z=K=>{q(X=>{const ee=new Set(X);return ee.has(K)?ee.delete(K):ee.add(K),ee})},Z=async K=>{if(K.preventDefault(),B){v("label required — give the token a recognizable name");return}p(!0),v(null);try{const X=await yx(u,{verb:d,label:F,scopedTags:[...H],ttlDays:g});c(X),r(""),h("admin"),S(Ph),q(new Set)}catch(X){if(X instanceof Ln&&X.disposition==="forbidden"){Ka();return}v(X instanceof Error?X.message:String(X))}finally{p(!1)}};return i.jsxs("form",{onSubmit:Z,className:"section",children:[i.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Mint a token"}),i.jsx("p",{className:"dim",style:{margin:"0 0 0.85rem"},children:"Issues a hub-signed token (JWT) scoped to this vault. Store it like a password — it's shown once and can't be re-displayed."}),E?i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:E})}):null,i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{htmlFor:"mint-label",children:["Label ",i.jsx("span",{className:"dim",children:"(required)"})]}),i.jsx("input",{id:"mint-label",type:"text",value:o,onChange:K=>r(K.target.value),placeholder:"e.g. ci, paraclaw-prod, my-laptop",maxLength:120,required:!0})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"mint-scope",children:"Scope"}),i.jsx("select",{id:"mint-scope",value:d,onChange:K=>h(K.target.value),children:jx.map(K=>i.jsx("option",{value:K,children:K==="read"?"read — query notes only":K==="write"?"write — query + create/update notes":"admin — full control (incl. token mgmt)"},K))}),i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Issued as ",i.jsxs("code",{children:["vault:",u,":",d]}),". Lower scopes inherit narrower powers."]})]}),i.jsxs("div",{className:"form-row",children:[i.jsx("label",{htmlFor:"mint-ttl",children:"Expires after"}),i.jsx("select",{id:"mint-ttl",value:g,onChange:K=>S(Number(K.target.value)),children:hx.map(K=>i.jsx("option",{value:K,children:Sx[K]??`${K} days`},K))}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"The token stops working after this. Rotate before it lapses."})]}),i.jsxs("div",{className:"form-row",children:[i.jsxs("label",{children:["Tag scope ",i.jsx("span",{className:"dim",children:"(optional)"})]}),D?i.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Couldn't load tags: ",i.jsx("code",{children:D}),". Token will be unscoped."]}):C.length===0?i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"No root tags in this vault yet — token will see the full vault."}):i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"tag-picker",children:C.map(K=>i.jsxs("label",{className:"tag-checkbox",children:[i.jsx("input",{type:"checkbox",checked:H.has(K),onChange:()=>z(K)}),i.jsx("code",{children:K})]},K))}),i.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:H.size===0?"Nothing selected — token sees the full vault (unscoped).":`Token limited to: ${[...H].join(", ")}. Sub-tags (e.g. health/food) are reachable when their root is selected.`})]})]}),i.jsx("div",{className:"actions",children:i.jsx("button",{type:"submit",disabled:x||B,children:x?"Minting…":"Mint token"})})]})}function Nx({tokens:u,allowRevoke:c,confirmingJti:o,onAskConfirm:r,onRevoked:d}){return u.length===0?i.jsx("p",{className:"muted",children:"No tokens yet. Mint one above to get started."}):i.jsx("div",{className:"token-list",children:u.map(h=>i.jsx(wx,{token:h,allowRevoke:c,confirming:o===h.jti,onAskConfirm:r,onRevoked:d},h.jti))})}function wx({token:u,allowRevoke:c,confirming:o,onAskConfirm:r,onRevoked:d}){const[h,g]=y.useState(!1),[S,x]=y.useState(null),p=u.revoked_at!==null,E=async()=>{g(!0),x(null);try{await xx(u.jti),d()}catch(v){if(v instanceof Ln&&v.disposition==="forbidden"){Ka();return}x(v instanceof Error?v.message:String(v)),g(!1)}};return i.jsxs("div",{className:"token-row",children:[i.jsxs("div",{className:"body",children:[i.jsxs("div",{className:"name",children:[i.jsx("strong",{children:u.label??"(unlabeled)"}),i.jsx("code",{className:"dim",children:u.jti}),p?i.jsx("code",{className:"scope-tag",title:"This token has been revoked and no longer works.",children:"revoked"}):null]}),i.jsxs("div",{className:"meta",children:[i.jsx("span",{className:"dim",children:"scopes:"})," ",u.scopes.length>0?u.scopes.map(v=>i.jsx("code",{className:"scope-tag",children:v},v)):i.jsx("span",{className:"dim",children:"(none)"})]}),u.scoped_tags&&u.scoped_tags.length>0?i.jsxs("div",{className:"meta",children:[i.jsx("span",{className:"dim",children:"tags:"})," ",u.scoped_tags.map(v=>i.jsxs("code",{className:"scope-tag tag-pill",children:["#",v]},v))]}):null,i.jsxs("div",{className:"meta dim",children:["created ",u.created_at,u.expires_at?` · expires ${u.expires_at}`:"",p&&u.revoked_at?` · revoked ${u.revoked_at}`:""]}),S?i.jsx("div",{className:"error-banner",style:{marginTop:"0.5rem"},children:i.jsx("code",{children:S})}):null]}),c&&!p?o?i.jsxs("div",{className:"actions",children:[i.jsx("button",{type:"button",onClick:E,disabled:h,children:h?"Revoking…":"Confirm revoke"}),i.jsx("button",{type:"button",className:"secondary",onClick:()=>r(null),disabled:h,children:"Cancel"})]}):i.jsx("button",{type:"button",className:"secondary",onClick:()=>r(u.jti),children:"Revoke"}):null]})}function Cx(){const[u,c]=y.useState({kind:"loading"});return y.useEffect(()=>{let o=!1;return _m().then(r=>{o||c({kind:"ok",vaults:r})}).catch(r=>{if(o)return;const d=r instanceof pe?`${r.status}: ${r.message}`:r instanceof Error?r.message:String(r);c({kind:"error",message:d})}),()=>{o=!0}},[]),u.kind==="loading"?i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsx("p",{className:"muted",children:"Loading…"})]}):u.kind==="error"?i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsx("div",{className:"error-banner",children:i.jsx("code",{children:u.message})})]}):u.vaults.length===0?i.jsxs("div",{children:[i.jsx("h2",{children:"Vaults"}),i.jsxs("div",{className:"empty",children:["No vaults yet. Run ",i.jsx("code",{children:"parachute-vault create <name>"})," on the host to create one."]})]}):i.jsxs("div",{children:[i.jsx("div",{className:"list-header",children:i.jsx("h2",{children:"Vaults"})}),u.vaults.map(o=>i.jsxs(Ze,{to:`/vault/${o}`,className:"vault-row",children:[i.jsx("div",{className:"body",children:i.jsx("div",{className:"name",children:i.jsx("code",{children:o})})}),i.jsx("div",{className:"chev",children:"→"})]},o))]})}function Ax(){const u=xr(),c=u?null:Em();return i.jsxs("div",{className:"page",children:[i.jsxs("nav",{className:"nav",children:[i.jsxs(Ze,{to:"/",className:"brand",children:["Parachute Vault ",i.jsx("span",{className:"sub",children:"admin"})]}),c?i.jsx(Ze,{to:"/",children:i.jsx("code",{children:c})}):i.jsx(Ze,{to:"/",children:"Vaults"})]}),u?i.jsxs(tr,{children:[i.jsx(ft,{path:"/",element:i.jsx(_0,{})}),i.jsx(ft,{path:"*",element:i.jsx(lr,{})})]}):c?i.jsxs(tr,{children:[i.jsx(ft,{path:"/",element:i.jsx(Jh,{vaultName:c})}),i.jsx(ft,{path:"/tokens",element:i.jsx(em,{vaultName:c})}),i.jsx(ft,{path:"/mirror",element:i.jsx($h,{vaultName:c})}),i.jsx(ft,{path:"/schema",element:i.jsx(Wh,{vaultName:c})}),i.jsx(ft,{path:"*",element:i.jsx(lr,{})})]}):i.jsxs(tr,{children:[i.jsx(ft,{path:"/",element:i.jsx(Cx,{})}),i.jsx(ft,{path:"/vault/:name",element:i.jsx(Jh,{})}),i.jsx(ft,{path:"/vault/:name/tokens",element:i.jsx(em,{})}),i.jsx(ft,{path:"/vault/:name/mirror",element:i.jsx($h,{})}),i.jsx(ft,{path:"/vault/:name/schema",element:i.jsx(Wh,{})}),i.jsx(ft,{path:"*",element:i.jsx(lr,{})})]})]})}function lr(){return i.jsxs("div",{className:"empty",children:["404 — back to ",i.jsx(Ze,{to:"/",children:"vault"}),"."]})}$v();const Dm=document.getElementById("root");if(!Dm)throw new Error("#root not found");function ar(){my.createRoot(Dm).render(i.jsx(y.StrictMode,{children:i.jsx(Dv,{basename:Qv(),children:i.jsx(Ax,{})})}))}const tm=Em();!xr()&&tm?Iv(tm).then(ar,ar):ar();