@openparachute/vault 0.5.2 → 0.5.3-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.
- package/core/src/core.test.ts +89 -0
- package/core/src/links.ts +19 -1
- package/core/src/mcp.ts +60 -20
- package/core/src/types.ts +10 -0
- package/package.json +1 -1
- package/src/config.test.ts +66 -0
- package/src/config.ts +31 -10
- package/src/mcp-tools.ts +20 -1
- package/src/routes.ts +52 -24
- package/src/routing.test.ts +192 -1
- package/src/routing.ts +32 -1
- package/src/vault.test.ts +40 -0
- package/web/ui/dist/assets/{index-D8nCVT1e.js → index-DJL6Az--.js} +1 -1
- package/web/ui/dist/index.html +1 -1
|
@@ -57,4 +57,4 @@ Error generating stack: `+a.message+`
|
|
|
57
57
|
* @license MIT
|
|
58
58
|
*/var Ah="popstate";function Nh(i){return typeof i=="object"&&i!=null&&"pathname"in i&&"search"in i&&"hash"in i&&"state"in i&&"key"in i}function Wy(i={}){function s(r,h){var v;let m=(v=h.state)==null?void 0:v.masked,{pathname:y,search:E,hash:b}=m||r.location;return Fs("",{pathname:y,search:E,hash:b},h.state&&h.state.usr||null,h.state&&h.state.key||"default",m?{pathname:r.location.pathname,search:r.location.search,hash:r.location.hash}:void 0)}function f(r,h){return typeof h=="string"?h:Qn(h)}return Py(s,f,null,i)}function ze(i,s){if(i===!1||i===null||typeof i>"u")throw new Error(s)}function Xt(i,s){if(!i){typeof console<"u"&&console.warn(s);try{throw new Error(s)}catch{}}}function Iy(){return Math.random().toString(36).substring(2,10)}function Rh(i,s){return{usr:i.state,key:i.key,idx:s,masked:i.unstable_mask?{pathname:i.pathname,search:i.search,hash:i.hash}:void 0}}function Fs(i,s,f=null,r,h){return{pathname:typeof i=="string"?i:i.pathname,search:"",hash:"",...typeof s=="string"?Xa(s):s,state:f,key:s&&s.key||r||Iy(),unstable_mask:h}}function Qn({pathname:i="/",search:s="",hash:f=""}){return s&&s!=="?"&&(i+=s.charAt(0)==="?"?s:"?"+s),f&&f!=="#"&&(i+=f.charAt(0)==="#"?f:"#"+f),i}function Xa(i){let s={};if(i){let f=i.indexOf("#");f>=0&&(s.hash=i.substring(f),i=i.substring(0,f));let r=i.indexOf("?");r>=0&&(s.search=i.substring(r),i=i.substring(0,r)),i&&(s.pathname=i)}return s}function Py(i,s,f,r={}){let{window:h=document.defaultView,v5Compat:m=!1}=r,y=h.history,E="POP",b=null,v=_();v==null&&(v=0,y.replaceState({...y.state,idx:v},""));function _(){return(y.state||{idx:null}).idx}function g(){E="POP";let q=_(),L=q==null?null:q-v;v=q,b&&b({action:E,location:B.location,delta:L})}function R(q,L){E="PUSH";let X=Nh(q)?q:Fs(B.location,q,L);v=_()+1;let J=Rh(X,v),V=B.createHref(X.unstable_mask||X);try{y.pushState(J,"",V)}catch(Y){if(Y instanceof DOMException&&Y.name==="DataCloneError")throw Y;h.location.assign(V)}m&&b&&b({action:E,location:B.location,delta:1})}function k(q,L){E="REPLACE";let X=Nh(q)?q:Fs(B.location,q,L);v=_();let J=Rh(X,v),V=B.createHref(X.unstable_mask||X);y.replaceState(J,"",V),m&&b&&b({action:E,location:B.location,delta:0})}function D(q){return ep(q)}let B={get action(){return E},get location(){return i(h,y)},listen(q){if(b)throw new Error("A history only accepts one active listener");return h.addEventListener(Ah,g),b=q,()=>{h.removeEventListener(Ah,g),b=null}},createHref(q){return s(h,q)},createURL:D,encodeLocation(q){let L=D(q);return{pathname:L.pathname,search:L.search,hash:L.hash}},push:R,replace:k,go(q){return y.go(q)}};return B}function ep(i,s=!1){let f="http://localhost";typeof window<"u"&&(f=window.location.origin!=="null"?window.location.origin:window.location.href),ze(f,"No window.location.(origin|href) available to create URL");let r=typeof i=="string"?i:Qn(i);return r=r.replace(/ $/,"%20"),!s&&r.startsWith("//")&&(r=f+r),new URL(r,f)}function Qh(i,s,f="/"){return tp(i,s,f,!1)}function tp(i,s,f,r){let h=typeof s=="string"?Xa(s):s,m=ol(h.pathname||"/",f);if(m==null)return null;let y=Vh(i);lp(y);let E=null;for(let b=0;E==null&&b<y.length;++b){let v=hp(m);E=fp(y[b],v,r)}return E}function Vh(i,s=[],f=[],r="",h=!1){let m=(y,E,b=h,v)=>{let _={relativePath:v===void 0?y.path||"":v,caseSensitive:y.caseSensitive===!0,childrenIndex:E,route:y};if(_.relativePath.startsWith("/")){if(!_.relativePath.startsWith(r)&&b)return;ze(_.relativePath.startsWith(r),`Absolute route path "${_.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),_.relativePath=_.relativePath.slice(r.length)}let g=Ut([r,_.relativePath]),R=f.concat(_);y.children&&y.children.length>0&&(ze(y.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${g}".`),Vh(y.children,s,R,g,b)),!(y.path==null&&!y.index)&&s.push({path:g,score:rp(g,y.index),routesMeta:R})};return i.forEach((y,E)=>{var b;if(y.path===""||!((b=y.path)!=null&&b.includes("?")))m(y,E);else for(let v of Zh(y.path))m(y,E,!0,v)}),s}function Zh(i){let s=i.split("/");if(s.length===0)return[];let[f,...r]=s,h=f.endsWith("?"),m=f.replace(/\?$/,"");if(r.length===0)return h?[m,""]:[m];let y=Zh(r.join("/")),E=[];return E.push(...y.map(b=>b===""?m:[m,b].join("/"))),h&&E.push(...y),E.map(b=>i.startsWith("/")&&b===""?"/":b)}function lp(i){i.sort((s,f)=>s.score!==f.score?f.score-s.score:op(s.routesMeta.map(r=>r.childrenIndex),f.routesMeta.map(r=>r.childrenIndex)))}var ap=/^:[\w-]+$/,np=3,up=2,ip=1,cp=10,sp=-2,zh=i=>i==="*";function rp(i,s){let f=i.split("/"),r=f.length;return f.some(zh)&&(r+=sp),s&&(r+=up),f.filter(h=>!zh(h)).reduce((h,m)=>h+(ap.test(m)?np:m===""?ip:cp),r)}function op(i,s){return i.length===s.length&&i.slice(0,-1).every((r,h)=>r===s[h])?i[i.length-1]-s[s.length-1]:0}function fp(i,s,f=!1){let{routesMeta:r}=i,h={},m="/",y=[];for(let E=0;E<r.length;++E){let b=r[E],v=E===r.length-1,_=m==="/"?s:s.slice(m.length)||"/",g=yi({path:b.relativePath,caseSensitive:b.caseSensitive,end:v},_),R=b.route;if(!g&&v&&f&&!r[r.length-1].route.index&&(g=yi({path:b.relativePath,caseSensitive:b.caseSensitive,end:!1},_)),!g)return null;Object.assign(h,g.params),y.push({params:h,pathname:Ut([m,g.pathname]),pathnameBase:pp(Ut([m,g.pathnameBase])),route:R}),g.pathnameBase!=="/"&&(m=Ut([m,g.pathnameBase]))}return y}function yi(i,s){typeof i=="string"&&(i={path:i,caseSensitive:!1,end:!0});let[f,r]=dp(i.path,i.caseSensitive,i.end),h=s.match(f);if(!h)return null;let m=h[0],y=m.replace(/(.)\/+$/,"$1"),E=h.slice(1);return{params:r.reduce((v,{paramName:_,isOptional:g},R)=>{if(_==="*"){let D=E[R]||"";y=m.slice(0,m.length-D.length).replace(/(.)\/+$/,"$1")}const k=E[R];return g&&!k?v[_]=void 0:v[_]=(k||"").replace(/%2F/g,"/"),v},{}),pathname:m,pathnameBase:y,pattern:i}}function dp(i,s=!1,f=!0){Xt(i==="*"||!i.endsWith("*")||i.endsWith("/*"),`Route path "${i}" will be treated as if it were "${i.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${i.replace(/\*$/,"/*")}".`);let r=[],h="^"+i.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(y,E,b,v,_)=>{if(r.push({paramName:E,isOptional:b!=null}),b){let g=_.charAt(v+y.length);return g&&g!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return i.endsWith("*")?(r.push({paramName:"*"}),h+=i==="*"||i==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):f?h+="\\/*$":i!==""&&i!=="/"&&(h+="(?:(?=\\/|$))"),[new RegExp(h,s?void 0:"i"),r]}function hp(i){try{return i.split("/").map(s=>decodeURIComponent(s).replace(/\//g,"%2F")).join("/")}catch(s){return Xt(!1,`The URL path "${i}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${s}).`),i}}function ol(i,s){if(s==="/")return i;if(!i.toLowerCase().startsWith(s.toLowerCase()))return null;let f=s.endsWith("/")?s.length-1:s.length,r=i.charAt(f);return r&&r!=="/"?null:i.slice(f)||"/"}var mp=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function vp(i,s="/"){let{pathname:f,search:r="",hash:h=""}=typeof i=="string"?Xa(i):i,m;return f?(f=Jh(f),f.startsWith("/")?m=Ch(f.substring(1),"/"):m=Ch(f,s)):m=s,{pathname:m,search:gp(r),hash:bp(h)}}function Ch(i,s){let f=pi(s).split("/");return i.split("/").forEach(h=>{h===".."?f.length>1&&f.pop():h!=="."&&f.push(h)}),f.length>1?f.join("/"):"/"}function Zs(i,s,f,r){return`Cannot include a '${i}' character in a manually specified \`to.${s}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${f}\` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.`}function yp(i){return i.filter((s,f)=>f===0||s.route.path&&s.route.path.length>0)}function Kh(i){let s=yp(i);return s.map((f,r)=>r===s.length-1?f.pathname:f.pathnameBase)}function er(i,s,f,r=!1){let h;typeof i=="string"?h=Xa(i):(h={...i},ze(!h.pathname||!h.pathname.includes("?"),Zs("?","pathname","search",h)),ze(!h.pathname||!h.pathname.includes("#"),Zs("#","pathname","hash",h)),ze(!h.search||!h.search.includes("#"),Zs("#","search","hash",h)));let m=i===""||h.pathname==="",y=m?"/":h.pathname,E;if(y==null)E=f;else{let g=s.length-1;if(!r&&y.startsWith("..")){let R=y.split("/");for(;R[0]==="..";)R.shift(),g-=1;h.pathname=R.join("/")}E=g>=0?s[g]:"/"}let b=vp(h,E),v=y&&y!=="/"&&y.endsWith("/"),_=(m||y===".")&&f.endsWith("/");return!b.pathname.endsWith("/")&&(v||_)&&(b.pathname+="/"),b}var Jh=i=>i.replace(/\/\/+/g,"/"),Ut=i=>Jh(i.join("/")),pi=i=>i.replace(/\/+$/,""),pp=i=>pi(i).replace(/^\/*/,"/"),gp=i=>!i||i==="?"?"":i.startsWith("?")?i:"?"+i,bp=i=>!i||i==="#"?"":i.startsWith("#")?i:"#"+i,Sp=class{constructor(i,s,f,r=!1){this.status=i,this.statusText=s||"",this.internal=r,f instanceof Error?(this.data=f.toString(),this.error=f):this.data=f}};function xp(i){return i!=null&&typeof i.status=="number"&&typeof i.statusText=="string"&&typeof i.internal=="boolean"&&"data"in i}function jp(i){let s=i.map(f=>f.route.path).filter(Boolean);return Ut(s)||"/"}var $h=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Fh(i,s){let f=i;if(typeof f!="string"||!mp.test(f))return{absoluteURL:void 0,isExternal:!1,to:f};let r=f,h=!1;if($h)try{let m=new URL(window.location.href),y=f.startsWith("//")?new URL(m.protocol+f):new URL(f),E=ol(y.pathname,s);y.origin===m.origin&&E!=null?f=E+y.search+y.hash:h=!0}catch{Xt(!1,`<Link to="${f}"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:h,to:f}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var Wh=["POST","PUT","PATCH","DELETE"];new Set(Wh);var Ep=["GET",...Wh];new Set(Ep);var Qa=S.createContext(null);Qa.displayName="DataRouter";var gi=S.createContext(null);gi.displayName="DataRouterState";var Ih=S.createContext(!1);function Tp(){return S.useContext(Ih)}var Ph=S.createContext({isTransitioning:!1});Ph.displayName="ViewTransition";var _p=S.createContext(new Map);_p.displayName="Fetchers";var Ap=S.createContext(null);Ap.displayName="Await";var wt=S.createContext(null);wt.displayName="Navigation";var Zn=S.createContext(null);Zn.displayName="Location";var Qt=S.createContext({outlet:null,matches:[],isDataRoute:!1});Qt.displayName="Route";var tr=S.createContext(null);tr.displayName="RouteError";var em="REACT_ROUTER_ERROR",Np="REDIRECT",Rp="ROUTE_ERROR_RESPONSE";function zp(i){if(i.startsWith(`${em}:${Np}:{`))try{let s=JSON.parse(i.slice(28));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string"&&typeof s.location=="string"&&typeof s.reloadDocument=="boolean"&&typeof s.replace=="boolean")return s}catch{}}function Cp(i){if(i.startsWith(`${em}:${Rp}:{`))try{let s=JSON.parse(i.slice(40));if(typeof s=="object"&&s&&typeof s.status=="number"&&typeof s.statusText=="string")return new Sp(s.status,s.statusText,s.data)}catch{}}function wp(i,{relative:s}={}){ze(Kn(),"useHref() may be used only in the context of a <Router> component.");let{basename:f,navigator:r}=S.useContext(wt),{hash:h,pathname:m,search:y}=Jn(i,{relative:s}),E=m;return f!=="/"&&(E=m==="/"?f:Ut([f,m])),r.createHref({pathname:E,search:y,hash:h})}function Kn(){return S.useContext(Zn)!=null}function fl(){return ze(Kn(),"useLocation() may be used only in the context of a <Router> component."),S.useContext(Zn).location}var tm="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function lm(i){S.useContext(wt).static||S.useLayoutEffect(i)}function Mp(){let{isDataRoute:i}=S.useContext(Qt);return i?Vp():Op()}function Op(){ze(Kn(),"useNavigate() may be used only in the context of a <Router> component.");let i=S.useContext(Qa),{basename:s,navigator:f}=S.useContext(wt),{matches:r}=S.useContext(Qt),{pathname:h}=fl(),m=JSON.stringify(Kh(r)),y=S.useRef(!1);return lm(()=>{y.current=!0}),S.useCallback((b,v={})=>{if(Xt(y.current,tm),!y.current)return;if(typeof b=="number"){f.go(b);return}let _=er(b,JSON.parse(m),h,v.relative==="path");i==null&&s!=="/"&&(_.pathname=_.pathname==="/"?s:Ut([s,_.pathname])),(v.replace?f.replace:f.push)(_,v.state,v)},[s,f,m,h,i])}S.createContext(null);function lr(){let{matches:i}=S.useContext(Qt),s=i[i.length-1];return(s==null?void 0:s.params)??{}}function Jn(i,{relative:s}={}){let{matches:f}=S.useContext(Qt),{pathname:r}=fl(),h=JSON.stringify(Kh(f));return S.useMemo(()=>er(i,JSON.parse(h),r,s==="path"),[i,h,r,s])}function Dp(i,s){return am(i,s)}function am(i,s,f){var q;ze(Kn(),"useRoutes() may be used only in the context of a <Router> component.");let{navigator:r}=S.useContext(wt),{matches:h}=S.useContext(Qt),m=h[h.length-1],y=m?m.params:{},E=m?m.pathname:"/",b=m?m.pathnameBase:"/",v=m&&m.route;{let L=v&&v.path||"";um(E,!v||L.endsWith("*")||L.endsWith("*?"),`You rendered descendant <Routes> (or called \`useRoutes()\`) at "${E}" (under <Route path="${L}">) 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
|
-
Please change the parent <Route path="${L}"> to <Route path="${L==="/"?"*":`${L}/*`}">.`)}let _=fl(),g;if(s){let L=typeof s=="string"?Xa(s):s;ze(b==="/"||((q=L.pathname)==null?void 0:q.startsWith(b)),`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 "${b}" but pathname "${L.pathname}" was given in the \`location\` prop.`),g=L}else g=_;let R=g.pathname||"/",k=R;if(b!=="/"){let L=b.replace(/^\//,"").split("/");k="/"+R.replace(/^\//,"").split("/").slice(L.length).join("/")}let D=Qh(i,{pathname:k});Xt(v||D!=null,`No routes matched location "${g.pathname}${g.search}${g.hash}" `),Xt(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 "${g.pathname}${g.search}${g.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 B=kp(D&&D.map(L=>Object.assign({},L,{params:Object.assign({},y,L.params),pathname:Ut([b,r.encodeLocation?r.encodeLocation(L.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:L.pathname]),pathnameBase:L.pathnameBase==="/"?b:Ut([b,r.encodeLocation?r.encodeLocation(L.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:L.pathnameBase])})),h,f);return s&&B?S.createElement(Zn.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",unstable_mask:void 0,...g},navigationType:"POP"}},B):B}function Up(){let i=Qp(),s=xp(i)?`${i.status} ${i.statusText}`:i instanceof Error?i.message:JSON.stringify(i),f=i instanceof Error?i.stack:null,r="rgba(200,200,200, 0.5)",h={padding:"0.5rem",backgroundColor:r},m={padding:"2px 4px",backgroundColor:r},y=null;return console.error("Error handled by React Router default ErrorBoundary:",i),y=S.createElement(S.Fragment,null,S.createElement("p",null,"💿 Hey developer 👋"),S.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",S.createElement("code",{style:m},"ErrorBoundary")," or"," ",S.createElement("code",{style:m},"errorElement")," prop on your route.")),S.createElement(S.Fragment,null,S.createElement("h2",null,"Unexpected Application Error!"),S.createElement("h3",{style:{fontStyle:"italic"}},s),f?S.createElement("pre",{style:h},f):null,y)}var Hp=S.createElement(Up,null),nm=class extends S.Component{constructor(i){super(i),this.state={location:i.location,revalidation:i.revalidation,error:i.error}}static getDerivedStateFromError(i){return{error:i}}static getDerivedStateFromProps(i,s){return s.location!==i.location||s.revalidation!=="idle"&&i.revalidation==="idle"?{error:i.error,location:i.location,revalidation:i.revalidation}:{error:i.error!==void 0?i.error:s.error,location:s.location,revalidation:i.revalidation||s.revalidation}}componentDidCatch(i,s){this.props.onError?this.props.onError(i,s):console.error("React Router caught the following error during render",i)}render(){let i=this.state.error;if(this.context&&typeof i=="object"&&i&&"digest"in i&&typeof i.digest=="string"){const f=Cp(i.digest);f&&(i=f)}let s=i!==void 0?S.createElement(Qt.Provider,{value:this.props.routeContext},S.createElement(tr.Provider,{value:i,children:this.props.component})):this.props.children;return this.context?S.createElement(Bp,{error:i},s):s}};nm.contextType=Ih;var Ks=new WeakMap;function Bp({children:i,error:s}){let{basename:f}=S.useContext(wt);if(typeof s=="object"&&s&&"digest"in s&&typeof s.digest=="string"){let r=zp(s.digest);if(r){let h=Ks.get(s);if(h)throw h;let m=Fh(r.location,f);if($h&&!Ks.get(s))if(m.isExternal||r.reloadDocument)window.location.href=m.absoluteURL||m.to;else{const y=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(m.to,{replace:r.replace}));throw Ks.set(s,y),y}return S.createElement("meta",{httpEquiv:"refresh",content:`0;url=${m.absoluteURL||m.to}`})}}return i}function Lp({routeContext:i,match:s,children:f}){let r=S.useContext(Qa);return r&&r.static&&r.staticContext&&(s.route.errorElement||s.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=s.route.id),S.createElement(Qt.Provider,{value:i},f)}function kp(i,s=[],f){let r=f==null?void 0:f.state;if(i==null){if(!r)return null;if(r.errors)i=r.matches;else if(s.length===0&&!r.initialized&&r.matches.length>0)i=r.matches;else return null}let h=i,m=r==null?void 0:r.errors;if(m!=null){let _=h.findIndex(g=>g.route.id&&(m==null?void 0:m[g.route.id])!==void 0);ze(_>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(m).join(",")}`),h=h.slice(0,Math.min(h.length,_+1))}let y=!1,E=-1;if(f&&r){y=r.renderFallback;for(let _=0;_<h.length;_++){let g=h[_];if((g.route.HydrateFallback||g.route.hydrateFallbackElement)&&(E=_),g.route.id){let{loaderData:R,errors:k}=r,D=g.route.loader&&!R.hasOwnProperty(g.route.id)&&(!k||k[g.route.id]===void 0);if(g.route.lazy||D){f.isStatic&&(y=!0),E>=0?h=h.slice(0,E+1):h=[h[0]];break}}}}let b=f==null?void 0:f.onError,v=r&&b?(_,g)=>{var R,k;b(_,{location:r.location,params:((k=(R=r.matches)==null?void 0:R[0])==null?void 0:k.params)??{},unstable_pattern:jp(r.matches),errorInfo:g})}:void 0;return h.reduceRight((_,g,R)=>{let k,D=!1,B=null,q=null;r&&(k=m&&g.route.id?m[g.route.id]:void 0,B=g.route.errorElement||Hp,y&&(E<0&&R===0?(um("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),D=!0,q=null):E===R&&(D=!0,q=g.route.hydrateFallbackElement||null)));let L=s.concat(h.slice(0,R+1)),X=()=>{let J;return k?J=B:D?J=q:g.route.Component?J=S.createElement(g.route.Component,null):g.route.element?J=g.route.element:J=_,S.createElement(Lp,{match:g,routeContext:{outlet:_,matches:L,isDataRoute:r!=null},children:J})};return r&&(g.route.ErrorBoundary||g.route.errorElement||R===0)?S.createElement(nm,{location:r.location,revalidation:r.revalidation,component:B,error:k,children:X(),routeContext:{outlet:null,matches:L,isDataRoute:!0},onError:v}):X()},null)}function ar(i){return`${i} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function qp(i){let s=S.useContext(Qa);return ze(s,ar(i)),s}function Yp(i){let s=S.useContext(gi);return ze(s,ar(i)),s}function Gp(i){let s=S.useContext(Qt);return ze(s,ar(i)),s}function nr(i){let s=Gp(i),f=s.matches[s.matches.length-1];return ze(f.route.id,`${i} can only be used on routes that contain a unique "id"`),f.route.id}function Xp(){return nr("useRouteId")}function Qp(){var r;let i=S.useContext(tr),s=Yp("useRouteError"),f=nr("useRouteError");return i!==void 0?i:(r=s.errors)==null?void 0:r[f]}function Vp(){let{router:i}=qp("useNavigate"),s=nr("useNavigate"),f=S.useRef(!1);return lm(()=>{f.current=!0}),S.useCallback(async(h,m={})=>{Xt(f.current,tm),f.current&&(typeof h=="number"?await i.navigate(h):await i.navigate(h,{fromRouteId:s,...m}))},[i,s])}var wh={};function um(i,s,f){!s&&!wh[i]&&(wh[i]=!0,Xt(!1,f))}S.memo(Zp);function Zp({routes:i,future:s,state:f,isStatic:r,onError:h}){return am(i,void 0,{state:f,isStatic:r,onError:h})}function Yt(i){ze(!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 Kp({basename:i="/",children:s=null,location:f,navigationType:r="POP",navigator:h,static:m=!1,unstable_useTransitions:y}){ze(!Kn(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let E=i.replace(/^\/*/,"/"),b=S.useMemo(()=>({basename:E,navigator:h,static:m,unstable_useTransitions:y,future:{}}),[E,h,m,y]);typeof f=="string"&&(f=Xa(f));let{pathname:v="/",search:_="",hash:g="",state:R=null,key:k="default",unstable_mask:D}=f,B=S.useMemo(()=>{let q=ol(v,E);return q==null?null:{location:{pathname:q,search:_,hash:g,state:R,key:k,unstable_mask:D},navigationType:r}},[E,v,_,g,R,k,r,D]);return Xt(B!=null,`<Router basename="${E}"> is not able to match the URL "${v}${_}${g}" because it does not start with the basename, so the <Router> won't render anything.`),B==null?null:S.createElement(wt.Provider,{value:b},S.createElement(Zn.Provider,{children:s,value:B}))}function Mh({children:i,location:s}){return Dp(Ws(i),s)}function Ws(i,s=[]){let f=[];return S.Children.forEach(i,(r,h)=>{if(!S.isValidElement(r))return;let m=[...s,h];if(r.type===S.Fragment){f.push.apply(f,Ws(r.props.children,m));return}ze(r.type===Yt,`[${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>`),ze(!r.props.index||!r.props.children,"An index route cannot have child routes.");let y={id:r.props.id||m.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&&(y.children=Ws(r.props.children,m)),f.push(y)}),f}var mi="get",vi="application/x-www-form-urlencoded";function bi(i){return typeof HTMLElement<"u"&&i instanceof HTMLElement}function Jp(i){return bi(i)&&i.tagName.toLowerCase()==="button"}function $p(i){return bi(i)&&i.tagName.toLowerCase()==="form"}function Fp(i){return bi(i)&&i.tagName.toLowerCase()==="input"}function Wp(i){return!!(i.metaKey||i.altKey||i.ctrlKey||i.shiftKey)}function Ip(i,s){return i.button===0&&(!s||s==="_self")&&!Wp(i)}var hi=null;function Pp(){if(hi===null)try{new FormData(document.createElement("form"),0),hi=!1}catch{hi=!0}return hi}var eg=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Js(i){return i!=null&&!eg.has(i)?(Xt(!1,`"${i}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${vi}"`),null):i}function tg(i,s){let f,r,h,m,y;if($p(i)){let E=i.getAttribute("action");r=E?ol(E,s):null,f=i.getAttribute("method")||mi,h=Js(i.getAttribute("enctype"))||vi,m=new FormData(i)}else if(Jp(i)||Fp(i)&&(i.type==="submit"||i.type==="image")){let E=i.form;if(E==null)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let b=i.getAttribute("formaction")||E.getAttribute("action");if(r=b?ol(b,s):null,f=i.getAttribute("formmethod")||E.getAttribute("method")||mi,h=Js(i.getAttribute("formenctype"))||Js(E.getAttribute("enctype"))||vi,m=new FormData(E,i),!Pp()){let{name:v,type:_,value:g}=i;if(_==="image"){let R=v?`${v}.`:"";m.append(`${R}x`,"0"),m.append(`${R}y`,"0")}else v&&m.append(v,g)}}else{if(bi(i))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');f=mi,r=null,h=vi,y=i}return m&&h==="text/plain"&&(y=m,m=void 0),{action:r,method:f.toLowerCase(),encType:h,formData:m,body:y}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function ur(i,s){if(i===!1||i===null||typeof i>"u")throw new Error(s)}function im(i,s,f,r){let h=typeof i=="string"?new URL(i,typeof window>"u"?"server://singlefetch/":window.location.origin):i;return f?h.pathname.endsWith("/")?h.pathname=`${h.pathname}_.${r}`:h.pathname=`${h.pathname}.${r}`:h.pathname==="/"?h.pathname=`_root.${r}`:s&&ol(h.pathname,s)==="/"?h.pathname=`${pi(s)}/_root.${r}`:h.pathname=`${pi(h.pathname)}.${r}`,h}async function lg(i,s){if(i.id in s)return s[i.id];try{let f=await import(i.module);return s[i.id]=f,f}catch(f){return console.error(`Error loading route module \`${i.module}\`, reloading page...`),console.error(f),window.__reactRouterContext&&window.__reactRouterContext.isSpaMode,window.location.reload(),new Promise(()=>{})}}function ag(i){return i==null?!1:i.href==null?i.rel==="preload"&&typeof i.imageSrcSet=="string"&&typeof i.imageSizes=="string":typeof i.rel=="string"&&typeof i.href=="string"}async function ng(i,s,f){let r=await Promise.all(i.map(async h=>{let m=s.routes[h.route.id];if(m){let y=await lg(m,f);return y.links?y.links():[]}return[]}));return sg(r.flat(1).filter(ag).filter(h=>h.rel==="stylesheet"||h.rel==="preload").map(h=>h.rel==="stylesheet"?{...h,rel:"prefetch",as:"style"}:{...h,rel:"prefetch"}))}function Oh(i,s,f,r,h,m){let y=(b,v)=>f[v]?b.route.id!==f[v].route.id:!0,E=(b,v)=>{var _;return f[v].pathname!==b.pathname||((_=f[v].route.path)==null?void 0:_.endsWith("*"))&&f[v].params["*"]!==b.params["*"]};return m==="assets"?s.filter((b,v)=>y(b,v)||E(b,v)):m==="data"?s.filter((b,v)=>{var g;let _=r.routes[b.route.id];if(!_||!_.hasLoader)return!1;if(y(b,v)||E(b,v))return!0;if(b.route.shouldRevalidate){let R=b.route.shouldRevalidate({currentUrl:new URL(h.pathname+h.search+h.hash,window.origin),currentParams:((g=f[0])==null?void 0:g.params)||{},nextUrl:new URL(i,window.origin),nextParams:b.params,defaultShouldRevalidate:!0});if(typeof R=="boolean")return R}return!0}):[]}function ug(i,s,{includeHydrateFallback:f}={}){return ig(i.map(r=>{let h=s.routes[r.route.id];if(!h)return[];let m=[h.module];return h.clientActionModule&&(m=m.concat(h.clientActionModule)),h.clientLoaderModule&&(m=m.concat(h.clientLoaderModule)),f&&h.hydrateFallbackModule&&(m=m.concat(h.hydrateFallbackModule)),h.imports&&(m=m.concat(h.imports)),m}).flat(1))}function ig(i){return[...new Set(i)]}function cg(i){let s={},f=Object.keys(i).sort();for(let r of f)s[r]=i[r];return s}function sg(i,s){let f=new Set;return new Set(s),i.reduce((r,h)=>{let m=JSON.stringify(cg(h));return f.has(m)||(f.add(m),r.push({key:m,link:h})),r},[])}function ir(){let i=S.useContext(Qa);return ur(i,"You must render this element inside a <DataRouterContext.Provider> element"),i}function rg(){let i=S.useContext(gi);return ur(i,"You must render this element inside a <DataRouterStateContext.Provider> element"),i}var cr=S.createContext(void 0);cr.displayName="FrameworkContext";function sr(){let i=S.useContext(cr);return ur(i,"You must render this element inside a <HydratedRouter> element"),i}function og(i,s){let f=S.useContext(cr),[r,h]=S.useState(!1),[m,y]=S.useState(!1),{onFocus:E,onBlur:b,onMouseEnter:v,onMouseLeave:_,onTouchStart:g}=s,R=S.useRef(null);S.useEffect(()=>{if(i==="render"&&y(!0),i==="viewport"){let B=L=>{L.forEach(X=>{y(X.isIntersecting)})},q=new IntersectionObserver(B,{threshold:.5});return R.current&&q.observe(R.current),()=>{q.disconnect()}}},[i]),S.useEffect(()=>{if(r){let B=setTimeout(()=>{y(!0)},100);return()=>{clearTimeout(B)}}},[r]);let k=()=>{h(!0)},D=()=>{h(!1),y(!1)};return f?i!=="intent"?[m,R,{}]:[m,R,{onFocus:Yn(E,k),onBlur:Yn(b,D),onMouseEnter:Yn(v,k),onMouseLeave:Yn(_,D),onTouchStart:Yn(g,k)}]:[!1,R,{}]}function Yn(i,s){return f=>{i&&i(f),f.defaultPrevented||s(f)}}function fg({page:i,...s}){let f=Tp(),{router:r}=ir(),h=S.useMemo(()=>Qh(r.routes,i,r.basename),[r.routes,i,r.basename]);return h?f?S.createElement(hg,{page:i,matches:h,...s}):S.createElement(mg,{page:i,matches:h,...s}):null}function dg(i){let{manifest:s,routeModules:f}=sr(),[r,h]=S.useState([]);return S.useEffect(()=>{let m=!1;return ng(i,s,f).then(y=>{m||h(y)}),()=>{m=!0}},[i,s,f]),r}function hg({page:i,matches:s,...f}){let r=fl(),{future:h}=sr(),{basename:m}=ir(),y=S.useMemo(()=>{if(i===r.pathname+r.search+r.hash)return[];let E=im(i,m,h.unstable_trailingSlashAwareDataRequests,"rsc"),b=!1,v=[];for(let _ of s)typeof _.route.shouldRevalidate=="function"?b=!0:v.push(_.route.id);return b&&v.length>0&&E.searchParams.set("_routes",v.join(",")),[E.pathname+E.search]},[m,h.unstable_trailingSlashAwareDataRequests,i,r,s]);return S.createElement(S.Fragment,null,y.map(E=>S.createElement("link",{key:E,rel:"prefetch",as:"fetch",href:E,...f})))}function mg({page:i,matches:s,...f}){let r=fl(),{future:h,manifest:m,routeModules:y}=sr(),{basename:E}=ir(),{loaderData:b,matches:v}=rg(),_=S.useMemo(()=>Oh(i,s,v,m,r,"data"),[i,s,v,m,r]),g=S.useMemo(()=>Oh(i,s,v,m,r,"assets"),[i,s,v,m,r]),R=S.useMemo(()=>{if(i===r.pathname+r.search+r.hash)return[];let B=new Set,q=!1;if(s.forEach(X=>{var V;let J=m.routes[X.route.id];!J||!J.hasLoader||(!_.some(Y=>Y.route.id===X.route.id)&&X.route.id in b&&((V=y[X.route.id])!=null&&V.shouldRevalidate)||J.hasClientLoader?q=!0:B.add(X.route.id))}),B.size===0)return[];let L=im(i,E,h.unstable_trailingSlashAwareDataRequests,"data");return q&&B.size>0&&L.searchParams.set("_routes",s.filter(X=>B.has(X.route.id)).map(X=>X.route.id).join(",")),[L.pathname+L.search]},[E,h.unstable_trailingSlashAwareDataRequests,b,r,m,_,s,i,y]),k=S.useMemo(()=>ug(g,m),[g,m]),D=dg(g);return S.createElement(S.Fragment,null,R.map(B=>S.createElement("link",{key:B,rel:"prefetch",as:"fetch",href:B,...f})),k.map(B=>S.createElement("link",{key:B,rel:"modulepreload",href:B,...f})),D.map(({key:B,link:q})=>S.createElement("link",{key:B,nonce:f.nonce,...q,crossOrigin:q.crossOrigin??f.crossOrigin})))}function vg(...i){return s=>{i.forEach(f=>{typeof f=="function"?f(s):f!=null&&(f.current=s)})}}var yg=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";try{yg&&(window.__reactRouterVersion="7.14.2")}catch{}function pg({basename:i,children:s,unstable_useTransitions:f,window:r}){let h=S.useRef();h.current==null&&(h.current=Wy({window:r,v5Compat:!0}));let m=h.current,[y,E]=S.useState({action:m.action,location:m.location}),b=S.useCallback(v=>{f===!1?E(v):S.startTransition(()=>E(v))},[f]);return S.useLayoutEffect(()=>m.listen(b),[m,b]),S.createElement(Kp,{basename:i,children:s,location:y.location,navigationType:y.action,navigator:m,unstable_useTransitions:f})}var cm=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Je=S.forwardRef(function({onClick:s,discover:f="render",prefetch:r="none",relative:h,reloadDocument:m,replace:y,unstable_mask:E,state:b,target:v,to:_,preventScrollReset:g,viewTransition:R,unstable_defaultShouldRevalidate:k,...D},B){let{basename:q,navigator:L,unstable_useTransitions:X}=S.useContext(wt),J=typeof _=="string"&&cm.test(_),V=Fh(_,q);_=V.to;let Y=wp(_,{relative:h}),K=fl(),G=null;if(E){let Ue=er(E,[],K.unstable_mask?K.unstable_mask.pathname:"/",!0);q!=="/"&&(Ue.pathname=Ue.pathname==="/"?q:Ut([q,Ue.pathname])),G=L.createHref(Ue)}let[te,ye,tt]=og(r,D),We=xg(_,{replace:y,unstable_mask:E,state:b,target:v,preventScrollReset:g,relative:h,viewTransition:R,unstable_defaultShouldRevalidate:k,unstable_useTransitions:X});function $e(Ue){s&&s(Ue),Ue.defaultPrevented||We(Ue)}let Ht=!(V.isExternal||m),St=S.createElement("a",{...D,...tt,href:(Ht?G:void 0)||V.absoluteURL||Y,onClick:Ht?$e:s,ref:vg(B,ye),target:v,"data-discover":!J&&f==="render"?"true":void 0});return te&&!J?S.createElement(S.Fragment,null,St,S.createElement(fg,{page:Y})):St});Je.displayName="Link";var gg=S.forwardRef(function({"aria-current":s="page",caseSensitive:f=!1,className:r="",end:h=!1,style:m,to:y,viewTransition:E,children:b,...v},_){let g=Jn(y,{relative:v.relative}),R=fl(),k=S.useContext(gi),{navigator:D,basename:B}=S.useContext(wt),q=k!=null&&Ag(g)&&E===!0,L=D.encodeLocation?D.encodeLocation(g).pathname:g.pathname,X=R.pathname,J=k&&k.navigation&&k.navigation.location?k.navigation.location.pathname:null;f||(X=X.toLowerCase(),J=J?J.toLowerCase():null,L=L.toLowerCase()),J&&B&&(J=ol(J,B)||J);const V=L!=="/"&&L.endsWith("/")?L.length-1:L.length;let Y=X===L||!h&&X.startsWith(L)&&X.charAt(V)==="/",K=J!=null&&(J===L||!h&&J.startsWith(L)&&J.charAt(L.length)==="/"),G={isActive:Y,isPending:K,isTransitioning:q},te=Y?s:void 0,ye;typeof r=="function"?ye=r(G):ye=[r,Y?"active":null,K?"pending":null,q?"transitioning":null].filter(Boolean).join(" ");let tt=typeof m=="function"?m(G):m;return S.createElement(Je,{...v,"aria-current":te,className:ye,ref:_,style:tt,to:y,viewTransition:E},typeof b=="function"?b(G):b)});gg.displayName="NavLink";var bg=S.forwardRef(({discover:i="render",fetcherKey:s,navigate:f,reloadDocument:r,replace:h,state:m,method:y=mi,action:E,onSubmit:b,relative:v,preventScrollReset:_,viewTransition:g,unstable_defaultShouldRevalidate:R,...k},D)=>{let{unstable_useTransitions:B}=S.useContext(wt),q=Tg(),L=_g(E,{relative:v}),X=y.toLowerCase()==="get"?"get":"post",J=typeof E=="string"&&cm.test(E),V=Y=>{if(b&&b(Y),Y.defaultPrevented)return;Y.preventDefault();let K=Y.nativeEvent.submitter,G=(K==null?void 0:K.getAttribute("formmethod"))||y,te=()=>q(K||Y.currentTarget,{fetcherKey:s,method:G,navigate:f,replace:h,state:m,relative:v,preventScrollReset:_,viewTransition:g,unstable_defaultShouldRevalidate:R});B&&f!==!1?S.startTransition(()=>te()):te()};return S.createElement("form",{ref:D,method:X,action:L,onSubmit:r?b:V,...k,"data-discover":!J&&i==="render"?"true":void 0})});bg.displayName="Form";function Sg(i){return`${i} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function sm(i){let s=S.useContext(Qa);return ze(s,Sg(i)),s}function xg(i,{target:s,replace:f,unstable_mask:r,state:h,preventScrollReset:m,relative:y,viewTransition:E,unstable_defaultShouldRevalidate:b,unstable_useTransitions:v}={}){let _=Mp(),g=fl(),R=Jn(i,{relative:y});return S.useCallback(k=>{if(Ip(k,s)){k.preventDefault();let D=f!==void 0?f:Qn(g)===Qn(R),B=()=>_(i,{replace:D,unstable_mask:r,state:h,preventScrollReset:m,relative:y,viewTransition:E,unstable_defaultShouldRevalidate:b});v?S.startTransition(()=>B()):B()}},[g,_,R,f,r,h,s,i,m,y,E,b,v])}var jg=0,Eg=()=>`__${String(++jg)}__`;function Tg(){let{router:i}=sm("useSubmit"),{basename:s}=S.useContext(wt),f=Xp(),r=i.fetch,h=i.navigate;return S.useCallback(async(m,y={})=>{let{action:E,method:b,encType:v,formData:_,body:g}=tg(m,s);if(y.navigate===!1){let R=y.fetcherKey||Eg();await r(R,f,y.action||E,{unstable_defaultShouldRevalidate:y.unstable_defaultShouldRevalidate,preventScrollReset:y.preventScrollReset,formData:_,body:g,formMethod:y.method||b,formEncType:y.encType||v,flushSync:y.flushSync})}else await h(y.action||E,{unstable_defaultShouldRevalidate:y.unstable_defaultShouldRevalidate,preventScrollReset:y.preventScrollReset,formData:_,body:g,formMethod:y.method||b,formEncType:y.encType||v,replace:y.replace,state:y.state,fromRouteId:f,flushSync:y.flushSync,viewTransition:y.viewTransition})},[r,h,s,f])}function _g(i,{relative:s}={}){let{basename:f}=S.useContext(wt),r=S.useContext(Qt);ze(r,"useFormAction must be used inside a RouteContext");let[h]=r.matches.slice(-1),m={...Jn(i||".",{relative:s})},y=fl();if(i==null){m.search=y.search;let E=new URLSearchParams(m.search),b=E.getAll("index");if(b.some(_=>_==="")){E.delete("index"),b.filter(g=>g).forEach(g=>E.append("index",g));let _=E.toString();m.search=_?`?${_}`:""}}return(!i||i===".")&&h.route.index&&(m.search=m.search?m.search.replace(/^\?/,"?index&"):"?index"),f!=="/"&&(m.pathname=m.pathname==="/"?f:Ut([f,m.pathname])),Qn(m)}function Ag(i,{relative:s}={}){let f=S.useContext(Ph);ze(f!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:r}=sm("useViewTransitionState"),h=Jn(i,{relative:s});if(!f.isTransitioning)return!1;let m=ol(f.currentLocation.pathname,r)||f.currentLocation.pathname,y=ol(f.nextLocation.pathname,r)||f.nextLocation.pathname;return yi(h.pathname,y)!=null||yi(h.pathname,m)!=null}const rm=/^\/vault\/([^/]+)\/admin(?=\/|$)/;function om(){if(typeof window>"u")return null;const i=window.location.pathname.match(rm);if(!i)return null;try{return decodeURIComponent(i[1])}catch{return null}}function Ng(){if(typeof window>"u")return"";const i=window.location.pathname,s=i.match(rm);return s?`/vault/${s[1]}/admin`:i==="/admin"||i.startsWith("/admin/")?"/admin":""}let Bl=null,Gt=null,aa=null,rl=null,Dh=!1;const Rg=.8,zg=1e3,Cg=3e4;function wg(){if(typeof window>"u")return;const i=window.location.hash;if(!i||i.length<2)return;const s=new URLSearchParams(i.slice(1)),f=s.get("token");if(!f)return;Bl=f,Gt=null,s.delete("token");const r=s.toString(),h=r.length>0?`#${r}`:"",m=`${window.location.pathname}${window.location.search}${h}`;window.history.replaceState(null,"",m)}function rr(){return Bl}function Mg(){Bl=null,Gt=null,rl=null,Si()}async function Vn(i){if(typeof window>"u")return{kind:"network-error",message:"no window"};let s;try{s=await fetch(`/admin/vault-admin-token/${encodeURIComponent(i)}`,{method:"GET",headers:{accept:"application/json"},credentials:"same-origin"})}catch(r){return{kind:"network-error",message:r instanceof Error?r.message:String(r)}}if(s.status===401||s.status===403||s.status===404)return{kind:"auth-required",status:s.status};if(!s.ok)return{kind:"network-error",message:`hub returned ${s.status}`};let f;try{f=await s.json()}catch(r){return{kind:"network-error",message:r instanceof Error?r.message:"could not parse mint response"}}return typeof f.token!="string"||f.token.length===0?{kind:"network-error",message:"mint response missing token"}:(Bl=f.token,Gt=f.expires_at?Og(f.expires_at):null,rl=i,fm(),Hg(),{kind:"ok",token:f.token})}function Og(i){const s=Date.parse(i);return Number.isNaN(s)?null:s}async function Is(i){if(Bl){if(Gt===null||Gt>Date.now())return{kind:"ok",token:Bl};Bl=null,Gt=null,Si()}return Vn(i)}async function Dg(i){typeof window>"u"||Bl||await Vn(i).catch(()=>{})}function fm(){if(Si(),Gt===null||rl===null||typeof document<"u"&&document.visibilityState==="hidden")return;const i=Date.now(),s=Gt-i;if(s<=0)return;const f=Math.max(Math.floor(s*Rg),zg);aa=setTimeout(()=>{Ug()},f)}function Si(){aa!==null&&(clearTimeout(aa),aa=null)}async function Ug(){if(aa=null,rl===null)return;const i=await Vn(rl);i.kind!=="ok"&&(typeof console<"u"&&console.warn("[vault-admin-spa] proactive token refresh failed; will retry once",i),aa=setTimeout(()=>{aa=null,rl!==null&&Vn(rl).catch(()=>{})},Cg))}function Hg(){Dh||typeof document>"u"||(Dh=!0,document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden"){Si();return}if(rl!==null){if(Gt!==null&&Gt<=Date.now()){Vn(rl).catch(()=>{});return}fm()}}))}class _e extends Error{constructor(s,f){super(f),this.status=s,this.name="HttpError"}}async function et(i,s,f={}){let r=rr();if(!r){const v=await Is(i);if(v.kind!=="ok")throw new _e(401,"no admin token — sign in to the hub to refresh");r=v.token}const{headers:h,...m}=f,y=v=>({accept:"application/json",...h??{},authorization:`Bearer ${v}`}),E=await fetch(s,{...m,headers:y(r)});if(E.status!==401)return E;Mg();const b=await Is(i);return b.kind!=="ok"?E:fetch(s,{...m,headers:y(b.token)})}async function Bg(){const i=await fetch("/vaults/list",{headers:{accept:"application/json"}});if(i.status===404)return[];if(!i.ok)throw new _e(i.status,`vaults/list fetch failed: ${i.status}`);return(await i.json()).vaults??[]}async function Lg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function kg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function qg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function Yg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/run-now`,{method:"POST"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Gg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/push-now`,{method:"POST"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function dm(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Xg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth`,{method:"DELETE"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Qg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/device-code`,{method:"POST"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Vg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/poll`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({polling_id:s})});if(!f.ok&&f.status!==404)throw new _e(f.status,await rt(f));return await f.json()}async function Zg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/pat`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function hm(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/repos`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Kg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/create-repo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function Jg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/select-repo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function $g(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/import`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function rt(i){try{const s=await i.text(),f=JSON.parse(s);if(f.error_description)return f.error_description;if(f.message)return f.message;if(f.error)return f.error;if(s)return s}catch{}return`${i.status} ${i.statusText}`}function mm(i){const s=i.split(".");if(s.length!==3)return null;try{const f=s[1].replace(/-/g,"+").replace(/_/g,"/"),r=f.length%4===0?"":"=".repeat(4-f.length%4),h=atob(f+r),m=JSON.parse(h);return m===null||typeof m!="object"?null:m}catch{return null}}function Fg(i){if(!i)return[];const s=mm(i);if(!s)return[];const f=s.scope;if(typeof f=="string"&&f.length>0)return f.split(/\s+/).filter(h=>h.length>0);const r=s.scopes;return Array.isArray(r)?r.filter(h=>typeof h=="string"&&h.length>0):[]}function vm(i){return Fg(rr()).includes(`vault:${i}:admin`)}function ym(){const i=rr();if(!i)return null;const s=mm(i);if(!s)return null;const f=s.iss;return typeof f!="string"||f.length===0?null:f.replace(/\/$/,"")}const Uh=5e3;function or({vaultName:i,status:s,onRecovered:f}){const r=s===403;if(S.useEffect(()=>{if(r)return;let E=!1,b=null;const v=async()=>{if(E||typeof document<"u"&&document.visibilityState!=="visible")return;const g=await Is(i);if(!E){if(g.kind==="ok"){f();return}b=setTimeout(()=>void v(),Uh)}},_=()=>{typeof document>"u"||document.visibilityState==="visible"&&(b!==null&&(clearTimeout(b),b=null),v())};return b=setTimeout(()=>void v(),Uh),typeof document<"u"&&document.addEventListener("visibilitychange",_),()=>{E=!0,b!==null&&clearTimeout(b),typeof document<"u"&&document.removeEventListener("visibilitychange",_)}},[i,f,r]),r)return c.jsxs("div",{className:"warn-banner",role:"status",children:[c.jsxs("p",{style:{margin:"0 0 0.5rem"},children:["You're signed in, but vault management is restricted to the hub admin."," ",c.jsx("a",{href:"/account/",children:"Go to your account →"})]}),c.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=Wg(),m=`/login?next=${encodeURIComponent(h)}`,y=s===404?"This hub doesn't host a vault by that name.":"You're not signed in to the hub.";return c.jsxs("div",{className:"warn-banner",role:"status",children:[c.jsxs("p",{style:{margin:"0 0 0.5rem"},children:[y," ",c.jsx("a",{href:m,children:"Sign in to the hub →"})]}),c.jsx("p",{className:"dim",style:{margin:0,fontSize:"0.85rem"},children:"After signing in, this page will refresh automatically."})]})}function Wg(){return typeof window>"u"?"/":`${window.location.pathname}${window.location.search}${window.location.hash}`}function Hh({vaultName:i}={}){const s=lr(),f=i??s.name,r=i!==void 0,h=r?"/tokens":`/vault/${encodeURIComponent(f??"")}/tokens`,m=r?"/mirror":`/vault/${encodeURIComponent(f??"")}/mirror`,[y,E]=S.useState({kind:"loading"}),[b,v]=S.useState(0),_=S.useCallback(()=>v(k=>k+1),[]);if(S.useEffect(()=>{let k=!1;if(!f){E({kind:"missing"});return}return E({kind:"loading"}),Lg(f).then(D=>{k||E({kind:"ok",vault:D})}).catch(D=>{if(k)return;if(D instanceof _e){if(D.status===401||D.status===403){E({kind:"auth-required",status:D.status});return}if(D.status===404){E({kind:"missing"});return}E({kind:"error",message:`${D.status}: ${D.message}`});return}const B=D instanceof Error?D.message:String(D);E({kind:"error",message:B})}),()=>{k=!0}},[f,b]),y.kind==="loading")return c.jsxs("div",{children:[c.jsx("h2",{children:"Vault"}),c.jsx("p",{className:"muted",children:"Loading…"})]});if(y.kind==="auth-required")return c.jsxs("div",{children:[c.jsxs("h2",{children:["Vault ",c.jsx("code",{children:f})]}),c.jsx(or,{vaultName:f??"",status:y.status,onRecovered:_}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});if(y.kind==="missing")return c.jsxs("div",{children:[c.jsx("h2",{children:"Vault not found"}),c.jsxs("p",{className:"muted",children:["No vault named ",c.jsx("code",{children:f})," is registered on this server."]}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});if(y.kind==="error")return c.jsxs("div",{children:[c.jsxs("h2",{children:["Vault ",c.jsx("code",{children:f})]}),c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:y.message})}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});const{vault:g}=y,R=`/vault/${g.name}`;return c.jsxs("div",{children:[c.jsxs("div",{className:"list-header",children:[c.jsxs("h2",{children:["Vault ",c.jsx("code",{children:g.name})]}),r?null:c.jsx(Je,{to:"/",className:"muted",children:"← All vaults"})]}),c.jsxs("div",{className:"kv section",children:[c.jsx("div",{children:"Name"}),c.jsx("div",{children:c.jsx("code",{children:g.name})}),g.description?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Description"}),c.jsx("div",{children:g.description})]}):null,c.jsx("div",{children:"Mount"}),c.jsx("div",{children:c.jsx("code",{children:R})}),g.createdAt?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Created"}),c.jsx("div",{children:c.jsx("code",{children:g.createdAt})})]}):null]}),c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Stats"}),c.jsxs("div",{className:"stats",children:[c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Notes"}),c.jsx("div",{className:"value",children:g.stats.totalNotes})]}),c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Tags"}),c.jsx("div",{className:"value",children:g.stats.tagCount})]}),c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Attachments"}),c.jsx("div",{className:"value",children:g.stats.attachmentCount})]}),c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Links"}),c.jsx("div",{className:"value",children:g.stats.linkCount})]})]})]}),c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Manage"}),c.jsxs("ul",{className:"manage-list",children:[c.jsxs("li",{children:[c.jsx(Je,{to:h,children:"Tokens →"}),c.jsxs("span",{className:"dim",children:[" mint, list, and revoke ",c.jsx("code",{children:"pvt_*"})," tokens"]})]}),c.jsxs("li",{children:[c.jsx(Je,{to:m,children:"Git backup →"}),c.jsx("span",{className:"dim",children:" mirror this vault to a git repository on a schedule, or on demand"})]}),c.jsx(Ig,{vaultName:g.name})]})]})]})}function Ig({vaultName:i}){const s=ym();if(!s)return c.jsxs("li",{children:[c.jsx("span",{children:"Permissions →"}),c.jsxs("span",{className:"dim",children:[" ","grants are managed on hub (the OAuth issuer); link will be live when hub ships its permissions UI."]})]});const f=`${s}/hub/permissions?vault=${encodeURIComponent(i)}`;return c.jsxs("li",{children:[c.jsx("a",{href:f,children:"Permissions →"}),c.jsxs("span",{className:"dim",children:[" ","grants are managed on hub (the OAuth issuer); link will be live when hub ships its permissions UI."]})]})}const Pg=[{value:"events",label:"On change (default)"},{value:"manual",label:"Manual only"}],e0=[{id:"history",label:"History",subtext:"Local audit trail. Hidden under vault data. Events-driven.",apply:i=>({...i,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:i=>({...i,enabled:!0,location:"external",sync_mode:"events",auto_commit:!0})},{id:"manual",label:"Manual Export",subtext:"Snapshot on demand. No auto-fire.",apply:i=>({...i,enabled:!0,location:"external",sync_mode:"manual",auto_commit:!0,auto_push:!1})}];function Bh({vaultName:i}={}){const s=lr(),f=i??s.name,r=i!==void 0,h=r?"/":`/vault/${encodeURIComponent(f??"")}`,[m,y]=S.useState({kind:"loading"}),[E,b]=S.useState(0);S.useEffect(()=>{let _=!1;if(f)return y({kind:"loading"}),kg(f).then(g=>{_||y({kind:"ok",snapshot:g})}).catch(g=>{if(_)return;if(g instanceof _e&&(g.status===401||g.status===403)){y({kind:"auth-required",status:g.status});return}const R=g instanceof Error?g.message:String(g);y({kind:"error",message:R})}),()=>{_=!0}},[f,E]);const v=S.useCallback(()=>b(_=>_+1),[]);return f?c.jsxs("div",{children:[c.jsxs("div",{className:"list-header",children:[c.jsxs("h2",{children:["Backup for ",c.jsx("code",{children:f})]}),c.jsx(Je,{to:h,className:"muted",children:"← Vault detail"})]}),m.kind==="loading"?c.jsx("p",{className:"muted",children:"Loading…"}):null,m.kind==="auth-required"?c.jsx(or,{vaultName:f,status:m.status,onRecovered:v}):null,m.kind==="error"?c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:m.message})}):null,m.kind==="ok"?c.jsx(t0,{vaultName:f,snapshot:m.snapshot,onRefresh:()=>b(_=>_+1),onSnapshot:_=>y({kind:"ok",snapshot:_})}):null]}):c.jsxs("div",{children:[c.jsx("h2",{children:"Mirror"}),c.jsx("p",{className:"muted",children:"Missing vault name."}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]})}function t0({vaultName:i,snapshot:s,onRefresh:f,onSnapshot:r}){const h=vm(i),[m,y]=S.useState(null),[E,b]=S.useState(null);S.useEffect(()=>{if(!h)return;let g=!1;return dm(i).then(R=>{g||y(R)}).catch(R=>{g||b(R instanceof Error?R.message:String(R))}),()=>{g=!0}},[i,h]);const[v,_]=S.useState(!1);return c.jsxs(c.Fragment,{children:[c.jsx(l0,{status:s.status,config:s.config,creds:m}),h?null:c.jsxs("div",{className:"warn-banner",children:["You're viewing this page with a read-only token. Saving config + manual run require ",c.jsxs("code",{children:["vault:",i,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin-scoped session to make changes.`]}),h?c.jsx(u0,{vaultName:i,creds:m,credsError:E,onCredsChanged:y,onCredsSaved:()=>{f()},locationIsExternal:s.config.location==="external"}):null,c.jsxs("div",{className:"section",children:[c.jsx("button",{type:"button",className:"secondary",onClick:()=>_(g=>!g),"aria-expanded":v,children:v?"Hide advanced settings":"Advanced settings"}),v?null:c.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."})]}),v?c.jsxs(c.Fragment,{children:[c.jsx(a0,{status:s.status,config:s.config,creds:m,canRun:h&&s.status.enabled,vaultName:i,onSnapshot:r}),c.jsx(n0,{vaultName:i,initial:s.config,readOnly:!h,creds:m,onSaved:g=>{r(g),f()}}),h?c.jsx(o0,{vaultName:i,creds:m}):null]}):null]})}function l0({status:i,config:s,creds:f}){var y;if(!s.enabled)return c.jsxs("div",{className:"warn-banner",role:"status",children:[c.jsx("strong",{children:"Version history is off."})," This vault isn't saving a local history of changes right now. Open ",c.jsx("strong",{children:"Advanced settings"})," ","below to turn it back on."]});const r=!!(f!=null&&f.active_method),h=s.auto_push&&r,m=(f==null?void 0:f.active_method)==="github_oauth"?(y=f.github_oauth)==null?void 0:y.user_login:void 0;return c.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"1rem"},children:[h?c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"✓ Version history + backed up off this machine."})," ",m?c.jsxs(c.Fragment,{children:["Every change is saved locally and pushed to GitHub as"," ",c.jsxs("code",{children:["@",m]}),"."]}):c.jsx(c.Fragment,{children:"Every change is saved locally and pushed to your git remote automatically."})]}):c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"✓ Version history — on."})," Your vault automatically saves a full local history of every change. Want an off-machine copy too? Use ",c.jsx("strong",{children:"Back up to GitHub"})," below."]}),i.last_error?c.jsxs("p",{className:"dim",style:{margin:"0.5rem 0 0"},children:["Heads up — the last backup pass reported an error. See"," ",c.jsx("strong",{children:"Advanced settings"})," below for details."]}):null]})}function a0({status:i,config:s,creds:f,canRun:r,vaultName:h,onSnapshot:m}){const y=s.enabled,[E,b]=S.useState(!1),[v,_]=S.useState(!1),[g,R]=S.useState(null),k=async()=>{b(!0),R(null);try{const L=await Yg(h);m(L)}catch(L){R(L instanceof Error?L.message:String(L))}finally{b(!1)}},D=async()=>{_(!0),R(null);try{const L=await Gg(h);m(L)}catch(L){R(L instanceof Error?L.message:String(L))}finally{_(!1)}},B=!!(f!=null&&f.active_method)||s.auto_push,q=!r||v||!B;return c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Status"}),c.jsxs("div",{className:"kv",children:[c.jsx("div",{children:"Enabled"}),c.jsx("div",{children:y?c.jsx("code",{children:"yes"}):c.jsx("code",{children:"no"})}),c.jsx("div",{children:"Watch loop"}),c.jsx("div",{children:i.watch_running?c.jsx("code",{children:"running"}):c.jsx("code",{children:"stopped"})}),c.jsx("div",{children:"Path"}),c.jsx("div",{children:i.mirror_path?c.jsx("code",{children:i.mirror_path}):c.jsx("span",{className:"dim",children:"—"})}),c.jsx("div",{children:"Last export"}),c.jsx("div",{children:i.last_export_at?c.jsxs(c.Fragment,{children:[c.jsx("code",{children:i.last_export_at}),i.last_export_notes_count!==null?c.jsxs("span",{className:"dim",children:[" ","· ",i.last_export_notes_count," note",i.last_export_notes_count===1?"":"s"]}):null]}):c.jsx("span",{className:"dim",children:"never"})}),c.jsx("div",{children:"Last commit"}),c.jsx("div",{children:i.last_commit_sha?c.jsx("code",{children:i.last_commit_sha.slice(0,10)}):c.jsx("span",{className:"dim",children:"—"})}),c.jsx("div",{children:"Last push"}),c.jsx("div",{children:i.last_push_at?c.jsxs(c.Fragment,{children:[c.jsx("code",{children:i.last_push_at}),i.last_push_sha?c.jsxs("span",{className:"dim",children:[" ","· ",c.jsx("code",{children:i.last_push_sha.slice(0,10)})]}):null]}):c.jsx("span",{className:"dim",children:"never"})}),i.commits_unpushed!==null&&i.commits_unpushed>0?c.jsxs(c.Fragment,{children:[c.jsx("div",{}),c.jsxs("div",{className:"dim",children:[i.commits_unpushed," commit",i.commits_unpushed===1?"":"s"," ready to push"]})]}):null]}),i.last_push_error?c.jsxs("div",{className:"error-banner",style:{marginTop:"1rem"},children:[c.jsx("strong",{children:"Last push failed:"})," ",c.jsx("code",{children:i.last_push_error})]}):null,i.last_error?c.jsxs("div",{className:"error-banner",style:{marginTop:"1rem"},children:[c.jsx("strong",{children:"Last error:"})," ",c.jsx("code",{children:i.last_error})]}):null,g?c.jsx("div",{className:"error-banner",style:{marginTop:"1rem"},children:c.jsx("code",{children:g})}):null,c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:k,disabled:!r||E,title:y?r?void 0:"Admin scope required to trigger a manual export.":"Enable the mirror first, then trigger a manual export.",children:E?"Running…":"Run export now"}),c.jsx("button",{type:"button",className:"secondary",onClick:D,disabled:q,title:y?r?B?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:v?"Pushing…":"Push now"})]})]})}function n0({vaultName:i,initial:s,readOnly:f,creds:r,onSaved:h}){const[m,y]=S.useState(s),[E,b]=S.useState(!1),[v,_]=S.useState(!1),[g,R]=S.useState(null),[k,D]=S.useState(null),[B,q]=S.useState(0);S.useEffect(()=>{y(s)},[s]);const L=V=>{const Y=V.apply(m);y(Y)},X=V=>{y(Y=>({...Y,sync_mode:V}))},J=async V=>{if(V.preventDefault(),!f){_(!0),R(null),D(null);try{const Y=await qg(i,m);h(Y),q(K=>K+1),setTimeout(()=>q(0),3e3)}catch(Y){if(Y instanceof _e){const K=Y.message;R(K);const G=K.toLowerCase();G.includes("external_path")?D("external_path"):G.includes("commit_template")?D("commit_template"):G.includes("safety_net_seconds")?D("safety_net_seconds"):G.includes("sync_mode")?D("sync_mode"):G.includes("auto_push")?D("auto_push"):G.includes("location")?D("location"):D(null)}else R(Y instanceof Error?Y.message:String(Y))}finally{_(!1)}}};return c.jsxs("form",{className:"section",onSubmit:J,children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Configuration"}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:m.enabled,disabled:f,onChange:V=>y(Y=>({...Y,enabled:V.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Enable mirror"]}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"Master switch. When off, no export / commit / push runs."})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{children:"Presets"}),c.jsxs("p",{className:"dim",style:{marginTop:0,marginBottom:"0.5rem",fontSize:"0.9em"},children:[c.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. ",c.jsx("strong",{children:"External folder mirror"})," +"," ",c.jsx("strong",{children:"Manual Export"})," are for operators who want to point at a visible folder (Obsidian, GitHub)."]}),c.jsx("div",{className:"preset-grid",children:e0.map(V=>c.jsxs("button",{type:"button",className:"preset-card",disabled:f,onClick:()=>L(V),"aria-label":`Apply ${V.label} preset`,children:[c.jsx("strong",{children:V.label}),c.jsx("span",{className:"dim",children:V.subtext})]},V.id))})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{children:"Location"}),c.jsxs("div",{children:[c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"location",value:"internal",checked:m.location==="internal",disabled:f,onChange:()=>y(V=>({...V,location:"internal"}))}),c.jsxs("span",{children:["Internal ",c.jsx("span",{className:"dim",children:"— hidden under vault data dir"})]})]}),c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"location",value:"external",checked:m.location==="external",disabled:f,onChange:()=>y(V=>({...V,location:"external"}))}),c.jsxs("span",{children:["External ",c.jsx("span",{className:"dim",children:"— operator-picked path"})]})]})]})]}),m.location==="external"?c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"external-path",children:"External path"}),c.jsx("input",{id:"external-path",type:"text",value:m.external_path??"",disabled:f,onChange:V=>y(Y=>({...Y,external_path:V.target.value.length>0?V.target.value:null})),placeholder:"/Users/you/Documents/vault-mirror","aria-invalid":k==="external_path"}),c.jsxs("div",{className:"warn-banner",style:{marginTop:"0.5rem"},role:"alert",children:["Path must exist AND be a git repo (run ",c.jsx("code",{children:"git init"})," first if needed)."]})]}):null,c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"sync-mode-select",children:"Sync mode"}),c.jsx("select",{id:"sync-mode-select",value:m.sync_mode,disabled:f,onChange:V=>X(V.target.value),children:Pg.map(V=>c.jsx("option",{value:V.value,children:V.label},V.value))}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:m.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."})]}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:m.auto_commit,disabled:f,onChange:V=>y(Y=>({...Y,auto_commit:V.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Commit after each export"]}),m.auto_commit?null:c.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."})]}),m.location==="external"||r!=null&&r.active_method?c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:m.auto_push,disabled:f,onChange:V=>y(Y=>({...Y,auto_push:V.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Push after each commit"]}),c.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."}),m.auto_push?r!=null&&r.active_method?c.jsxs("div",{className:"info-banner",style:{marginTop:"0.5rem"},role:"status",children:[r.active_method==="github_oauth"&&r.github_oauth?c.jsxs(c.Fragment,{children:["Will push to ",c.jsxs("code",{children:["@",r.github_oauth.user_login]})," on GitHub."]}):r.active_method==="pat"&&r.pat?c.jsxs(c.Fragment,{children:["Will push using saved credential: ",c.jsx("code",{children:r.pat.label}),"."]}):c.jsx(c.Fragment,{children:"Will push using saved credential."})," ","Failed pushes are logged but won't crash the export."]}):c.jsxs("div",{className:"warn-banner",style:{marginTop:"0.5rem"},role:"alert",children:["Auto-push needs git credentials. Either connect GitHub in the"," ",c.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,c.jsx("div",{className:"form-row",children:c.jsxs("button",{type:"button",className:"secondary",onClick:()=>b(V=>!V),children:[E?"Hide":"Show"," advanced"]})}),E?c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"commit-template",children:"Commit template"}),c.jsx("input",{id:"commit-template",type:"text",value:m.commit_template,disabled:f,onChange:V=>y(Y=>({...Y,commit_template:V.target.value})),"aria-invalid":k==="commit_template"}),c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Supports ",c.jsx("code",{children:"{{date}}"}),", ",c.jsx("code",{children:"{{notes_changed}}"}),","," ",c.jsx("code",{children:"{{plural}}"}),", ",c.jsx("code",{children:"{{first_note_title}}"}),","," ",c.jsx("code",{children:"{{vault_name}}"}),"."]})]}):null,g?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:g})}):null,B>0?c.jsx("div",{className:"mint-banner",style:{padding:"0.75rem 1rem",marginBottom:"1rem"},role:"status",children:"Saved."}):null,c.jsx("div",{className:"actions",children:c.jsx("button",{type:"submit",disabled:f||v,children:v?"Saving…":"Save"})})]})}function u0({vaultName:i,creds:s,credsError:f,onCredsChanged:r,onCredsSaved:h,locationIsExternal:m}){const[y,E]=S.useState(!1),[b,v]=S.useState(!1),[_,g]=S.useState(!1),[R,k]=S.useState(null),[D,B]=S.useState(null),q=(s==null?void 0:s.active_method)!==null&&(s==null?void 0:s.active_method)!==void 0,L=async()=>{if(confirm("Disconnect git remote credentials? Auto-push will stop working until you reconnect.")){g(!0),k(null);try{const X=await Xg(i);r(X)}catch(X){k(X instanceof Error?X.message:String(X))}finally{g(!1)}}};return c.jsxs("div",{className:"section",id:"git-remote-section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:q?"Backed up to a git remote":"Back up to GitHub"}),c.jsx("p",{className:"dim",style:{marginTop:0},children:q?c.jsxs(c.Fragment,{children:["Your vault pushes its history to an off-machine git remote. Credentials are stored on this server with ",c.jsx("code",{children:"0600"})," file permissions — never sent to GitHub or any third party."]}):c.jsxs(c.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"," ",c.jsx("code",{children:"0600"})," file permissions, never sent to a third party."]})}),!m&&!(s!=null&&s.active_method)?c.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,f?c.jsxs("div",{className:"error-banner",role:"alert",children:["Could not load credential status: ",c.jsx("code",{children:f})]}):null,q?c.jsxs("div",{className:"kv",style:{marginBottom:"0.75rem"},children:[c.jsx("div",{children:"Status"}),c.jsx("div",{children:(s==null?void 0:s.active_method)==="github_oauth"&&s.github_oauth?c.jsxs(c.Fragment,{children:["Connected to ",c.jsxs("code",{children:["@",s.github_oauth.user_login]})," on GitHub"]}):(s==null?void 0:s.active_method)==="pat"&&s.pat?c.jsxs(c.Fragment,{children:["Custom credential: ",c.jsx("code",{children:s.pat.label})]}):null}),(s==null?void 0:s.active_method)==="github_oauth"&&s.github_oauth?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Token"}),c.jsxs("div",{children:[c.jsx("code",{children:s.github_oauth.token_preview})," ",c.jsxs("span",{className:"dim",children:["· scope ",s.github_oauth.scope||"—"," · authorized"," ",s.github_oauth.authorized_at.slice(0,10)]})]})]}):null,(s==null?void 0:s.active_method)==="pat"&&s.pat?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Remote"}),c.jsx("div",{children:c.jsx("code",{children:s.pat.remote_url})}),c.jsx("div",{children:"Token"}),c.jsx("div",{children:c.jsx("code",{children:s.pat.token_preview})})]}):null]}):c.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."}),R?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:R})}):null,D?c.jsxs("div",{className:"mint-banner",style:{marginBottom:"0.75rem"},role:"status",children:[c.jsx("strong",{children:"Credentials saved."})," ",(()=>{const X=D,J=X.initial_push.fired&&X.initial_push.pushed?X.initial_push.sha:void 0,V=X.initial_push.fired&&!X.initial_push.pushed?X.initial_push.error:void 0;return X.auto_push_was_already_enabled?J?c.jsxs(c.Fragment,{children:["Auto-push was already on; just pushed"," ",c.jsx("code",{children:J.slice(0,10)}),"."]}):V?c.jsx(c.Fragment,{children:"Auto-push was already on; the push attempt failed — see Advanced settings → Status for details."}):c.jsx(c.Fragment,{children:"Auto-push was already on; nothing to push right now."}):X.auto_push_enabled?J?c.jsxs(c.Fragment,{children:["Auto-push enabled and the first push landed"," ",c.jsx("code",{children:J.slice(0,10)}),". Your next commit will push to the remote too."]}):V?c.jsx(c.Fragment,{children:"Auto-push enabled. The initial push attempt failed — see Advanced settings → Status for the error."}):c.jsx(c.Fragment,{children:"Auto-push enabled. Your next commit will push to the remote."}):c.jsx(c.Fragment,{children:"Credentials wired. Auto-push remains off; flip it on in Advanced settings → Configuration to push commits automatically."})})()," ",c.jsx("button",{type:"button",className:"secondary",onClick:()=>B(null),style:{marginLeft:"0.5rem"},"aria-label":"Dismiss",children:"Dismiss"})]}):null,c.jsx("div",{className:"actions",children:q?c.jsx("button",{type:"button",className:"secondary",onClick:L,disabled:_,children:_?"Disconnecting…":"Disconnect"}):c.jsxs(c.Fragment,{children:[c.jsx("button",{type:"button",onClick:()=>v(!0),children:"Use Personal Access Token"}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>E(!0),children:"Connect GitHub (one-click for GitHub users)"})]})}),y?c.jsx(i0,{vaultName:i,onClose:()=>E(!1),onConnected:(X,J)=>{r(X),J&&(B(J),h(J)),E(!1)}}):null,b?c.jsx(r0,{vaultName:i,onClose:()=>v(!1),onSaved:X=>{r(X),B(X),h(X),v(!1)}}):null]})}function i0({vaultName:i,onClose:s,onConnected:f}){const[r,h]=S.useState({kind:"starting"}),[m,y]=S.useState(Date.now()),E=S.useRef(!1);S.useEffect(()=>{const v=setInterval(()=>y(Date.now()),1e3);return()=>clearInterval(v)},[]),S.useEffect(()=>{let v=!1;return E.current=!1,Qg(i).then(_=>{v||h({kind:"polling",code:_,pollIntervalMs:Math.max(_.interval,1)*1e3,startedAt:Date.now()})}).catch(_=>{v||h({kind:"error",message:_ instanceof Error?_.message:String(_)})}),()=>{v=!0,E.current=!0}},[i]),S.useEffect(()=>{if(r.kind!=="polling")return;const v=r.code;let _=!1,g=null,R=r.pollIntervalMs;const k=async()=>{if(!(_||E.current))try{const D=await Vg(i,v.polling_id);if(_)return;if(D.state==="granted"){h({kind:"granted",user:{login:D.user.login}});return}if(D.state==="denied"){h({kind:"error",message:"Authorization denied."});return}if(D.state==="expired"){h({kind:"error",message:"The device code expired. Try again."});return}D.state==="slow_down"&&(R=D.interval*1e3),g=setTimeout(k,R)}catch(D){if(_)return;h({kind:"error",message:D instanceof Error?D.message:String(D)})}};return g=setTimeout(k,R),()=>{_=!0,g&&clearTimeout(g)}},[r,i]);const b=async v=>{try{await navigator.clipboard.writeText(v)}catch{}};return c.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:c.jsxs("div",{className:"modal",children:[c.jsxs("div",{className:"list-header",children:[c.jsx("h3",{style:{margin:0},children:"Connect GitHub"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,children:"Close"})]}),r.kind==="starting"?c.jsx("p",{className:"muted",children:"Requesting device code from GitHub…"}):null,r.kind==="polling"?c.jsxs(c.Fragment,{children:[c.jsxs("p",{children:[c.jsx("strong",{children:"Step 1."})," Open"," ",c.jsx("a",{href:r.code.verification_uri,target:"_blank",rel:"noreferrer",children:r.code.verification_uri})," ","in your browser."]}),c.jsxs("p",{children:[c.jsx("strong",{children:"Step 2."})," Enter this code:"]}),c.jsxs("div",{className:"device-code-row",children:[c.jsx("code",{className:"device-code",children:r.code.user_code}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>b(r.code.user_code),children:"Copy"})]}),c.jsxs("p",{className:"dim",children:["Waiting for authorization…"," ",c0(r.code.expires_in,r.startedAt,m)]})]}):null,r.kind==="granted"?c.jsx(s0,{vaultName:i,user:r.user,onPicked:async(v,_)=>{const g=await Jg(i,{owner:v,name:_}),R=await dm(i);f(R,g)},onError:v=>h({kind:"error",message:v})}):null,r.kind==="error"?c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:r.message})}),c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:()=>h({kind:"starting"}),children:"Try again"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,children:"Close"})]})]}):null]})})}function c0(i,s,f){const r=Math.floor((f-s)/1e3),h=Math.max(0,i-r),m=Math.floor(h/60),y=h%60;return`${m}:${String(y).padStart(2,"0")} remaining`}function s0({vaultName:i,user:s,onPicked:f,onError:r}){const[h,m]=S.useState(null),[y,E]=S.useState(!1),[b,v]=S.useState(""),[_,g]=S.useState(null),[R,k]=S.useState(!1),[D,B]=S.useState(""),[q,L]=S.useState(!1);S.useEffect(()=>{let Y=!1;return hm(i).then(({repos:K,truncated:G})=>{Y||(m(K),E(!!G))}).catch(K=>{Y||r(K instanceof Error?K.message:String(K))}),()=>{Y=!0}},[i,r]);const X=(h??[]).filter(Y=>b.length===0?!0:Y.full_name.toLowerCase().includes(b.toLowerCase())),J=async(Y,K)=>{g(`${Y}/${K}`);try{await f(Y,K)}catch(G){r(G instanceof Error?G.message:String(G))}finally{g(null)}},V=async()=>{if(D.trim().length!==0){k(!0);try{const Y=await Kg(i,{name:D.trim(),description:"Parachute Vault mirror",private:!0});await f(Y.owner,Y.name)}catch(Y){r(Y instanceof Error?Y.message:String(Y))}finally{k(!1)}}};return c.jsxs(c.Fragment,{children:[c.jsxs("p",{children:["Authorized as ",c.jsxs("code",{children:["@",s.login]}),". Pick a repository to push the mirror to:"]}),c.jsx("div",{className:"form-row",children:c.jsx("input",{type:"search",placeholder:"Filter by name…",value:b,onChange:Y=>v(Y.target.value)})}),y?c.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos. Use the filter above to narrow down — or paste the clone URL directly via Personal Access Token below if your repo isn't here."}):null,h===null?c.jsx("p",{className:"muted",children:"Loading repos…"}):null,h!==null?c.jsxs("div",{className:"repo-list",children:[X.length===0&&b.length>0?c.jsxs("p",{className:"dim",children:['No repos match "',b,'".']}):null,X.length===0&&b.length===0&&h.length===0?c.jsx("p",{className:"dim",children:"You don't own any repos on this account yet."}):null,X.map(Y=>c.jsxs("button",{type:"button",className:"repo-row",onClick:()=>J(Y.owner,Y.name),disabled:_!==null,children:[c.jsxs("span",{children:[c.jsx("strong",{children:Y.name}),Y.private?c.jsx("span",{className:"dim",children:" · private"}):null]}),c.jsx("span",{className:"dim",children:Y.updated_at.slice(0,10)})]},Y.full_name))]}):null,q?c.jsxs("div",{className:"form-row",style:{marginTop:"0.75rem"},children:[c.jsx("label",{htmlFor:"new-repo-name",children:"New repo name"}),c.jsx("input",{id:"new-repo-name",type:"text",value:D,placeholder:"my-vault-backup",onChange:Y=>B(Y.target.value)}),c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:V,disabled:R||D.trim().length===0,children:R?"Creating…":"Create"}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>L(!1),disabled:R,children:"Cancel"})]})]}):c.jsx("div",{className:"actions",style:{marginTop:"0.75rem"},children:c.jsx("button",{type:"button",className:"secondary",onClick:()=>L(!0),children:"+ Create new private repo"})})]})}function r0({vaultName:i,onClose:s,onSaved:f}){const[r,h]=S.useState(""),[m,y]=S.useState(""),[E,b]=S.useState(""),[v,_]=S.useState(!1),[g,R]=S.useState(null),k=async D=>{D.preventDefault(),_(!0),R(null);try{const B=await Zg(i,{token:r.trim(),remote_url:m.trim(),label:E.trim()||void 0});f(B)}catch(B){R(B instanceof Error?B.message:String(B))}finally{_(!1)}};return c.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:c.jsxs("div",{className:"modal",children:[c.jsxs("div",{className:"list-header",children:[c.jsx("h3",{style:{margin:0},children:"Use Personal Access Token"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,disabled:v,children:"Close"})]}),c.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"," ",c.jsx("code",{children:"0600"})," file perms on this server."]}),c.jsxs("form",{onSubmit:k,children:[c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"pat-token",children:"Token"}),c.jsx("input",{id:"pat-token",type:"password",value:r,autoComplete:"off",onChange:D=>h(D.target.value),placeholder:"ghp_… or glpat-… or similar",required:!0})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"pat-url",children:"Remote URL"}),c.jsx("input",{id:"pat-url",type:"url",value:m,onChange:D=>y(D.target.value),placeholder:"https://github.com/owner/repo.git",required:!0}),c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["We'll embed your token in the URL before saving (using GitHub's"," ",c.jsx("code",{children:"x-access-token"})," convention). The URL you see on disk will carry the token; ensure the file isn't shared."]})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"pat-label",children:"Label (optional)"}),c.jsx("input",{id:"pat-label",type:"text",value:E,onChange:D=>b(D.target.value),placeholder:"GitHub PAT for backup"})]}),g?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:g})}):null,c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"submit",disabled:v,children:v?"Validating…":"Validate & save"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,disabled:v,children:"Cancel"})]})]})]})})}function o0({vaultName:i,creds:s}){const[f,r]=S.useState(""),[h,m]=S.useState("merge"),[y,E]=S.useState(!1),[b,v]=S.useState(""),[_,g]=S.useState(!0),[R,k]=S.useState({kind:"idle"}),[D,B]=S.useState(""),[q,L]=S.useState(!1),X=(s==null?void 0:s.active_method)==="github_oauth"&&s.github_oauth!==null,J=(s==null?void 0:s.active_method)!==null&&(s==null?void 0:s.active_method)!==void 0,V=h!=="replace"||D.trim()===i,Y=R.kind!=="running"&&f.trim().length>0&&V&&(!y||b.trim().length>0),K=async()=>{k({kind:"running",stage:"cloning"});let te;y?te={kind:"pat",token:b.trim()}:J?te=null:te={kind:"none"};try{const ye=window.setTimeout(()=>k(We=>We.kind==="running"?{kind:"running",stage:"importing"}:We),1500),tt=await $g(i,{remote_url:f.trim(),mode:h,credentials:te,enable_sync:_});window.clearTimeout(ye),k({kind:"success",result:tt,remoteUrl:f.trim(),mode:h})}catch(ye){const tt=ye instanceof _e?`${ye.status===409?"Already running. ":""}${ye.message}`:ye instanceof Error?ye.message:String(ye);k({kind:"error",message:tt})}},G=()=>{k({kind:"idle"}),B("")};return c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Import from a git repo"}),c.jsxs("p",{className:"dim",style:{marginTop:0},children:["Pull a vault state from a remote git repo into ",c.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 ",c.jsx("code",{children:"parachute-vault export"})," or the mirror's export flow)."]}),c.jsxs("div",{className:"warn-banner",style:{marginBottom:"1rem"},role:"note",children:[c.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."]}),R.kind==="success"?c.jsx(f0,{vaultName:i,result:R.result,remoteUrl:R.remoteUrl,mode:R.mode,onReset:G}):c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"import-remote-url",children:"Remote URL"}),c.jsx("input",{id:"import-remote-url",type:"text",value:f,placeholder:"https://github.com/aaron/my-vault.git",onChange:te=>r(te.target.value),disabled:R.kind==="running"}),X?c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.9em"},children:["Or"," ",c.jsx("button",{type:"button",onClick:()=>L(!0),disabled:R.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,!J&&!y?c.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]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{children:"Mode"}),c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"import-mode",value:"merge",checked:h==="merge",onChange:()=>{m("merge"),B("")},disabled:R.kind==="running"}),c.jsxs("span",{children:[c.jsx("strong",{children:"Merge"})," ",c.jsxs("span",{className:"dim",children:["— upsert by id. Notes in the remote get created/updated; any notes that exist only locally ",c.jsx("strong",{children:"survive"}),"."]})]})]}),c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"import-mode",value:"replace",checked:h==="replace",onChange:()=>m("replace"),disabled:R.kind==="running"}),c.jsxs("span",{children:[c.jsx("strong",{children:"Replace"})," ",c.jsxs("span",{className:"dim",children:["— wipe this vault first, then import. The remote becomes the new source of truth. ",c.jsx("strong",{children:"Destructive."})]})]})]})]}),h==="replace"?c.jsxs("div",{className:"form-row",children:[c.jsxs("div",{className:"error-banner",role:"alert",style:{marginBottom:"0.5rem"},children:[c.jsxs("strong",{children:['Replace will delete every note in vault "',i,'" before importing.']})," To confirm, type the vault name below:"]}),c.jsx("input",{id:"import-confirm-name",type:"text",value:D,placeholder:i,onChange:te=>B(te.target.value),disabled:R.kind==="running","aria-label":"Type vault name to confirm"})]}):null,c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:y,onChange:te=>E(te.target.checked),disabled:R.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"One-time credential for this import only"]}),c.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."}),y?c.jsx("input",{id:"import-per-call-pat",type:"password",value:b,placeholder:"ghp_… or similar",onChange:te=>v(te.target.value),disabled:R.kind==="running",autoComplete:"off",style:{marginTop:"0.5rem"}}):null]}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:_,onChange:te=>g(te.target.checked),disabled:R.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"Also sync changes back to this repo"]}),c.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."})]}),R.kind==="error"?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:R.message})}):null,c.jsx("div",{className:"actions",children:c.jsx("button",{type:"button",onClick:K,disabled:!Y,title:V?f.trim().length===0?"Provide a remote URL.":y&&b.trim().length===0?"Provide a token for one-time credential.":void 0:"Type the vault name to confirm Replace.",children:R.kind==="running"?R.stage==="cloning"?"Cloning…":"Importing…":"Start import"})})]}),q?c.jsx(d0,{vaultName:i,onClose:()=>L(!1),onPicked:te=>{r(te),L(!1)}}):null]})}function f0({vaultName:i,result:s,remoteUrl:f,mode:r,onReset:h}){return c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"0.75rem"},children:[c.jsx("strong",{children:"Import succeeded."})," Imported ",s.notes_imported," note",s.notes_imported===1?"":"s",", ",s.tags_imported," tag schema",s.tags_imported===1?"":"s",", ",s.attachments_imported," ","attachment",s.attachments_imported===1?"":"s",r==="replace"&&s.notes_deleted!==void 0?`, wiped ${s.notes_deleted} pre-existing note${s.notes_deleted===1?"":"s"}`:"","."]}),s.warnings.length>0?c.jsxs("details",{style:{marginBottom:"0.75rem"},children:[c.jsxs("summary",{children:[s.warnings.length," warning",s.warnings.length===1?"":"s"," ","(see details)"]}),c.jsx("ul",{style:{marginTop:"0.5rem"},children:s.warnings.map((m,y)=>c.jsx("li",{children:c.jsx("code",{style:{fontSize:"0.85em"},children:m})},y))})]}):null,s.sync_enabled?c.jsxs("div",{className:"mint-banner",style:{marginBottom:"0.75rem"},role:"status",children:[c.jsx("strong",{children:"Sync enabled."})," Changes to vault ",c.jsx("code",{children:i})," ","now push back to ",c.jsx("code",{children:f})," automatically."]}):s.sync_warning?c.jsxs("div",{className:"info-banner",style:{marginBottom:"0.75rem"},role:"status",children:[c.jsxs("p",{style:{marginTop:0},children:[c.jsx("strong",{children:"Sync not enabled."})," ",s.sync_warning]}),c.jsxs("p",{className:"dim",style:{marginBottom:0,fontSize:"0.9em"},children:["You can still set up Sync from the"," ",c.jsx("button",{type:"button",onClick:()=>{var m;return(m=document.getElementById("git-remote-section"))==null?void 0:m.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,c.jsx("div",{className:"actions",children:c.jsx("button",{type:"button",className:"secondary",onClick:h,children:"Run another import"})})]})}function d0({vaultName:i,onClose:s,onPicked:f}){const[r,h]=S.useState(null),[m,y]=S.useState(!1),[E,b]=S.useState(""),[v,_]=S.useState(null);S.useEffect(()=>{let R=!1;return hm(i).then(({repos:k,truncated:D})=>{R||(h(k),y(!!D))}).catch(k=>{R||_(k instanceof Error?k.message:String(k))}),()=>{R=!0}},[i]);const g=(r??[]).filter(R=>E.length===0?!0:R.full_name.toLowerCase().includes(E.toLowerCase()));return c.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:c.jsxs("div",{className:"modal",children:[c.jsxs("div",{className:"list-header",children:[c.jsx("h3",{style:{margin:0},children:"Pick a repo to import from"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,children:"Close"})]}),v?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:v})}):null,c.jsx("div",{className:"form-row",children:c.jsx("input",{type:"search",placeholder:"Filter by name…",value:E,onChange:R=>b(R.target.value)})}),m?c.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos. Use the filter above to narrow down."}):null,r===null&&!v?c.jsx("p",{className:"muted",children:"Loading repos…"}):null,r!==null?c.jsxs("div",{className:"repo-list",children:[g.length===0&&E.length>0?c.jsxs("p",{className:"dim",children:['No repos match "',E,'".']}):null,g.length===0&&E.length===0&&r.length===0?c.jsx("p",{className:"dim",children:"You don't own any repos on this account."}):null,g.map(R=>c.jsxs("button",{type:"button",className:"repo-row",onClick:()=>f(R.clone_url),children:[c.jsxs("span",{children:[c.jsx("strong",{children:R.name}),R.private?c.jsx("span",{className:"dim",children:" · private"}):null]}),c.jsx("span",{className:"dim",children:R.updated_at.slice(0,10)})]},R.full_name))]}):null]})})}let Gn=null,Xn=null;function h0(i){const s=Date.parse(i);return Number.isNaN(s)?null:s}async function m0(){if(typeof window>"u")return{kind:"network-error",message:"no window"};let i;try{i=await fetch("/admin/host-admin-token",{method:"GET",headers:{accept:"application/json"},credentials:"same-origin"})}catch(f){return{kind:"network-error",message:f instanceof Error?f.message:String(f)}}if(i.status===403)return{kind:"forbidden"};if(i.status===401||i.status===404)return{kind:"auth-required",status:i.status};if(!i.ok)return{kind:"network-error",message:`hub returned ${i.status}`};let s;try{s=await i.json()}catch(f){return{kind:"network-error",message:f instanceof Error?f.message:"could not parse host-admin mint response"}}return typeof s.token!="string"||s.token.length===0?{kind:"network-error",message:"host-admin mint response missing token"}:(Gn=s.token,Xn=s.expires_at?h0(s.expires_at):null,{kind:"ok",token:s.token})}async function Lh(){if(Gn){if(Xn===null||Xn>Date.now())return{kind:"ok",token:Gn};Gn=null,Xn=null}return m0()}function v0(){Gn=null,Xn=null}class Ga extends Error{constructor(s,f,r){super(f),this.status=s,this.disposition=r,this.name="HostAdminError"}}async function fr(i,s={}){let f;const r=await Lh();if(r.kind!=="ok")throw kh(r);f=r.token;const{headers:h,...m}=s,y=v=>({accept:"application/json",...h??{},authorization:`Bearer ${v}`}),E=await fetch(i,{...m,headers:y(f)});if(E.status!==401)return E;v0();const b=await Lh();if(b.kind!=="ok")throw kh(b);return fetch(i,{...m,headers:y(b.token)})}function kh(i){return i.kind==="forbidden"?new Ga(403,"host-admin token mint forbidden — not the hub admin","forbidden"):i.kind==="auth-required"?new Ga(i.status,"no host-admin session — sign in to the hub to manage tokens","auth-required"):new Ga(0,i.message,"network-error")}function dr(){if(typeof window>"u")return;const i=ym();window.location.href=i?`${i}/account/`:"/account/"}const y0=[30,90,180,365],qh=90,p0=1440*60;function g0(i){if(!i)return null;const s=i.scoped_tags;if(!Array.isArray(s))return null;const f=s.filter(r=>typeof r=="string"&&r.length>0);return f.length>0?f:null}function b0(i){return{jti:i.jti,label:i.subject,scopes:Array.isArray(i.scopes)?i.scopes:[],scoped_tags:g0(i.permissions),expires_at:i.expires_at??null,revoked_at:i.revoked_at??null,created_at:i.created_at}}async function S0(i,s){const f={scope:`vault:${i}:${s.verb}`,expires_in:s.ttlDays*p0,subject:s.label};s.scopedTags.length>0&&(f.permissions={scoped_tags:s.scopedTags});const r=await fr("/api/auth/mint-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(f)});if(!r.ok)throw new _e(r.status,await xi(r));const h=await r.json();return{jti:h.jti,token:h.token,scope:h.scope,expires_at:h.expires_at??null}}async function x0(i){const s=`vault:${i}:`,f=[];let r=null;for(let h=0;h<1e3;h++){const m=new URLSearchParams({revoked:"all"});r&&m.set("cursor",r);const y=await fr(`/api/auth/tokens?${m.toString()}`);if(!y.ok)throw new _e(y.status,await xi(y));const E=await y.json(),b=Array.isArray(E.tokens)?E.tokens:[];if(f.push(...b),r=E.next_cursor??null,!r)break}return f.filter(h=>Array.isArray(h.scopes)&&h.scopes.some(m=>m.startsWith(s))).map(b0)}async function j0(i){const s=await fr("/api/auth/revoke-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jti:i})});if(!s.ok)throw new _e(s.status,await xi(s))}async function E0(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/api/tags`);if(!s.ok)throw new _e(s.status,await xi(s));const f=await s.json();return Array.isArray(f)?f:[]}async function xi(i){try{const s=await i.text(),f=JSON.parse(s);if(f.error_description)return f.error_description;if(f.message)return f.message;if(f.error)return f.error;if(s)return s}catch{}return`${i.status} ${i.statusText}`}const T0=["read","write","admin"],_0={30:"30 days",90:"90 days",180:"180 days",365:"1 year (max)"};function A0(i){return i instanceof Ga?i.disposition==="forbidden"?(dr(),{kind:"auth-required",status:403}):i.disposition==="auth-required"?{kind:"auth-required",status:i.status}:{kind:"error",message:i.message}:i instanceof _e&&(i.status===401||i.status===403)?{kind:"auth-required",status:i.status}:{kind:"error",message:i instanceof Error?i.message:String(i)}}function Yh({vaultName:i}={}){const s=lr(),f=i??s.name,r=i!==void 0,h=r?"/":`/vault/${encodeURIComponent(f??"")}`,[m,y]=S.useState({kind:"loading"}),[E,b]=S.useState(null),[v,_]=S.useState(null),[g,R]=S.useState(0);S.useEffect(()=>{let B=!1;if(f)return y({kind:"loading"}),x0(f).then(q=>{B||y({kind:"ok",tokens:q})}).catch(q=>{B||y(A0(q))}),()=>{B=!0}},[f,g]);const k=S.useCallback(()=>R(B=>B+1),[]);if(S.useEffect(()=>{if(!E)return;const B=q=>{q.preventDefault(),q.returnValue=""};return window.addEventListener("beforeunload",B),()=>window.removeEventListener("beforeunload",B)},[E]),!f)return c.jsxs("div",{children:[c.jsx("h2",{children:"Tokens"}),c.jsx("p",{className:"muted",children:"Missing vault name."}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});const D=vm(f);return c.jsxs("div",{children:[c.jsxs("div",{className:"list-header",children:[c.jsxs("h2",{children:["Tokens for ",c.jsx("code",{children:f})]}),c.jsx(Je,{to:h,className:"muted",children:"← Vault detail"})]}),D?null:c.jsxs("div",{className:"warn-banner",children:["You're viewing this page with a read-only token. Mint and revoke require"," ",c.jsxs("code",{children:["vault:",f,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin-scoped session to manage tokens.`]}),E?c.jsx(N0,{result:E,onDismiss:()=>b(null)}):null,m.kind==="ok"&&D&&!E?c.jsx(R0,{vaultName:f,onMinted:B=>{b(B),R(q=>q+1)}}):null,c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Existing tokens"}),m.kind==="loading"?c.jsx("p",{className:"muted",children:"Loading…"}):null,m.kind==="auth-required"?c.jsx(or,{vaultName:f,status:m.status,onRecovered:k}):null,m.kind==="error"?c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:m.message})}):null,m.kind==="ok"?c.jsx(z0,{tokens:m.tokens,allowRevoke:D,confirmingJti:v,onAskConfirm:_,onRevoked:()=>{_(null),R(B=>B+1)}}):null]})]})}function N0({result:i,onDismiss:s}){const[f,r]=S.useState(!1),h=async()=>{try{await navigator.clipboard.writeText(i.token),r(!0),setTimeout(()=>r(!1),2e3)}catch{}};return c.jsxs("div",{className:"mint-banner",children:[c.jsx("h3",{children:"New token (shown once)"}),c.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."}),c.jsxs("div",{className:"token-box",children:[c.jsx("code",{children:i.token}),c.jsx("button",{type:"button",onClick:h,className:"secondary",children:f?"Copied":"Copy"})]}),c.jsx("p",{className:"warn",children:"⚠ Don't dismiss this banner until you've saved the token."}),c.jsx("div",{className:"actions",children:c.jsx("button",{type:"button",onClick:s,children:"Done — I've saved the token"})})]})}function R0({vaultName:i,onMinted:s}){const[f,r]=S.useState(""),[h,m]=S.useState("admin"),[y,E]=S.useState(qh),[b,v]=S.useState(!1),[_,g]=S.useState(null),[R,k]=S.useState([]),[D,B]=S.useState(null),[q,L]=S.useState(new Set);S.useEffect(()=>{let K=!1;return E0(i).then(G=>{if(K)return;const te=G.map(ye=>ye.name).filter(ye=>!ye.includes("/")).sort();k(te)}).catch(G=>{K||B(G instanceof Error?G.message:String(G))}),()=>{K=!0}},[i]);const X=f.trim(),J=X.length===0,V=K=>{L(G=>{const te=new Set(G);return te.has(K)?te.delete(K):te.add(K),te})},Y=async K=>{if(K.preventDefault(),J){g("label required — give the token a recognizable name");return}v(!0),g(null);try{const G=await S0(i,{verb:h,label:X,scopedTags:[...q],ttlDays:y});s(G),r(""),m("admin"),E(qh),L(new Set)}catch(G){if(G instanceof Ga&&G.disposition==="forbidden"){dr();return}g(G instanceof Error?G.message:String(G))}finally{v(!1)}};return c.jsxs("form",{onSubmit:Y,className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Mint a token"}),c.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."}),_?c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:_})}):null,c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{htmlFor:"mint-label",children:["Label ",c.jsx("span",{className:"dim",children:"(required)"})]}),c.jsx("input",{id:"mint-label",type:"text",value:f,onChange:K=>r(K.target.value),placeholder:"e.g. ci, paraclaw-prod, my-laptop",maxLength:120,required:!0})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"mint-scope",children:"Scope"}),c.jsx("select",{id:"mint-scope",value:h,onChange:K=>m(K.target.value),children:T0.map(K=>c.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))}),c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Issued as ",c.jsxs("code",{children:["vault:",i,":",h]}),". Lower scopes inherit narrower powers."]})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"mint-ttl",children:"Expires after"}),c.jsx("select",{id:"mint-ttl",value:y,onChange:K=>E(Number(K.target.value)),children:y0.map(K=>c.jsx("option",{value:K,children:_0[K]??`${K} days`},K))}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"The token stops working after this. Rotate before it lapses."})]}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:["Tag scope ",c.jsx("span",{className:"dim",children:"(optional)"})]}),D?c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Couldn't load tags: ",c.jsx("code",{children:D}),". Token will be unscoped."]}):R.length===0?c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"No root tags in this vault yet — token will see the full vault."}):c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"tag-picker",children:R.map(K=>c.jsxs("label",{className:"tag-checkbox",children:[c.jsx("input",{type:"checkbox",checked:q.has(K),onChange:()=>V(K)}),c.jsx("code",{children:K})]},K))}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:q.size===0?"Nothing selected — token sees the full vault (unscoped).":`Token limited to: ${[...q].join(", ")}. Sub-tags (e.g. health/food) are reachable when their root is selected.`})]})]}),c.jsx("div",{className:"actions",children:c.jsx("button",{type:"submit",disabled:b||J,children:b?"Minting…":"Mint token"})})]})}function z0({tokens:i,allowRevoke:s,confirmingJti:f,onAskConfirm:r,onRevoked:h}){return i.length===0?c.jsx("p",{className:"muted",children:"No tokens yet. Mint one above to get started."}):c.jsx("div",{className:"token-list",children:i.map(m=>c.jsx(C0,{token:m,allowRevoke:s,confirming:f===m.jti,onAskConfirm:r,onRevoked:h},m.jti))})}function C0({token:i,allowRevoke:s,confirming:f,onAskConfirm:r,onRevoked:h}){const[m,y]=S.useState(!1),[E,b]=S.useState(null),v=i.revoked_at!==null,_=async()=>{y(!0),b(null);try{await j0(i.jti),h()}catch(g){if(g instanceof Ga&&g.disposition==="forbidden"){dr();return}b(g instanceof Error?g.message:String(g)),y(!1)}};return c.jsxs("div",{className:"token-row",children:[c.jsxs("div",{className:"body",children:[c.jsxs("div",{className:"name",children:[c.jsx("strong",{children:i.label??"(unlabeled)"}),c.jsx("code",{className:"dim",children:i.jti}),v?c.jsx("code",{className:"scope-tag",title:"This token has been revoked and no longer works.",children:"revoked"}):null]}),c.jsxs("div",{className:"meta",children:[c.jsx("span",{className:"dim",children:"scopes:"})," ",i.scopes.length>0?i.scopes.map(g=>c.jsx("code",{className:"scope-tag",children:g},g)):c.jsx("span",{className:"dim",children:"(none)"})]}),i.scoped_tags&&i.scoped_tags.length>0?c.jsxs("div",{className:"meta",children:[c.jsx("span",{className:"dim",children:"tags:"})," ",i.scoped_tags.map(g=>c.jsxs("code",{className:"scope-tag tag-pill",children:["#",g]},g))]}):null,c.jsxs("div",{className:"meta dim",children:["created ",i.created_at,i.expires_at?` · expires ${i.expires_at}`:"",v&&i.revoked_at?` · revoked ${i.revoked_at}`:""]}),E?c.jsx("div",{className:"error-banner",style:{marginTop:"0.5rem"},children:c.jsx("code",{children:E})}):null]}),s&&!v?f?c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:_,disabled:m,children:m?"Revoking…":"Confirm revoke"}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>r(null),disabled:m,children:"Cancel"})]}):c.jsx("button",{type:"button",className:"secondary",onClick:()=>r(i.jti),children:"Revoke"}):null]})}function w0(){const[i,s]=S.useState({kind:"loading"});return S.useEffect(()=>{let f=!1;return Bg().then(r=>{f||s({kind:"ok",vaults:r})}).catch(r=>{if(f)return;const h=r instanceof _e?`${r.status}: ${r.message}`:r instanceof Error?r.message:String(r);s({kind:"error",message:h})}),()=>{f=!0}},[]),i.kind==="loading"?c.jsxs("div",{children:[c.jsx("h2",{children:"Vaults"}),c.jsx("p",{className:"muted",children:"Loading…"})]}):i.kind==="error"?c.jsxs("div",{children:[c.jsx("h2",{children:"Vaults"}),c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:i.message})})]}):i.vaults.length===0?c.jsxs("div",{children:[c.jsx("h2",{children:"Vaults"}),c.jsxs("div",{className:"empty",children:["No vaults yet. Run ",c.jsx("code",{children:"parachute-vault create <name>"})," on the host to create one."]})]}):c.jsxs("div",{children:[c.jsx("div",{className:"list-header",children:c.jsx("h2",{children:"Vaults"})}),i.vaults.map(f=>c.jsxs(Je,{to:`/vault/${f}`,className:"vault-row",children:[c.jsx("div",{className:"body",children:c.jsx("div",{className:"name",children:c.jsx("code",{children:f})})}),c.jsx("div",{className:"chev",children:"→"})]},f))]})}function M0(){const i=om();return c.jsxs("div",{className:"page",children:[c.jsxs("nav",{className:"nav",children:[c.jsxs(Je,{to:"/",className:"brand",children:["Parachute Vault ",c.jsx("span",{className:"sub",children:"admin"})]}),i?c.jsx(Je,{to:"/",children:c.jsx("code",{children:i})}):c.jsx(Je,{to:"/",children:"Vaults"})]}),i?c.jsxs(Mh,{children:[c.jsx(Yt,{path:"/",element:c.jsx(Hh,{vaultName:i})}),c.jsx(Yt,{path:"/tokens",element:c.jsx(Yh,{vaultName:i})}),c.jsx(Yt,{path:"/mirror",element:c.jsx(Bh,{vaultName:i})}),c.jsx(Yt,{path:"*",element:c.jsx(Gh,{})})]}):c.jsxs(Mh,{children:[c.jsx(Yt,{path:"/",element:c.jsx(w0,{})}),c.jsx(Yt,{path:"/vault/:name",element:c.jsx(Hh,{})}),c.jsx(Yt,{path:"/vault/:name/tokens",element:c.jsx(Yh,{})}),c.jsx(Yt,{path:"/vault/:name/mirror",element:c.jsx(Bh,{})}),c.jsx(Yt,{path:"*",element:c.jsx(Gh,{})})]})]})}function Gh(){return c.jsxs("div",{className:"empty",children:["404 — back to ",c.jsx(Je,{to:"/",children:"vault"}),"."]})}wg();const pm=document.getElementById("root");if(!pm)throw new Error("#root not found");function $s(){Fy.createRoot(pm).render(c.jsx(S.StrictMode,{children:c.jsx(pg,{basename:Ng(),children:c.jsx(M0,{})})}))}const Xh=om();Xh?Dg(Xh).then($s,$s):$s();
|
|
60
|
+
Please change the parent <Route path="${L}"> to <Route path="${L==="/"?"*":`${L}/*`}">.`)}let _=fl(),g;if(s){let L=typeof s=="string"?Xa(s):s;ze(b==="/"||((q=L.pathname)==null?void 0:q.startsWith(b)),`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 "${b}" but pathname "${L.pathname}" was given in the \`location\` prop.`),g=L}else g=_;let R=g.pathname||"/",k=R;if(b!=="/"){let L=b.replace(/^\//,"").split("/");k="/"+R.replace(/^\//,"").split("/").slice(L.length).join("/")}let D=Qh(i,{pathname:k});Xt(v||D!=null,`No routes matched location "${g.pathname}${g.search}${g.hash}" `),Xt(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 "${g.pathname}${g.search}${g.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 B=kp(D&&D.map(L=>Object.assign({},L,{params:Object.assign({},y,L.params),pathname:Ut([b,r.encodeLocation?r.encodeLocation(L.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:L.pathname]),pathnameBase:L.pathnameBase==="/"?b:Ut([b,r.encodeLocation?r.encodeLocation(L.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:L.pathnameBase])})),h,f);return s&&B?S.createElement(Zn.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",unstable_mask:void 0,...g},navigationType:"POP"}},B):B}function Up(){let i=Qp(),s=xp(i)?`${i.status} ${i.statusText}`:i instanceof Error?i.message:JSON.stringify(i),f=i instanceof Error?i.stack:null,r="rgba(200,200,200, 0.5)",h={padding:"0.5rem",backgroundColor:r},m={padding:"2px 4px",backgroundColor:r},y=null;return console.error("Error handled by React Router default ErrorBoundary:",i),y=S.createElement(S.Fragment,null,S.createElement("p",null,"💿 Hey developer 👋"),S.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",S.createElement("code",{style:m},"ErrorBoundary")," or"," ",S.createElement("code",{style:m},"errorElement")," prop on your route.")),S.createElement(S.Fragment,null,S.createElement("h2",null,"Unexpected Application Error!"),S.createElement("h3",{style:{fontStyle:"italic"}},s),f?S.createElement("pre",{style:h},f):null,y)}var Hp=S.createElement(Up,null),nm=class extends S.Component{constructor(i){super(i),this.state={location:i.location,revalidation:i.revalidation,error:i.error}}static getDerivedStateFromError(i){return{error:i}}static getDerivedStateFromProps(i,s){return s.location!==i.location||s.revalidation!=="idle"&&i.revalidation==="idle"?{error:i.error,location:i.location,revalidation:i.revalidation}:{error:i.error!==void 0?i.error:s.error,location:s.location,revalidation:i.revalidation||s.revalidation}}componentDidCatch(i,s){this.props.onError?this.props.onError(i,s):console.error("React Router caught the following error during render",i)}render(){let i=this.state.error;if(this.context&&typeof i=="object"&&i&&"digest"in i&&typeof i.digest=="string"){const f=Cp(i.digest);f&&(i=f)}let s=i!==void 0?S.createElement(Qt.Provider,{value:this.props.routeContext},S.createElement(tr.Provider,{value:i,children:this.props.component})):this.props.children;return this.context?S.createElement(Bp,{error:i},s):s}};nm.contextType=Ih;var Ks=new WeakMap;function Bp({children:i,error:s}){let{basename:f}=S.useContext(wt);if(typeof s=="object"&&s&&"digest"in s&&typeof s.digest=="string"){let r=zp(s.digest);if(r){let h=Ks.get(s);if(h)throw h;let m=Fh(r.location,f);if($h&&!Ks.get(s))if(m.isExternal||r.reloadDocument)window.location.href=m.absoluteURL||m.to;else{const y=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(m.to,{replace:r.replace}));throw Ks.set(s,y),y}return S.createElement("meta",{httpEquiv:"refresh",content:`0;url=${m.absoluteURL||m.to}`})}}return i}function Lp({routeContext:i,match:s,children:f}){let r=S.useContext(Qa);return r&&r.static&&r.staticContext&&(s.route.errorElement||s.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=s.route.id),S.createElement(Qt.Provider,{value:i},f)}function kp(i,s=[],f){let r=f==null?void 0:f.state;if(i==null){if(!r)return null;if(r.errors)i=r.matches;else if(s.length===0&&!r.initialized&&r.matches.length>0)i=r.matches;else return null}let h=i,m=r==null?void 0:r.errors;if(m!=null){let _=h.findIndex(g=>g.route.id&&(m==null?void 0:m[g.route.id])!==void 0);ze(_>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(m).join(",")}`),h=h.slice(0,Math.min(h.length,_+1))}let y=!1,E=-1;if(f&&r){y=r.renderFallback;for(let _=0;_<h.length;_++){let g=h[_];if((g.route.HydrateFallback||g.route.hydrateFallbackElement)&&(E=_),g.route.id){let{loaderData:R,errors:k}=r,D=g.route.loader&&!R.hasOwnProperty(g.route.id)&&(!k||k[g.route.id]===void 0);if(g.route.lazy||D){f.isStatic&&(y=!0),E>=0?h=h.slice(0,E+1):h=[h[0]];break}}}}let b=f==null?void 0:f.onError,v=r&&b?(_,g)=>{var R,k;b(_,{location:r.location,params:((k=(R=r.matches)==null?void 0:R[0])==null?void 0:k.params)??{},unstable_pattern:jp(r.matches),errorInfo:g})}:void 0;return h.reduceRight((_,g,R)=>{let k,D=!1,B=null,q=null;r&&(k=m&&g.route.id?m[g.route.id]:void 0,B=g.route.errorElement||Hp,y&&(E<0&&R===0?(um("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),D=!0,q=null):E===R&&(D=!0,q=g.route.hydrateFallbackElement||null)));let L=s.concat(h.slice(0,R+1)),X=()=>{let J;return k?J=B:D?J=q:g.route.Component?J=S.createElement(g.route.Component,null):g.route.element?J=g.route.element:J=_,S.createElement(Lp,{match:g,routeContext:{outlet:_,matches:L,isDataRoute:r!=null},children:J})};return r&&(g.route.ErrorBoundary||g.route.errorElement||R===0)?S.createElement(nm,{location:r.location,revalidation:r.revalidation,component:B,error:k,children:X(),routeContext:{outlet:null,matches:L,isDataRoute:!0},onError:v}):X()},null)}function ar(i){return`${i} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function qp(i){let s=S.useContext(Qa);return ze(s,ar(i)),s}function Yp(i){let s=S.useContext(gi);return ze(s,ar(i)),s}function Gp(i){let s=S.useContext(Qt);return ze(s,ar(i)),s}function nr(i){let s=Gp(i),f=s.matches[s.matches.length-1];return ze(f.route.id,`${i} can only be used on routes that contain a unique "id"`),f.route.id}function Xp(){return nr("useRouteId")}function Qp(){var r;let i=S.useContext(tr),s=Yp("useRouteError"),f=nr("useRouteError");return i!==void 0?i:(r=s.errors)==null?void 0:r[f]}function Vp(){let{router:i}=qp("useNavigate"),s=nr("useNavigate"),f=S.useRef(!1);return lm(()=>{f.current=!0}),S.useCallback(async(h,m={})=>{Xt(f.current,tm),f.current&&(typeof h=="number"?await i.navigate(h):await i.navigate(h,{fromRouteId:s,...m}))},[i,s])}var wh={};function um(i,s,f){!s&&!wh[i]&&(wh[i]=!0,Xt(!1,f))}S.memo(Zp);function Zp({routes:i,future:s,state:f,isStatic:r,onError:h}){return am(i,void 0,{state:f,isStatic:r,onError:h})}function Yt(i){ze(!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 Kp({basename:i="/",children:s=null,location:f,navigationType:r="POP",navigator:h,static:m=!1,unstable_useTransitions:y}){ze(!Kn(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let E=i.replace(/^\/*/,"/"),b=S.useMemo(()=>({basename:E,navigator:h,static:m,unstable_useTransitions:y,future:{}}),[E,h,m,y]);typeof f=="string"&&(f=Xa(f));let{pathname:v="/",search:_="",hash:g="",state:R=null,key:k="default",unstable_mask:D}=f,B=S.useMemo(()=>{let q=ol(v,E);return q==null?null:{location:{pathname:q,search:_,hash:g,state:R,key:k,unstable_mask:D},navigationType:r}},[E,v,_,g,R,k,r,D]);return Xt(B!=null,`<Router basename="${E}"> is not able to match the URL "${v}${_}${g}" because it does not start with the basename, so the <Router> won't render anything.`),B==null?null:S.createElement(wt.Provider,{value:b},S.createElement(Zn.Provider,{children:s,value:B}))}function Mh({children:i,location:s}){return Dp(Ws(i),s)}function Ws(i,s=[]){let f=[];return S.Children.forEach(i,(r,h)=>{if(!S.isValidElement(r))return;let m=[...s,h];if(r.type===S.Fragment){f.push.apply(f,Ws(r.props.children,m));return}ze(r.type===Yt,`[${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>`),ze(!r.props.index||!r.props.children,"An index route cannot have child routes.");let y={id:r.props.id||m.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&&(y.children=Ws(r.props.children,m)),f.push(y)}),f}var mi="get",vi="application/x-www-form-urlencoded";function bi(i){return typeof HTMLElement<"u"&&i instanceof HTMLElement}function Jp(i){return bi(i)&&i.tagName.toLowerCase()==="button"}function $p(i){return bi(i)&&i.tagName.toLowerCase()==="form"}function Fp(i){return bi(i)&&i.tagName.toLowerCase()==="input"}function Wp(i){return!!(i.metaKey||i.altKey||i.ctrlKey||i.shiftKey)}function Ip(i,s){return i.button===0&&(!s||s==="_self")&&!Wp(i)}var hi=null;function Pp(){if(hi===null)try{new FormData(document.createElement("form"),0),hi=!1}catch{hi=!0}return hi}var eg=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Js(i){return i!=null&&!eg.has(i)?(Xt(!1,`"${i}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${vi}"`),null):i}function tg(i,s){let f,r,h,m,y;if($p(i)){let E=i.getAttribute("action");r=E?ol(E,s):null,f=i.getAttribute("method")||mi,h=Js(i.getAttribute("enctype"))||vi,m=new FormData(i)}else if(Jp(i)||Fp(i)&&(i.type==="submit"||i.type==="image")){let E=i.form;if(E==null)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let b=i.getAttribute("formaction")||E.getAttribute("action");if(r=b?ol(b,s):null,f=i.getAttribute("formmethod")||E.getAttribute("method")||mi,h=Js(i.getAttribute("formenctype"))||Js(E.getAttribute("enctype"))||vi,m=new FormData(E,i),!Pp()){let{name:v,type:_,value:g}=i;if(_==="image"){let R=v?`${v}.`:"";m.append(`${R}x`,"0"),m.append(`${R}y`,"0")}else v&&m.append(v,g)}}else{if(bi(i))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');f=mi,r=null,h=vi,y=i}return m&&h==="text/plain"&&(y=m,m=void 0),{action:r,method:f.toLowerCase(),encType:h,formData:m,body:y}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function ur(i,s){if(i===!1||i===null||typeof i>"u")throw new Error(s)}function im(i,s,f,r){let h=typeof i=="string"?new URL(i,typeof window>"u"?"server://singlefetch/":window.location.origin):i;return f?h.pathname.endsWith("/")?h.pathname=`${h.pathname}_.${r}`:h.pathname=`${h.pathname}.${r}`:h.pathname==="/"?h.pathname=`_root.${r}`:s&&ol(h.pathname,s)==="/"?h.pathname=`${pi(s)}/_root.${r}`:h.pathname=`${pi(h.pathname)}.${r}`,h}async function lg(i,s){if(i.id in s)return s[i.id];try{let f=await import(i.module);return s[i.id]=f,f}catch(f){return console.error(`Error loading route module \`${i.module}\`, reloading page...`),console.error(f),window.__reactRouterContext&&window.__reactRouterContext.isSpaMode,window.location.reload(),new Promise(()=>{})}}function ag(i){return i==null?!1:i.href==null?i.rel==="preload"&&typeof i.imageSrcSet=="string"&&typeof i.imageSizes=="string":typeof i.rel=="string"&&typeof i.href=="string"}async function ng(i,s,f){let r=await Promise.all(i.map(async h=>{let m=s.routes[h.route.id];if(m){let y=await lg(m,f);return y.links?y.links():[]}return[]}));return sg(r.flat(1).filter(ag).filter(h=>h.rel==="stylesheet"||h.rel==="preload").map(h=>h.rel==="stylesheet"?{...h,rel:"prefetch",as:"style"}:{...h,rel:"prefetch"}))}function Oh(i,s,f,r,h,m){let y=(b,v)=>f[v]?b.route.id!==f[v].route.id:!0,E=(b,v)=>{var _;return f[v].pathname!==b.pathname||((_=f[v].route.path)==null?void 0:_.endsWith("*"))&&f[v].params["*"]!==b.params["*"]};return m==="assets"?s.filter((b,v)=>y(b,v)||E(b,v)):m==="data"?s.filter((b,v)=>{var g;let _=r.routes[b.route.id];if(!_||!_.hasLoader)return!1;if(y(b,v)||E(b,v))return!0;if(b.route.shouldRevalidate){let R=b.route.shouldRevalidate({currentUrl:new URL(h.pathname+h.search+h.hash,window.origin),currentParams:((g=f[0])==null?void 0:g.params)||{},nextUrl:new URL(i,window.origin),nextParams:b.params,defaultShouldRevalidate:!0});if(typeof R=="boolean")return R}return!0}):[]}function ug(i,s,{includeHydrateFallback:f}={}){return ig(i.map(r=>{let h=s.routes[r.route.id];if(!h)return[];let m=[h.module];return h.clientActionModule&&(m=m.concat(h.clientActionModule)),h.clientLoaderModule&&(m=m.concat(h.clientLoaderModule)),f&&h.hydrateFallbackModule&&(m=m.concat(h.hydrateFallbackModule)),h.imports&&(m=m.concat(h.imports)),m}).flat(1))}function ig(i){return[...new Set(i)]}function cg(i){let s={},f=Object.keys(i).sort();for(let r of f)s[r]=i[r];return s}function sg(i,s){let f=new Set;return new Set(s),i.reduce((r,h)=>{let m=JSON.stringify(cg(h));return f.has(m)||(f.add(m),r.push({key:m,link:h})),r},[])}function ir(){let i=S.useContext(Qa);return ur(i,"You must render this element inside a <DataRouterContext.Provider> element"),i}function rg(){let i=S.useContext(gi);return ur(i,"You must render this element inside a <DataRouterStateContext.Provider> element"),i}var cr=S.createContext(void 0);cr.displayName="FrameworkContext";function sr(){let i=S.useContext(cr);return ur(i,"You must render this element inside a <HydratedRouter> element"),i}function og(i,s){let f=S.useContext(cr),[r,h]=S.useState(!1),[m,y]=S.useState(!1),{onFocus:E,onBlur:b,onMouseEnter:v,onMouseLeave:_,onTouchStart:g}=s,R=S.useRef(null);S.useEffect(()=>{if(i==="render"&&y(!0),i==="viewport"){let B=L=>{L.forEach(X=>{y(X.isIntersecting)})},q=new IntersectionObserver(B,{threshold:.5});return R.current&&q.observe(R.current),()=>{q.disconnect()}}},[i]),S.useEffect(()=>{if(r){let B=setTimeout(()=>{y(!0)},100);return()=>{clearTimeout(B)}}},[r]);let k=()=>{h(!0)},D=()=>{h(!1),y(!1)};return f?i!=="intent"?[m,R,{}]:[m,R,{onFocus:Yn(E,k),onBlur:Yn(b,D),onMouseEnter:Yn(v,k),onMouseLeave:Yn(_,D),onTouchStart:Yn(g,k)}]:[!1,R,{}]}function Yn(i,s){return f=>{i&&i(f),f.defaultPrevented||s(f)}}function fg({page:i,...s}){let f=Tp(),{router:r}=ir(),h=S.useMemo(()=>Qh(r.routes,i,r.basename),[r.routes,i,r.basename]);return h?f?S.createElement(hg,{page:i,matches:h,...s}):S.createElement(mg,{page:i,matches:h,...s}):null}function dg(i){let{manifest:s,routeModules:f}=sr(),[r,h]=S.useState([]);return S.useEffect(()=>{let m=!1;return ng(i,s,f).then(y=>{m||h(y)}),()=>{m=!0}},[i,s,f]),r}function hg({page:i,matches:s,...f}){let r=fl(),{future:h}=sr(),{basename:m}=ir(),y=S.useMemo(()=>{if(i===r.pathname+r.search+r.hash)return[];let E=im(i,m,h.unstable_trailingSlashAwareDataRequests,"rsc"),b=!1,v=[];for(let _ of s)typeof _.route.shouldRevalidate=="function"?b=!0:v.push(_.route.id);return b&&v.length>0&&E.searchParams.set("_routes",v.join(",")),[E.pathname+E.search]},[m,h.unstable_trailingSlashAwareDataRequests,i,r,s]);return S.createElement(S.Fragment,null,y.map(E=>S.createElement("link",{key:E,rel:"prefetch",as:"fetch",href:E,...f})))}function mg({page:i,matches:s,...f}){let r=fl(),{future:h,manifest:m,routeModules:y}=sr(),{basename:E}=ir(),{loaderData:b,matches:v}=rg(),_=S.useMemo(()=>Oh(i,s,v,m,r,"data"),[i,s,v,m,r]),g=S.useMemo(()=>Oh(i,s,v,m,r,"assets"),[i,s,v,m,r]),R=S.useMemo(()=>{if(i===r.pathname+r.search+r.hash)return[];let B=new Set,q=!1;if(s.forEach(X=>{var V;let J=m.routes[X.route.id];!J||!J.hasLoader||(!_.some(Y=>Y.route.id===X.route.id)&&X.route.id in b&&((V=y[X.route.id])!=null&&V.shouldRevalidate)||J.hasClientLoader?q=!0:B.add(X.route.id))}),B.size===0)return[];let L=im(i,E,h.unstable_trailingSlashAwareDataRequests,"data");return q&&B.size>0&&L.searchParams.set("_routes",s.filter(X=>B.has(X.route.id)).map(X=>X.route.id).join(",")),[L.pathname+L.search]},[E,h.unstable_trailingSlashAwareDataRequests,b,r,m,_,s,i,y]),k=S.useMemo(()=>ug(g,m),[g,m]),D=dg(g);return S.createElement(S.Fragment,null,R.map(B=>S.createElement("link",{key:B,rel:"prefetch",as:"fetch",href:B,...f})),k.map(B=>S.createElement("link",{key:B,rel:"modulepreload",href:B,...f})),D.map(({key:B,link:q})=>S.createElement("link",{key:B,nonce:f.nonce,...q,crossOrigin:q.crossOrigin??f.crossOrigin})))}function vg(...i){return s=>{i.forEach(f=>{typeof f=="function"?f(s):f!=null&&(f.current=s)})}}var yg=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";try{yg&&(window.__reactRouterVersion="7.14.2")}catch{}function pg({basename:i,children:s,unstable_useTransitions:f,window:r}){let h=S.useRef();h.current==null&&(h.current=Wy({window:r,v5Compat:!0}));let m=h.current,[y,E]=S.useState({action:m.action,location:m.location}),b=S.useCallback(v=>{f===!1?E(v):S.startTransition(()=>E(v))},[f]);return S.useLayoutEffect(()=>m.listen(b),[m,b]),S.createElement(Kp,{basename:i,children:s,location:y.location,navigationType:y.action,navigator:m,unstable_useTransitions:f})}var cm=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Je=S.forwardRef(function({onClick:s,discover:f="render",prefetch:r="none",relative:h,reloadDocument:m,replace:y,unstable_mask:E,state:b,target:v,to:_,preventScrollReset:g,viewTransition:R,unstable_defaultShouldRevalidate:k,...D},B){let{basename:q,navigator:L,unstable_useTransitions:X}=S.useContext(wt),J=typeof _=="string"&&cm.test(_),V=Fh(_,q);_=V.to;let Y=wp(_,{relative:h}),K=fl(),G=null;if(E){let Ue=er(E,[],K.unstable_mask?K.unstable_mask.pathname:"/",!0);q!=="/"&&(Ue.pathname=Ue.pathname==="/"?q:Ut([q,Ue.pathname])),G=L.createHref(Ue)}let[te,ye,tt]=og(r,D),We=xg(_,{replace:y,unstable_mask:E,state:b,target:v,preventScrollReset:g,relative:h,viewTransition:R,unstable_defaultShouldRevalidate:k,unstable_useTransitions:X});function $e(Ue){s&&s(Ue),Ue.defaultPrevented||We(Ue)}let Ht=!(V.isExternal||m),St=S.createElement("a",{...D,...tt,href:(Ht?G:void 0)||V.absoluteURL||Y,onClick:Ht?$e:s,ref:vg(B,ye),target:v,"data-discover":!J&&f==="render"?"true":void 0});return te&&!J?S.createElement(S.Fragment,null,St,S.createElement(fg,{page:Y})):St});Je.displayName="Link";var gg=S.forwardRef(function({"aria-current":s="page",caseSensitive:f=!1,className:r="",end:h=!1,style:m,to:y,viewTransition:E,children:b,...v},_){let g=Jn(y,{relative:v.relative}),R=fl(),k=S.useContext(gi),{navigator:D,basename:B}=S.useContext(wt),q=k!=null&&Ag(g)&&E===!0,L=D.encodeLocation?D.encodeLocation(g).pathname:g.pathname,X=R.pathname,J=k&&k.navigation&&k.navigation.location?k.navigation.location.pathname:null;f||(X=X.toLowerCase(),J=J?J.toLowerCase():null,L=L.toLowerCase()),J&&B&&(J=ol(J,B)||J);const V=L!=="/"&&L.endsWith("/")?L.length-1:L.length;let Y=X===L||!h&&X.startsWith(L)&&X.charAt(V)==="/",K=J!=null&&(J===L||!h&&J.startsWith(L)&&J.charAt(L.length)==="/"),G={isActive:Y,isPending:K,isTransitioning:q},te=Y?s:void 0,ye;typeof r=="function"?ye=r(G):ye=[r,Y?"active":null,K?"pending":null,q?"transitioning":null].filter(Boolean).join(" ");let tt=typeof m=="function"?m(G):m;return S.createElement(Je,{...v,"aria-current":te,className:ye,ref:_,style:tt,to:y,viewTransition:E},typeof b=="function"?b(G):b)});gg.displayName="NavLink";var bg=S.forwardRef(({discover:i="render",fetcherKey:s,navigate:f,reloadDocument:r,replace:h,state:m,method:y=mi,action:E,onSubmit:b,relative:v,preventScrollReset:_,viewTransition:g,unstable_defaultShouldRevalidate:R,...k},D)=>{let{unstable_useTransitions:B}=S.useContext(wt),q=Tg(),L=_g(E,{relative:v}),X=y.toLowerCase()==="get"?"get":"post",J=typeof E=="string"&&cm.test(E),V=Y=>{if(b&&b(Y),Y.defaultPrevented)return;Y.preventDefault();let K=Y.nativeEvent.submitter,G=(K==null?void 0:K.getAttribute("formmethod"))||y,te=()=>q(K||Y.currentTarget,{fetcherKey:s,method:G,navigate:f,replace:h,state:m,relative:v,preventScrollReset:_,viewTransition:g,unstable_defaultShouldRevalidate:R});B&&f!==!1?S.startTransition(()=>te()):te()};return S.createElement("form",{ref:D,method:X,action:L,onSubmit:r?b:V,...k,"data-discover":!J&&i==="render"?"true":void 0})});bg.displayName="Form";function Sg(i){return`${i} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function sm(i){let s=S.useContext(Qa);return ze(s,Sg(i)),s}function xg(i,{target:s,replace:f,unstable_mask:r,state:h,preventScrollReset:m,relative:y,viewTransition:E,unstable_defaultShouldRevalidate:b,unstable_useTransitions:v}={}){let _=Mp(),g=fl(),R=Jn(i,{relative:y});return S.useCallback(k=>{if(Ip(k,s)){k.preventDefault();let D=f!==void 0?f:Qn(g)===Qn(R),B=()=>_(i,{replace:D,unstable_mask:r,state:h,preventScrollReset:m,relative:y,viewTransition:E,unstable_defaultShouldRevalidate:b});v?S.startTransition(()=>B()):B()}},[g,_,R,f,r,h,s,i,m,y,E,b,v])}var jg=0,Eg=()=>`__${String(++jg)}__`;function Tg(){let{router:i}=sm("useSubmit"),{basename:s}=S.useContext(wt),f=Xp(),r=i.fetch,h=i.navigate;return S.useCallback(async(m,y={})=>{let{action:E,method:b,encType:v,formData:_,body:g}=tg(m,s);if(y.navigate===!1){let R=y.fetcherKey||Eg();await r(R,f,y.action||E,{unstable_defaultShouldRevalidate:y.unstable_defaultShouldRevalidate,preventScrollReset:y.preventScrollReset,formData:_,body:g,formMethod:y.method||b,formEncType:y.encType||v,flushSync:y.flushSync})}else await h(y.action||E,{unstable_defaultShouldRevalidate:y.unstable_defaultShouldRevalidate,preventScrollReset:y.preventScrollReset,formData:_,body:g,formMethod:y.method||b,formEncType:y.encType||v,replace:y.replace,state:y.state,fromRouteId:f,flushSync:y.flushSync,viewTransition:y.viewTransition})},[r,h,s,f])}function _g(i,{relative:s}={}){let{basename:f}=S.useContext(wt),r=S.useContext(Qt);ze(r,"useFormAction must be used inside a RouteContext");let[h]=r.matches.slice(-1),m={...Jn(i||".",{relative:s})},y=fl();if(i==null){m.search=y.search;let E=new URLSearchParams(m.search),b=E.getAll("index");if(b.some(_=>_==="")){E.delete("index"),b.filter(g=>g).forEach(g=>E.append("index",g));let _=E.toString();m.search=_?`?${_}`:""}}return(!i||i===".")&&h.route.index&&(m.search=m.search?m.search.replace(/^\?/,"?index&"):"?index"),f!=="/"&&(m.pathname=m.pathname==="/"?f:Ut([f,m.pathname])),Qn(m)}function Ag(i,{relative:s}={}){let f=S.useContext(Ph);ze(f!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:r}=sm("useViewTransitionState"),h=Jn(i,{relative:s});if(!f.isTransitioning)return!1;let m=ol(f.currentLocation.pathname,r)||f.currentLocation.pathname,y=ol(f.nextLocation.pathname,r)||f.nextLocation.pathname;return yi(h.pathname,y)!=null||yi(h.pathname,m)!=null}const rm=/^\/vault\/([^/]+)\/admin(?=\/|$)/;function om(){if(typeof window>"u")return null;const i=window.location.pathname.match(rm);if(!i)return null;try{return decodeURIComponent(i[1])}catch{return null}}function Ng(){if(typeof window>"u")return"";const i=window.location.pathname,s=i.match(rm);return s?`/vault/${s[1]}/admin`:i==="/admin"||i.startsWith("/admin/")?"/admin":""}let Bl=null,Gt=null,aa=null,rl=null,Dh=!1;const Rg=.8,zg=1e3,Cg=3e4;function wg(){if(typeof window>"u")return;const i=window.location.hash;if(!i||i.length<2)return;const s=new URLSearchParams(i.slice(1)),f=s.get("token");if(!f)return;Bl=f,Gt=null,s.delete("token");const r=s.toString(),h=r.length>0?`#${r}`:"",m=`${window.location.pathname}${window.location.search}${h}`;window.history.replaceState(null,"",m)}function rr(){return Bl}function Mg(){Bl=null,Gt=null,rl=null,Si()}async function Vn(i){if(typeof window>"u")return{kind:"network-error",message:"no window"};let s;try{s=await fetch(`/admin/vault-admin-token/${encodeURIComponent(i)}`,{method:"GET",headers:{accept:"application/json"},credentials:"same-origin"})}catch(r){return{kind:"network-error",message:r instanceof Error?r.message:String(r)}}if(s.status===401||s.status===403||s.status===404)return{kind:"auth-required",status:s.status};if(!s.ok)return{kind:"network-error",message:`hub returned ${s.status}`};let f;try{f=await s.json()}catch(r){return{kind:"network-error",message:r instanceof Error?r.message:"could not parse mint response"}}return typeof f.token!="string"||f.token.length===0?{kind:"network-error",message:"mint response missing token"}:(Bl=f.token,Gt=f.expires_at?Og(f.expires_at):null,rl=i,fm(),Hg(),{kind:"ok",token:f.token})}function Og(i){const s=Date.parse(i);return Number.isNaN(s)?null:s}async function Is(i){if(Bl){if(Gt===null||Gt>Date.now())return{kind:"ok",token:Bl};Bl=null,Gt=null,Si()}return Vn(i)}async function Dg(i){typeof window>"u"||Bl||await Vn(i).catch(()=>{})}function fm(){if(Si(),Gt===null||rl===null||typeof document<"u"&&document.visibilityState==="hidden")return;const i=Date.now(),s=Gt-i;if(s<=0)return;const f=Math.max(Math.floor(s*Rg),zg);aa=setTimeout(()=>{Ug()},f)}function Si(){aa!==null&&(clearTimeout(aa),aa=null)}async function Ug(){if(aa=null,rl===null)return;const i=await Vn(rl);i.kind!=="ok"&&(typeof console<"u"&&console.warn("[vault-admin-spa] proactive token refresh failed; will retry once",i),aa=setTimeout(()=>{aa=null,rl!==null&&Vn(rl).catch(()=>{})},Cg))}function Hg(){Dh||typeof document>"u"||(Dh=!0,document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden"){Si();return}if(rl!==null){if(Gt!==null&&Gt<=Date.now()){Vn(rl).catch(()=>{});return}fm()}}))}class _e extends Error{constructor(s,f){super(f),this.status=s,this.name="HttpError"}}async function et(i,s,f={}){let r=rr();if(!r){const v=await Is(i);if(v.kind!=="ok")throw new _e(401,"no admin token — sign in to the hub to refresh");r=v.token}const{headers:h,...m}=f,y=v=>({accept:"application/json",...h??{},authorization:`Bearer ${v}`}),E=await fetch(s,{...m,headers:y(r)});if(E.status!==401)return E;Mg();const b=await Is(i);return b.kind!=="ok"?E:fetch(s,{...m,headers:y(b.token)})}async function Bg(){const i=await fetch("/vaults/list",{headers:{accept:"application/json"}});if(i.status===404)return[];if(!i.ok)throw new _e(i.status,`vaults/list fetch failed: ${i.status}`);return(await i.json()).vaults??[]}async function Lg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function kg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function qg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function Yg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/run-now`,{method:"POST"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Gg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/push-now`,{method:"POST"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function dm(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Xg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth`,{method:"DELETE"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Qg(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/device-code`,{method:"POST"});if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Vg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/poll`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({polling_id:s})});if(!f.ok&&f.status!==404)throw new _e(f.status,await rt(f));return await f.json()}async function Zg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/pat`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function hm(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/repos`);if(!s.ok)throw new _e(s.status,await rt(s));return await s.json()}async function Kg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/create-repo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function Jg(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/auth/github/select-repo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function $g(i,s){const f=await et(i,`/vault/${encodeURIComponent(i)}/.parachute/mirror/import`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)});if(!f.ok)throw new _e(f.status,await rt(f));return await f.json()}async function rt(i){try{const s=await i.text(),f=JSON.parse(s);if(f.error_description)return f.error_description;if(f.message)return f.message;if(f.error)return f.error;if(s)return s}catch{}return`${i.status} ${i.statusText}`}function mm(i){const s=i.split(".");if(s.length!==3)return null;try{const f=s[1].replace(/-/g,"+").replace(/_/g,"/"),r=f.length%4===0?"":"=".repeat(4-f.length%4),h=atob(f+r),m=JSON.parse(h);return m===null||typeof m!="object"?null:m}catch{return null}}function Fg(i){if(!i)return[];const s=mm(i);if(!s)return[];const f=s.scope;if(typeof f=="string"&&f.length>0)return f.split(/\s+/).filter(h=>h.length>0);const r=s.scopes;return Array.isArray(r)?r.filter(h=>typeof h=="string"&&h.length>0):[]}function vm(i){return Fg(rr()).includes(`vault:${i}:admin`)}function ym(){const i=rr();if(!i)return null;const s=mm(i);if(!s)return null;const f=s.iss;return typeof f!="string"||f.length===0?null:f.replace(/\/$/,"")}const Uh=5e3;function or({vaultName:i,status:s,onRecovered:f}){const r=s===403;if(S.useEffect(()=>{if(r)return;let E=!1,b=null;const v=async()=>{if(E||typeof document<"u"&&document.visibilityState!=="visible")return;const g=await Is(i);if(!E){if(g.kind==="ok"){f();return}b=setTimeout(()=>void v(),Uh)}},_=()=>{typeof document>"u"||document.visibilityState==="visible"&&(b!==null&&(clearTimeout(b),b=null),v())};return b=setTimeout(()=>void v(),Uh),typeof document<"u"&&document.addEventListener("visibilitychange",_),()=>{E=!0,b!==null&&clearTimeout(b),typeof document<"u"&&document.removeEventListener("visibilitychange",_)}},[i,f,r]),r)return c.jsxs("div",{className:"warn-banner",role:"status",children:[c.jsxs("p",{style:{margin:"0 0 0.5rem"},children:["You're signed in, but vault management is restricted to the hub admin."," ",c.jsx("a",{href:"/account/",children:"Go to your account →"})]}),c.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=Wg(),m=`/login?next=${encodeURIComponent(h)}`,y=s===404?"This hub doesn't host a vault by that name.":"You're not signed in to the hub.";return c.jsxs("div",{className:"warn-banner",role:"status",children:[c.jsxs("p",{style:{margin:"0 0 0.5rem"},children:[y," ",c.jsx("a",{href:m,children:"Sign in to the hub →"})]}),c.jsx("p",{className:"dim",style:{margin:0,fontSize:"0.85rem"},children:"After signing in, this page will refresh automatically."})]})}function Wg(){return typeof window>"u"?"/":`${window.location.pathname}${window.location.search}${window.location.hash}`}function Hh({vaultName:i}={}){const s=lr(),f=i??s.name,r=i!==void 0,h=r?"/tokens":`/vault/${encodeURIComponent(f??"")}/tokens`,m=r?"/mirror":`/vault/${encodeURIComponent(f??"")}/mirror`,[y,E]=S.useState({kind:"loading"}),[b,v]=S.useState(0),_=S.useCallback(()=>v(k=>k+1),[]);if(S.useEffect(()=>{let k=!1;if(!f){E({kind:"missing"});return}return E({kind:"loading"}),Lg(f).then(D=>{k||E({kind:"ok",vault:D})}).catch(D=>{if(k)return;if(D instanceof _e){if(D.status===401||D.status===403){E({kind:"auth-required",status:D.status});return}if(D.status===404){E({kind:"missing"});return}E({kind:"error",message:`${D.status}: ${D.message}`});return}const B=D instanceof Error?D.message:String(D);E({kind:"error",message:B})}),()=>{k=!0}},[f,b]),y.kind==="loading")return c.jsxs("div",{children:[c.jsx("h2",{children:"Vault"}),c.jsx("p",{className:"muted",children:"Loading…"})]});if(y.kind==="auth-required")return c.jsxs("div",{children:[c.jsxs("h2",{children:["Vault ",c.jsx("code",{children:f})]}),c.jsx(or,{vaultName:f??"",status:y.status,onRecovered:_}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});if(y.kind==="missing")return c.jsxs("div",{children:[c.jsx("h2",{children:"Vault not found"}),c.jsxs("p",{className:"muted",children:["No vault named ",c.jsx("code",{children:f})," is registered on this server."]}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});if(y.kind==="error")return c.jsxs("div",{children:[c.jsxs("h2",{children:["Vault ",c.jsx("code",{children:f})]}),c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:y.message})}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});const{vault:g}=y,R=`/vault/${g.name}`;return c.jsxs("div",{children:[c.jsxs("div",{className:"list-header",children:[c.jsxs("h2",{children:["Vault ",c.jsx("code",{children:g.name})]}),r?null:c.jsx(Je,{to:"/",className:"muted",children:"← All vaults"})]}),c.jsxs("div",{className:"kv section",children:[c.jsx("div",{children:"Name"}),c.jsx("div",{children:c.jsx("code",{children:g.name})}),g.description?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Description"}),c.jsx("div",{children:g.description})]}):null,c.jsx("div",{children:"Mount"}),c.jsx("div",{children:c.jsx("code",{children:R})}),g.createdAt?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Created"}),c.jsx("div",{children:c.jsx("code",{children:g.createdAt})})]}):null]}),c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Stats"}),c.jsxs("div",{className:"stats",children:[c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Notes"}),c.jsx("div",{className:"value",children:g.stats.totalNotes})]}),c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Tags"}),c.jsx("div",{className:"value",children:g.stats.tagCount})]}),c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Attachments"}),c.jsx("div",{className:"value",children:g.stats.attachmentCount})]}),c.jsxs("div",{className:"stat",children:[c.jsx("div",{className:"label",children:"Links"}),c.jsx("div",{className:"value",children:g.stats.linkCount})]})]})]}),c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Manage"}),c.jsxs("ul",{className:"manage-list",children:[c.jsxs("li",{children:[c.jsx(Je,{to:h,children:"Tokens →"}),c.jsx("span",{className:"dim",children:" mint, list, and revoke hub access tokens (JWTs)"})]}),c.jsxs("li",{children:[c.jsx(Je,{to:m,children:"Git backup →"}),c.jsx("span",{className:"dim",children:" mirror this vault to a git repository on a schedule, or on demand"})]}),c.jsx(Ig,{vaultName:g.name})]})]})]})}function Ig({vaultName:i}){const s=ym();if(!s)return c.jsxs("li",{children:[c.jsx("span",{children:"Permissions →"}),c.jsxs("span",{className:"dim",children:[" ","grants are managed on hub (the OAuth issuer); link will be live when hub ships its permissions UI."]})]});const f=`${s}/hub/permissions?vault=${encodeURIComponent(i)}`;return c.jsxs("li",{children:[c.jsx("a",{href:f,children:"Permissions →"}),c.jsxs("span",{className:"dim",children:[" ","grants are managed on hub (the OAuth issuer); link will be live when hub ships its permissions UI."]})]})}const Pg=[{value:"events",label:"On change (default)"},{value:"manual",label:"Manual only"}],e0=[{id:"history",label:"History",subtext:"Local audit trail. Hidden under vault data. Events-driven.",apply:i=>({...i,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:i=>({...i,enabled:!0,location:"external",sync_mode:"events",auto_commit:!0})},{id:"manual",label:"Manual Export",subtext:"Snapshot on demand. No auto-fire.",apply:i=>({...i,enabled:!0,location:"external",sync_mode:"manual",auto_commit:!0,auto_push:!1})}];function Bh({vaultName:i}={}){const s=lr(),f=i??s.name,r=i!==void 0,h=r?"/":`/vault/${encodeURIComponent(f??"")}`,[m,y]=S.useState({kind:"loading"}),[E,b]=S.useState(0);S.useEffect(()=>{let _=!1;if(f)return y({kind:"loading"}),kg(f).then(g=>{_||y({kind:"ok",snapshot:g})}).catch(g=>{if(_)return;if(g instanceof _e&&(g.status===401||g.status===403)){y({kind:"auth-required",status:g.status});return}const R=g instanceof Error?g.message:String(g);y({kind:"error",message:R})}),()=>{_=!0}},[f,E]);const v=S.useCallback(()=>b(_=>_+1),[]);return f?c.jsxs("div",{children:[c.jsxs("div",{className:"list-header",children:[c.jsxs("h2",{children:["Backup for ",c.jsx("code",{children:f})]}),c.jsx(Je,{to:h,className:"muted",children:"← Vault detail"})]}),m.kind==="loading"?c.jsx("p",{className:"muted",children:"Loading…"}):null,m.kind==="auth-required"?c.jsx(or,{vaultName:f,status:m.status,onRecovered:v}):null,m.kind==="error"?c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:m.message})}):null,m.kind==="ok"?c.jsx(t0,{vaultName:f,snapshot:m.snapshot,onRefresh:()=>b(_=>_+1),onSnapshot:_=>y({kind:"ok",snapshot:_})}):null]}):c.jsxs("div",{children:[c.jsx("h2",{children:"Mirror"}),c.jsx("p",{className:"muted",children:"Missing vault name."}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]})}function t0({vaultName:i,snapshot:s,onRefresh:f,onSnapshot:r}){const h=vm(i),[m,y]=S.useState(null),[E,b]=S.useState(null);S.useEffect(()=>{if(!h)return;let g=!1;return dm(i).then(R=>{g||y(R)}).catch(R=>{g||b(R instanceof Error?R.message:String(R))}),()=>{g=!0}},[i,h]);const[v,_]=S.useState(!1);return c.jsxs(c.Fragment,{children:[c.jsx(l0,{status:s.status,config:s.config,creds:m}),h?null:c.jsxs("div",{className:"warn-banner",children:["You're viewing this page with a read-only token. Saving config + manual run require ",c.jsxs("code",{children:["vault:",i,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin-scoped session to make changes.`]}),h?c.jsx(u0,{vaultName:i,creds:m,credsError:E,onCredsChanged:y,onCredsSaved:()=>{f()},locationIsExternal:s.config.location==="external"}):null,c.jsxs("div",{className:"section",children:[c.jsx("button",{type:"button",className:"secondary",onClick:()=>_(g=>!g),"aria-expanded":v,children:v?"Hide advanced settings":"Advanced settings"}),v?null:c.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."})]}),v?c.jsxs(c.Fragment,{children:[c.jsx(a0,{status:s.status,config:s.config,creds:m,canRun:h&&s.status.enabled,vaultName:i,onSnapshot:r}),c.jsx(n0,{vaultName:i,initial:s.config,readOnly:!h,creds:m,onSaved:g=>{r(g),f()}}),h?c.jsx(o0,{vaultName:i,creds:m}):null]}):null]})}function l0({status:i,config:s,creds:f}){var y;if(!s.enabled)return c.jsxs("div",{className:"warn-banner",role:"status",children:[c.jsx("strong",{children:"Version history is off."})," This vault isn't saving a local history of changes right now. Open ",c.jsx("strong",{children:"Advanced settings"})," ","below to turn it back on."]});const r=!!(f!=null&&f.active_method),h=s.auto_push&&r,m=(f==null?void 0:f.active_method)==="github_oauth"?(y=f.github_oauth)==null?void 0:y.user_login:void 0;return c.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"1rem"},children:[h?c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"✓ Version history + backed up off this machine."})," ",m?c.jsxs(c.Fragment,{children:["Every change is saved locally and pushed to GitHub as"," ",c.jsxs("code",{children:["@",m]}),"."]}):c.jsx(c.Fragment,{children:"Every change is saved locally and pushed to your git remote automatically."})]}):c.jsxs(c.Fragment,{children:[c.jsx("strong",{children:"✓ Version history — on."})," Your vault automatically saves a full local history of every change. Want an off-machine copy too? Use ",c.jsx("strong",{children:"Back up to GitHub"})," below."]}),i.last_error?c.jsxs("p",{className:"dim",style:{margin:"0.5rem 0 0"},children:["Heads up — the last backup pass reported an error. See"," ",c.jsx("strong",{children:"Advanced settings"})," below for details."]}):null]})}function a0({status:i,config:s,creds:f,canRun:r,vaultName:h,onSnapshot:m}){const y=s.enabled,[E,b]=S.useState(!1),[v,_]=S.useState(!1),[g,R]=S.useState(null),k=async()=>{b(!0),R(null);try{const L=await Yg(h);m(L)}catch(L){R(L instanceof Error?L.message:String(L))}finally{b(!1)}},D=async()=>{_(!0),R(null);try{const L=await Gg(h);m(L)}catch(L){R(L instanceof Error?L.message:String(L))}finally{_(!1)}},B=!!(f!=null&&f.active_method)||s.auto_push,q=!r||v||!B;return c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Status"}),c.jsxs("div",{className:"kv",children:[c.jsx("div",{children:"Enabled"}),c.jsx("div",{children:y?c.jsx("code",{children:"yes"}):c.jsx("code",{children:"no"})}),c.jsx("div",{children:"Watch loop"}),c.jsx("div",{children:i.watch_running?c.jsx("code",{children:"running"}):c.jsx("code",{children:"stopped"})}),c.jsx("div",{children:"Path"}),c.jsx("div",{children:i.mirror_path?c.jsx("code",{children:i.mirror_path}):c.jsx("span",{className:"dim",children:"—"})}),c.jsx("div",{children:"Last export"}),c.jsx("div",{children:i.last_export_at?c.jsxs(c.Fragment,{children:[c.jsx("code",{children:i.last_export_at}),i.last_export_notes_count!==null?c.jsxs("span",{className:"dim",children:[" ","· ",i.last_export_notes_count," note",i.last_export_notes_count===1?"":"s"]}):null]}):c.jsx("span",{className:"dim",children:"never"})}),c.jsx("div",{children:"Last commit"}),c.jsx("div",{children:i.last_commit_sha?c.jsx("code",{children:i.last_commit_sha.slice(0,10)}):c.jsx("span",{className:"dim",children:"—"})}),c.jsx("div",{children:"Last push"}),c.jsx("div",{children:i.last_push_at?c.jsxs(c.Fragment,{children:[c.jsx("code",{children:i.last_push_at}),i.last_push_sha?c.jsxs("span",{className:"dim",children:[" ","· ",c.jsx("code",{children:i.last_push_sha.slice(0,10)})]}):null]}):c.jsx("span",{className:"dim",children:"never"})}),i.commits_unpushed!==null&&i.commits_unpushed>0?c.jsxs(c.Fragment,{children:[c.jsx("div",{}),c.jsxs("div",{className:"dim",children:[i.commits_unpushed," commit",i.commits_unpushed===1?"":"s"," ready to push"]})]}):null]}),i.last_push_error?c.jsxs("div",{className:"error-banner",style:{marginTop:"1rem"},children:[c.jsx("strong",{children:"Last push failed:"})," ",c.jsx("code",{children:i.last_push_error})]}):null,i.last_error?c.jsxs("div",{className:"error-banner",style:{marginTop:"1rem"},children:[c.jsx("strong",{children:"Last error:"})," ",c.jsx("code",{children:i.last_error})]}):null,g?c.jsx("div",{className:"error-banner",style:{marginTop:"1rem"},children:c.jsx("code",{children:g})}):null,c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:k,disabled:!r||E,title:y?r?void 0:"Admin scope required to trigger a manual export.":"Enable the mirror first, then trigger a manual export.",children:E?"Running…":"Run export now"}),c.jsx("button",{type:"button",className:"secondary",onClick:D,disabled:q,title:y?r?B?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:v?"Pushing…":"Push now"})]})]})}function n0({vaultName:i,initial:s,readOnly:f,creds:r,onSaved:h}){const[m,y]=S.useState(s),[E,b]=S.useState(!1),[v,_]=S.useState(!1),[g,R]=S.useState(null),[k,D]=S.useState(null),[B,q]=S.useState(0);S.useEffect(()=>{y(s)},[s]);const L=V=>{const Y=V.apply(m);y(Y)},X=V=>{y(Y=>({...Y,sync_mode:V}))},J=async V=>{if(V.preventDefault(),!f){_(!0),R(null),D(null);try{const Y=await qg(i,m);h(Y),q(K=>K+1),setTimeout(()=>q(0),3e3)}catch(Y){if(Y instanceof _e){const K=Y.message;R(K);const G=K.toLowerCase();G.includes("external_path")?D("external_path"):G.includes("commit_template")?D("commit_template"):G.includes("safety_net_seconds")?D("safety_net_seconds"):G.includes("sync_mode")?D("sync_mode"):G.includes("auto_push")?D("auto_push"):G.includes("location")?D("location"):D(null)}else R(Y instanceof Error?Y.message:String(Y))}finally{_(!1)}}};return c.jsxs("form",{className:"section",onSubmit:J,children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Configuration"}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:m.enabled,disabled:f,onChange:V=>y(Y=>({...Y,enabled:V.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Enable mirror"]}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"Master switch. When off, no export / commit / push runs."})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{children:"Presets"}),c.jsxs("p",{className:"dim",style:{marginTop:0,marginBottom:"0.5rem",fontSize:"0.9em"},children:[c.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. ",c.jsx("strong",{children:"External folder mirror"})," +"," ",c.jsx("strong",{children:"Manual Export"})," are for operators who want to point at a visible folder (Obsidian, GitHub)."]}),c.jsx("div",{className:"preset-grid",children:e0.map(V=>c.jsxs("button",{type:"button",className:"preset-card",disabled:f,onClick:()=>L(V),"aria-label":`Apply ${V.label} preset`,children:[c.jsx("strong",{children:V.label}),c.jsx("span",{className:"dim",children:V.subtext})]},V.id))})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{children:"Location"}),c.jsxs("div",{children:[c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"location",value:"internal",checked:m.location==="internal",disabled:f,onChange:()=>y(V=>({...V,location:"internal"}))}),c.jsxs("span",{children:["Internal ",c.jsx("span",{className:"dim",children:"— hidden under vault data dir"})]})]}),c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"location",value:"external",checked:m.location==="external",disabled:f,onChange:()=>y(V=>({...V,location:"external"}))}),c.jsxs("span",{children:["External ",c.jsx("span",{className:"dim",children:"— operator-picked path"})]})]})]})]}),m.location==="external"?c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"external-path",children:"External path"}),c.jsx("input",{id:"external-path",type:"text",value:m.external_path??"",disabled:f,onChange:V=>y(Y=>({...Y,external_path:V.target.value.length>0?V.target.value:null})),placeholder:"/Users/you/Documents/vault-mirror","aria-invalid":k==="external_path"}),c.jsxs("div",{className:"warn-banner",style:{marginTop:"0.5rem"},role:"alert",children:["Path must exist AND be a git repo (run ",c.jsx("code",{children:"git init"})," first if needed)."]})]}):null,c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"sync-mode-select",children:"Sync mode"}),c.jsx("select",{id:"sync-mode-select",value:m.sync_mode,disabled:f,onChange:V=>X(V.target.value),children:Pg.map(V=>c.jsx("option",{value:V.value,children:V.label},V.value))}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:m.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."})]}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:m.auto_commit,disabled:f,onChange:V=>y(Y=>({...Y,auto_commit:V.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Commit after each export"]}),m.auto_commit?null:c.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."})]}),m.location==="external"||r!=null&&r.active_method?c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:m.auto_push,disabled:f,onChange:V=>y(Y=>({...Y,auto_push:V.target.checked})),style:{width:"auto",marginRight:"0.5rem"}}),"Push after each commit"]}),c.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."}),m.auto_push?r!=null&&r.active_method?c.jsxs("div",{className:"info-banner",style:{marginTop:"0.5rem"},role:"status",children:[r.active_method==="github_oauth"&&r.github_oauth?c.jsxs(c.Fragment,{children:["Will push to ",c.jsxs("code",{children:["@",r.github_oauth.user_login]})," on GitHub."]}):r.active_method==="pat"&&r.pat?c.jsxs(c.Fragment,{children:["Will push using saved credential: ",c.jsx("code",{children:r.pat.label}),"."]}):c.jsx(c.Fragment,{children:"Will push using saved credential."})," ","Failed pushes are logged but won't crash the export."]}):c.jsxs("div",{className:"warn-banner",style:{marginTop:"0.5rem"},role:"alert",children:["Auto-push needs git credentials. Either connect GitHub in the"," ",c.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,c.jsx("div",{className:"form-row",children:c.jsxs("button",{type:"button",className:"secondary",onClick:()=>b(V=>!V),children:[E?"Hide":"Show"," advanced"]})}),E?c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"commit-template",children:"Commit template"}),c.jsx("input",{id:"commit-template",type:"text",value:m.commit_template,disabled:f,onChange:V=>y(Y=>({...Y,commit_template:V.target.value})),"aria-invalid":k==="commit_template"}),c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Supports ",c.jsx("code",{children:"{{date}}"}),", ",c.jsx("code",{children:"{{notes_changed}}"}),","," ",c.jsx("code",{children:"{{plural}}"}),", ",c.jsx("code",{children:"{{first_note_title}}"}),","," ",c.jsx("code",{children:"{{vault_name}}"}),"."]})]}):null,g?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:g})}):null,B>0?c.jsx("div",{className:"mint-banner",style:{padding:"0.75rem 1rem",marginBottom:"1rem"},role:"status",children:"Saved."}):null,c.jsx("div",{className:"actions",children:c.jsx("button",{type:"submit",disabled:f||v,children:v?"Saving…":"Save"})})]})}function u0({vaultName:i,creds:s,credsError:f,onCredsChanged:r,onCredsSaved:h,locationIsExternal:m}){const[y,E]=S.useState(!1),[b,v]=S.useState(!1),[_,g]=S.useState(!1),[R,k]=S.useState(null),[D,B]=S.useState(null),q=(s==null?void 0:s.active_method)!==null&&(s==null?void 0:s.active_method)!==void 0,L=async()=>{if(confirm("Disconnect git remote credentials? Auto-push will stop working until you reconnect.")){g(!0),k(null);try{const X=await Xg(i);r(X)}catch(X){k(X instanceof Error?X.message:String(X))}finally{g(!1)}}};return c.jsxs("div",{className:"section",id:"git-remote-section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:q?"Backed up to a git remote":"Back up to GitHub"}),c.jsx("p",{className:"dim",style:{marginTop:0},children:q?c.jsxs(c.Fragment,{children:["Your vault pushes its history to an off-machine git remote. Credentials are stored on this server with ",c.jsx("code",{children:"0600"})," file permissions — never sent to GitHub or any third party."]}):c.jsxs(c.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"," ",c.jsx("code",{children:"0600"})," file permissions, never sent to a third party."]})}),!m&&!(s!=null&&s.active_method)?c.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,f?c.jsxs("div",{className:"error-banner",role:"alert",children:["Could not load credential status: ",c.jsx("code",{children:f})]}):null,q?c.jsxs("div",{className:"kv",style:{marginBottom:"0.75rem"},children:[c.jsx("div",{children:"Status"}),c.jsx("div",{children:(s==null?void 0:s.active_method)==="github_oauth"&&s.github_oauth?c.jsxs(c.Fragment,{children:["Connected to ",c.jsxs("code",{children:["@",s.github_oauth.user_login]})," on GitHub"]}):(s==null?void 0:s.active_method)==="pat"&&s.pat?c.jsxs(c.Fragment,{children:["Custom credential: ",c.jsx("code",{children:s.pat.label})]}):null}),(s==null?void 0:s.active_method)==="github_oauth"&&s.github_oauth?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Token"}),c.jsxs("div",{children:[c.jsx("code",{children:s.github_oauth.token_preview})," ",c.jsxs("span",{className:"dim",children:["· scope ",s.github_oauth.scope||"—"," · authorized"," ",s.github_oauth.authorized_at.slice(0,10)]})]})]}):null,(s==null?void 0:s.active_method)==="pat"&&s.pat?c.jsxs(c.Fragment,{children:[c.jsx("div",{children:"Remote"}),c.jsx("div",{children:c.jsx("code",{children:s.pat.remote_url})}),c.jsx("div",{children:"Token"}),c.jsx("div",{children:c.jsx("code",{children:s.pat.token_preview})})]}):null]}):c.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."}),R?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:R})}):null,D?c.jsxs("div",{className:"mint-banner",style:{marginBottom:"0.75rem"},role:"status",children:[c.jsx("strong",{children:"Credentials saved."})," ",(()=>{const X=D,J=X.initial_push.fired&&X.initial_push.pushed?X.initial_push.sha:void 0,V=X.initial_push.fired&&!X.initial_push.pushed?X.initial_push.error:void 0;return X.auto_push_was_already_enabled?J?c.jsxs(c.Fragment,{children:["Auto-push was already on; just pushed"," ",c.jsx("code",{children:J.slice(0,10)}),"."]}):V?c.jsx(c.Fragment,{children:"Auto-push was already on; the push attempt failed — see Advanced settings → Status for details."}):c.jsx(c.Fragment,{children:"Auto-push was already on; nothing to push right now."}):X.auto_push_enabled?J?c.jsxs(c.Fragment,{children:["Auto-push enabled and the first push landed"," ",c.jsx("code",{children:J.slice(0,10)}),". Your next commit will push to the remote too."]}):V?c.jsx(c.Fragment,{children:"Auto-push enabled. The initial push attempt failed — see Advanced settings → Status for the error."}):c.jsx(c.Fragment,{children:"Auto-push enabled. Your next commit will push to the remote."}):c.jsx(c.Fragment,{children:"Credentials wired. Auto-push remains off; flip it on in Advanced settings → Configuration to push commits automatically."})})()," ",c.jsx("button",{type:"button",className:"secondary",onClick:()=>B(null),style:{marginLeft:"0.5rem"},"aria-label":"Dismiss",children:"Dismiss"})]}):null,c.jsx("div",{className:"actions",children:q?c.jsx("button",{type:"button",className:"secondary",onClick:L,disabled:_,children:_?"Disconnecting…":"Disconnect"}):c.jsxs(c.Fragment,{children:[c.jsx("button",{type:"button",onClick:()=>v(!0),children:"Use Personal Access Token"}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>E(!0),children:"Connect GitHub (one-click for GitHub users)"})]})}),y?c.jsx(i0,{vaultName:i,onClose:()=>E(!1),onConnected:(X,J)=>{r(X),J&&(B(J),h(J)),E(!1)}}):null,b?c.jsx(r0,{vaultName:i,onClose:()=>v(!1),onSaved:X=>{r(X),B(X),h(X),v(!1)}}):null]})}function i0({vaultName:i,onClose:s,onConnected:f}){const[r,h]=S.useState({kind:"starting"}),[m,y]=S.useState(Date.now()),E=S.useRef(!1);S.useEffect(()=>{const v=setInterval(()=>y(Date.now()),1e3);return()=>clearInterval(v)},[]),S.useEffect(()=>{let v=!1;return E.current=!1,Qg(i).then(_=>{v||h({kind:"polling",code:_,pollIntervalMs:Math.max(_.interval,1)*1e3,startedAt:Date.now()})}).catch(_=>{v||h({kind:"error",message:_ instanceof Error?_.message:String(_)})}),()=>{v=!0,E.current=!0}},[i]),S.useEffect(()=>{if(r.kind!=="polling")return;const v=r.code;let _=!1,g=null,R=r.pollIntervalMs;const k=async()=>{if(!(_||E.current))try{const D=await Vg(i,v.polling_id);if(_)return;if(D.state==="granted"){h({kind:"granted",user:{login:D.user.login}});return}if(D.state==="denied"){h({kind:"error",message:"Authorization denied."});return}if(D.state==="expired"){h({kind:"error",message:"The device code expired. Try again."});return}D.state==="slow_down"&&(R=D.interval*1e3),g=setTimeout(k,R)}catch(D){if(_)return;h({kind:"error",message:D instanceof Error?D.message:String(D)})}};return g=setTimeout(k,R),()=>{_=!0,g&&clearTimeout(g)}},[r,i]);const b=async v=>{try{await navigator.clipboard.writeText(v)}catch{}};return c.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:c.jsxs("div",{className:"modal",children:[c.jsxs("div",{className:"list-header",children:[c.jsx("h3",{style:{margin:0},children:"Connect GitHub"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,children:"Close"})]}),r.kind==="starting"?c.jsx("p",{className:"muted",children:"Requesting device code from GitHub…"}):null,r.kind==="polling"?c.jsxs(c.Fragment,{children:[c.jsxs("p",{children:[c.jsx("strong",{children:"Step 1."})," Open"," ",c.jsx("a",{href:r.code.verification_uri,target:"_blank",rel:"noreferrer",children:r.code.verification_uri})," ","in your browser."]}),c.jsxs("p",{children:[c.jsx("strong",{children:"Step 2."})," Enter this code:"]}),c.jsxs("div",{className:"device-code-row",children:[c.jsx("code",{className:"device-code",children:r.code.user_code}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>b(r.code.user_code),children:"Copy"})]}),c.jsxs("p",{className:"dim",children:["Waiting for authorization…"," ",c0(r.code.expires_in,r.startedAt,m)]})]}):null,r.kind==="granted"?c.jsx(s0,{vaultName:i,user:r.user,onPicked:async(v,_)=>{const g=await Jg(i,{owner:v,name:_}),R=await dm(i);f(R,g)},onError:v=>h({kind:"error",message:v})}):null,r.kind==="error"?c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:r.message})}),c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:()=>h({kind:"starting"}),children:"Try again"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,children:"Close"})]})]}):null]})})}function c0(i,s,f){const r=Math.floor((f-s)/1e3),h=Math.max(0,i-r),m=Math.floor(h/60),y=h%60;return`${m}:${String(y).padStart(2,"0")} remaining`}function s0({vaultName:i,user:s,onPicked:f,onError:r}){const[h,m]=S.useState(null),[y,E]=S.useState(!1),[b,v]=S.useState(""),[_,g]=S.useState(null),[R,k]=S.useState(!1),[D,B]=S.useState(""),[q,L]=S.useState(!1);S.useEffect(()=>{let Y=!1;return hm(i).then(({repos:K,truncated:G})=>{Y||(m(K),E(!!G))}).catch(K=>{Y||r(K instanceof Error?K.message:String(K))}),()=>{Y=!0}},[i,r]);const X=(h??[]).filter(Y=>b.length===0?!0:Y.full_name.toLowerCase().includes(b.toLowerCase())),J=async(Y,K)=>{g(`${Y}/${K}`);try{await f(Y,K)}catch(G){r(G instanceof Error?G.message:String(G))}finally{g(null)}},V=async()=>{if(D.trim().length!==0){k(!0);try{const Y=await Kg(i,{name:D.trim(),description:"Parachute Vault mirror",private:!0});await f(Y.owner,Y.name)}catch(Y){r(Y instanceof Error?Y.message:String(Y))}finally{k(!1)}}};return c.jsxs(c.Fragment,{children:[c.jsxs("p",{children:["Authorized as ",c.jsxs("code",{children:["@",s.login]}),". Pick a repository to push the mirror to:"]}),c.jsx("div",{className:"form-row",children:c.jsx("input",{type:"search",placeholder:"Filter by name…",value:b,onChange:Y=>v(Y.target.value)})}),y?c.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos. Use the filter above to narrow down — or paste the clone URL directly via Personal Access Token below if your repo isn't here."}):null,h===null?c.jsx("p",{className:"muted",children:"Loading repos…"}):null,h!==null?c.jsxs("div",{className:"repo-list",children:[X.length===0&&b.length>0?c.jsxs("p",{className:"dim",children:['No repos match "',b,'".']}):null,X.length===0&&b.length===0&&h.length===0?c.jsx("p",{className:"dim",children:"You don't own any repos on this account yet."}):null,X.map(Y=>c.jsxs("button",{type:"button",className:"repo-row",onClick:()=>J(Y.owner,Y.name),disabled:_!==null,children:[c.jsxs("span",{children:[c.jsx("strong",{children:Y.name}),Y.private?c.jsx("span",{className:"dim",children:" · private"}):null]}),c.jsx("span",{className:"dim",children:Y.updated_at.slice(0,10)})]},Y.full_name))]}):null,q?c.jsxs("div",{className:"form-row",style:{marginTop:"0.75rem"},children:[c.jsx("label",{htmlFor:"new-repo-name",children:"New repo name"}),c.jsx("input",{id:"new-repo-name",type:"text",value:D,placeholder:"my-vault-backup",onChange:Y=>B(Y.target.value)}),c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:V,disabled:R||D.trim().length===0,children:R?"Creating…":"Create"}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>L(!1),disabled:R,children:"Cancel"})]})]}):c.jsx("div",{className:"actions",style:{marginTop:"0.75rem"},children:c.jsx("button",{type:"button",className:"secondary",onClick:()=>L(!0),children:"+ Create new private repo"})})]})}function r0({vaultName:i,onClose:s,onSaved:f}){const[r,h]=S.useState(""),[m,y]=S.useState(""),[E,b]=S.useState(""),[v,_]=S.useState(!1),[g,R]=S.useState(null),k=async D=>{D.preventDefault(),_(!0),R(null);try{const B=await Zg(i,{token:r.trim(),remote_url:m.trim(),label:E.trim()||void 0});f(B)}catch(B){R(B instanceof Error?B.message:String(B))}finally{_(!1)}};return c.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:c.jsxs("div",{className:"modal",children:[c.jsxs("div",{className:"list-header",children:[c.jsx("h3",{style:{margin:0},children:"Use Personal Access Token"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,disabled:v,children:"Close"})]}),c.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"," ",c.jsx("code",{children:"0600"})," file perms on this server."]}),c.jsxs("form",{onSubmit:k,children:[c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"pat-token",children:"Token"}),c.jsx("input",{id:"pat-token",type:"password",value:r,autoComplete:"off",onChange:D=>h(D.target.value),placeholder:"ghp_… or glpat-… or similar",required:!0})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"pat-url",children:"Remote URL"}),c.jsx("input",{id:"pat-url",type:"url",value:m,onChange:D=>y(D.target.value),placeholder:"https://github.com/owner/repo.git",required:!0}),c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["We'll embed your token in the URL before saving (using GitHub's"," ",c.jsx("code",{children:"x-access-token"})," convention). The URL you see on disk will carry the token; ensure the file isn't shared."]})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"pat-label",children:"Label (optional)"}),c.jsx("input",{id:"pat-label",type:"text",value:E,onChange:D=>b(D.target.value),placeholder:"GitHub PAT for backup"})]}),g?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:g})}):null,c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"submit",disabled:v,children:v?"Validating…":"Validate & save"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,disabled:v,children:"Cancel"})]})]})]})})}function o0({vaultName:i,creds:s}){const[f,r]=S.useState(""),[h,m]=S.useState("merge"),[y,E]=S.useState(!1),[b,v]=S.useState(""),[_,g]=S.useState(!0),[R,k]=S.useState({kind:"idle"}),[D,B]=S.useState(""),[q,L]=S.useState(!1),X=(s==null?void 0:s.active_method)==="github_oauth"&&s.github_oauth!==null,J=(s==null?void 0:s.active_method)!==null&&(s==null?void 0:s.active_method)!==void 0,V=h!=="replace"||D.trim()===i,Y=R.kind!=="running"&&f.trim().length>0&&V&&(!y||b.trim().length>0),K=async()=>{k({kind:"running",stage:"cloning"});let te;y?te={kind:"pat",token:b.trim()}:J?te=null:te={kind:"none"};try{const ye=window.setTimeout(()=>k(We=>We.kind==="running"?{kind:"running",stage:"importing"}:We),1500),tt=await $g(i,{remote_url:f.trim(),mode:h,credentials:te,enable_sync:_});window.clearTimeout(ye),k({kind:"success",result:tt,remoteUrl:f.trim(),mode:h})}catch(ye){const tt=ye instanceof _e?`${ye.status===409?"Already running. ":""}${ye.message}`:ye instanceof Error?ye.message:String(ye);k({kind:"error",message:tt})}},G=()=>{k({kind:"idle"}),B("")};return c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Import from a git repo"}),c.jsxs("p",{className:"dim",style:{marginTop:0},children:["Pull a vault state from a remote git repo into ",c.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 ",c.jsx("code",{children:"parachute-vault export"})," or the mirror's export flow)."]}),c.jsxs("div",{className:"warn-banner",style:{marginBottom:"1rem"},role:"note",children:[c.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."]}),R.kind==="success"?c.jsx(f0,{vaultName:i,result:R.result,remoteUrl:R.remoteUrl,mode:R.mode,onReset:G}):c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"import-remote-url",children:"Remote URL"}),c.jsx("input",{id:"import-remote-url",type:"text",value:f,placeholder:"https://github.com/aaron/my-vault.git",onChange:te=>r(te.target.value),disabled:R.kind==="running"}),X?c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0",fontSize:"0.9em"},children:["Or"," ",c.jsx("button",{type:"button",onClick:()=>L(!0),disabled:R.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,!J&&!y?c.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]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{children:"Mode"}),c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"import-mode",value:"merge",checked:h==="merge",onChange:()=>{m("merge"),B("")},disabled:R.kind==="running"}),c.jsxs("span",{children:[c.jsx("strong",{children:"Merge"})," ",c.jsxs("span",{className:"dim",children:["— upsert by id. Notes in the remote get created/updated; any notes that exist only locally ",c.jsx("strong",{children:"survive"}),"."]})]})]}),c.jsxs("label",{className:"radio-row",children:[c.jsx("input",{type:"radio",name:"import-mode",value:"replace",checked:h==="replace",onChange:()=>m("replace"),disabled:R.kind==="running"}),c.jsxs("span",{children:[c.jsx("strong",{children:"Replace"})," ",c.jsxs("span",{className:"dim",children:["— wipe this vault first, then import. The remote becomes the new source of truth. ",c.jsx("strong",{children:"Destructive."})]})]})]})]}),h==="replace"?c.jsxs("div",{className:"form-row",children:[c.jsxs("div",{className:"error-banner",role:"alert",style:{marginBottom:"0.5rem"},children:[c.jsxs("strong",{children:['Replace will delete every note in vault "',i,'" before importing.']})," To confirm, type the vault name below:"]}),c.jsx("input",{id:"import-confirm-name",type:"text",value:D,placeholder:i,onChange:te=>B(te.target.value),disabled:R.kind==="running","aria-label":"Type vault name to confirm"})]}):null,c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:y,onChange:te=>E(te.target.checked),disabled:R.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"One-time credential for this import only"]}),c.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."}),y?c.jsx("input",{id:"import-per-call-pat",type:"password",value:b,placeholder:"ghp_… or similar",onChange:te=>v(te.target.value),disabled:R.kind==="running",autoComplete:"off",style:{marginTop:"0.5rem"}}):null]}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:_,onChange:te=>g(te.target.checked),disabled:R.kind==="running",style:{width:"auto",marginRight:"0.5rem"}}),"Also sync changes back to this repo"]}),c.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."})]}),R.kind==="error"?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:R.message})}):null,c.jsx("div",{className:"actions",children:c.jsx("button",{type:"button",onClick:K,disabled:!Y,title:V?f.trim().length===0?"Provide a remote URL.":y&&b.trim().length===0?"Provide a token for one-time credential.":void 0:"Type the vault name to confirm Replace.",children:R.kind==="running"?R.stage==="cloning"?"Cloning…":"Importing…":"Start import"})})]}),q?c.jsx(d0,{vaultName:i,onClose:()=>L(!1),onPicked:te=>{r(te),L(!1)}}):null]})}function f0({vaultName:i,result:s,remoteUrl:f,mode:r,onReset:h}){return c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"mint-banner",role:"status",style:{marginBottom:"0.75rem"},children:[c.jsx("strong",{children:"Import succeeded."})," Imported ",s.notes_imported," note",s.notes_imported===1?"":"s",", ",s.tags_imported," tag schema",s.tags_imported===1?"":"s",", ",s.attachments_imported," ","attachment",s.attachments_imported===1?"":"s",r==="replace"&&s.notes_deleted!==void 0?`, wiped ${s.notes_deleted} pre-existing note${s.notes_deleted===1?"":"s"}`:"","."]}),s.warnings.length>0?c.jsxs("details",{style:{marginBottom:"0.75rem"},children:[c.jsxs("summary",{children:[s.warnings.length," warning",s.warnings.length===1?"":"s"," ","(see details)"]}),c.jsx("ul",{style:{marginTop:"0.5rem"},children:s.warnings.map((m,y)=>c.jsx("li",{children:c.jsx("code",{style:{fontSize:"0.85em"},children:m})},y))})]}):null,s.sync_enabled?c.jsxs("div",{className:"mint-banner",style:{marginBottom:"0.75rem"},role:"status",children:[c.jsx("strong",{children:"Sync enabled."})," Changes to vault ",c.jsx("code",{children:i})," ","now push back to ",c.jsx("code",{children:f})," automatically."]}):s.sync_warning?c.jsxs("div",{className:"info-banner",style:{marginBottom:"0.75rem"},role:"status",children:[c.jsxs("p",{style:{marginTop:0},children:[c.jsx("strong",{children:"Sync not enabled."})," ",s.sync_warning]}),c.jsxs("p",{className:"dim",style:{marginBottom:0,fontSize:"0.9em"},children:["You can still set up Sync from the"," ",c.jsx("button",{type:"button",onClick:()=>{var m;return(m=document.getElementById("git-remote-section"))==null?void 0:m.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,c.jsx("div",{className:"actions",children:c.jsx("button",{type:"button",className:"secondary",onClick:h,children:"Run another import"})})]})}function d0({vaultName:i,onClose:s,onPicked:f}){const[r,h]=S.useState(null),[m,y]=S.useState(!1),[E,b]=S.useState(""),[v,_]=S.useState(null);S.useEffect(()=>{let R=!1;return hm(i).then(({repos:k,truncated:D})=>{R||(h(k),y(!!D))}).catch(k=>{R||_(k instanceof Error?k.message:String(k))}),()=>{R=!0}},[i]);const g=(r??[]).filter(R=>E.length===0?!0:R.full_name.toLowerCase().includes(E.toLowerCase()));return c.jsx("div",{className:"modal-backdrop",role:"dialog","aria-modal":"true",children:c.jsxs("div",{className:"modal",children:[c.jsxs("div",{className:"list-header",children:[c.jsx("h3",{style:{margin:0},children:"Pick a repo to import from"}),c.jsx("button",{type:"button",className:"secondary",onClick:s,children:"Close"})]}),v?c.jsx("div",{className:"error-banner",role:"alert",children:c.jsx("code",{children:v})}):null,c.jsx("div",{className:"form-row",children:c.jsx("input",{type:"search",placeholder:"Filter by name…",value:E,onChange:R=>b(R.target.value)})}),m?c.jsx("p",{className:"muted",style:{fontSize:"0.85em"},children:"Showing the first 300 repos. Use the filter above to narrow down."}):null,r===null&&!v?c.jsx("p",{className:"muted",children:"Loading repos…"}):null,r!==null?c.jsxs("div",{className:"repo-list",children:[g.length===0&&E.length>0?c.jsxs("p",{className:"dim",children:['No repos match "',E,'".']}):null,g.length===0&&E.length===0&&r.length===0?c.jsx("p",{className:"dim",children:"You don't own any repos on this account."}):null,g.map(R=>c.jsxs("button",{type:"button",className:"repo-row",onClick:()=>f(R.clone_url),children:[c.jsxs("span",{children:[c.jsx("strong",{children:R.name}),R.private?c.jsx("span",{className:"dim",children:" · private"}):null]}),c.jsx("span",{className:"dim",children:R.updated_at.slice(0,10)})]},R.full_name))]}):null]})})}let Gn=null,Xn=null;function h0(i){const s=Date.parse(i);return Number.isNaN(s)?null:s}async function m0(){if(typeof window>"u")return{kind:"network-error",message:"no window"};let i;try{i=await fetch("/admin/host-admin-token",{method:"GET",headers:{accept:"application/json"},credentials:"same-origin"})}catch(f){return{kind:"network-error",message:f instanceof Error?f.message:String(f)}}if(i.status===403)return{kind:"forbidden"};if(i.status===401||i.status===404)return{kind:"auth-required",status:i.status};if(!i.ok)return{kind:"network-error",message:`hub returned ${i.status}`};let s;try{s=await i.json()}catch(f){return{kind:"network-error",message:f instanceof Error?f.message:"could not parse host-admin mint response"}}return typeof s.token!="string"||s.token.length===0?{kind:"network-error",message:"host-admin mint response missing token"}:(Gn=s.token,Xn=s.expires_at?h0(s.expires_at):null,{kind:"ok",token:s.token})}async function Lh(){if(Gn){if(Xn===null||Xn>Date.now())return{kind:"ok",token:Gn};Gn=null,Xn=null}return m0()}function v0(){Gn=null,Xn=null}class Ga extends Error{constructor(s,f,r){super(f),this.status=s,this.disposition=r,this.name="HostAdminError"}}async function fr(i,s={}){let f;const r=await Lh();if(r.kind!=="ok")throw kh(r);f=r.token;const{headers:h,...m}=s,y=v=>({accept:"application/json",...h??{},authorization:`Bearer ${v}`}),E=await fetch(i,{...m,headers:y(f)});if(E.status!==401)return E;v0();const b=await Lh();if(b.kind!=="ok")throw kh(b);return fetch(i,{...m,headers:y(b.token)})}function kh(i){return i.kind==="forbidden"?new Ga(403,"host-admin token mint forbidden — not the hub admin","forbidden"):i.kind==="auth-required"?new Ga(i.status,"no host-admin session — sign in to the hub to manage tokens","auth-required"):new Ga(0,i.message,"network-error")}function dr(){if(typeof window>"u")return;const i=ym();window.location.href=i?`${i}/account/`:"/account/"}const y0=[30,90,180,365],qh=90,p0=1440*60;function g0(i){if(!i)return null;const s=i.scoped_tags;if(!Array.isArray(s))return null;const f=s.filter(r=>typeof r=="string"&&r.length>0);return f.length>0?f:null}function b0(i){return{jti:i.jti,label:i.subject,scopes:Array.isArray(i.scopes)?i.scopes:[],scoped_tags:g0(i.permissions),expires_at:i.expires_at??null,revoked_at:i.revoked_at??null,created_at:i.created_at}}async function S0(i,s){const f={scope:`vault:${i}:${s.verb}`,expires_in:s.ttlDays*p0,subject:s.label};s.scopedTags.length>0&&(f.permissions={scoped_tags:s.scopedTags});const r=await fr("/api/auth/mint-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(f)});if(!r.ok)throw new _e(r.status,await xi(r));const h=await r.json();return{jti:h.jti,token:h.token,scope:h.scope,expires_at:h.expires_at??null}}async function x0(i){const s=`vault:${i}:`,f=[];let r=null;for(let h=0;h<1e3;h++){const m=new URLSearchParams({revoked:"all"});r&&m.set("cursor",r);const y=await fr(`/api/auth/tokens?${m.toString()}`);if(!y.ok)throw new _e(y.status,await xi(y));const E=await y.json(),b=Array.isArray(E.tokens)?E.tokens:[];if(f.push(...b),r=E.next_cursor??null,!r)break}return f.filter(h=>Array.isArray(h.scopes)&&h.scopes.some(m=>m.startsWith(s))).map(b0)}async function j0(i){const s=await fr("/api/auth/revoke-token",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jti:i})});if(!s.ok)throw new _e(s.status,await xi(s))}async function E0(i){const s=await et(i,`/vault/${encodeURIComponent(i)}/api/tags`);if(!s.ok)throw new _e(s.status,await xi(s));const f=await s.json();return Array.isArray(f)?f:[]}async function xi(i){try{const s=await i.text(),f=JSON.parse(s);if(f.error_description)return f.error_description;if(f.message)return f.message;if(f.error)return f.error;if(s)return s}catch{}return`${i.status} ${i.statusText}`}const T0=["read","write","admin"],_0={30:"30 days",90:"90 days",180:"180 days",365:"1 year (max)"};function A0(i){return i instanceof Ga?i.disposition==="forbidden"?(dr(),{kind:"auth-required",status:403}):i.disposition==="auth-required"?{kind:"auth-required",status:i.status}:{kind:"error",message:i.message}:i instanceof _e&&(i.status===401||i.status===403)?{kind:"auth-required",status:i.status}:{kind:"error",message:i instanceof Error?i.message:String(i)}}function Yh({vaultName:i}={}){const s=lr(),f=i??s.name,r=i!==void 0,h=r?"/":`/vault/${encodeURIComponent(f??"")}`,[m,y]=S.useState({kind:"loading"}),[E,b]=S.useState(null),[v,_]=S.useState(null),[g,R]=S.useState(0);S.useEffect(()=>{let B=!1;if(f)return y({kind:"loading"}),x0(f).then(q=>{B||y({kind:"ok",tokens:q})}).catch(q=>{B||y(A0(q))}),()=>{B=!0}},[f,g]);const k=S.useCallback(()=>R(B=>B+1),[]);if(S.useEffect(()=>{if(!E)return;const B=q=>{q.preventDefault(),q.returnValue=""};return window.addEventListener("beforeunload",B),()=>window.removeEventListener("beforeunload",B)},[E]),!f)return c.jsxs("div",{children:[c.jsx("h2",{children:"Tokens"}),c.jsx("p",{className:"muted",children:"Missing vault name."}),r?null:c.jsx(Je,{to:"/",children:"← Back to vaults"})]});const D=vm(f);return c.jsxs("div",{children:[c.jsxs("div",{className:"list-header",children:[c.jsxs("h2",{children:["Tokens for ",c.jsx("code",{children:f})]}),c.jsx(Je,{to:h,className:"muted",children:"← Vault detail"})]}),D?null:c.jsxs("div",{className:"warn-banner",children:["You're viewing this page with a read-only token. Mint and revoke require"," ",c.jsxs("code",{children:["vault:",f,":admin"]}),`. Re-enter from the hub directory's "Manage" link with an admin-scoped session to manage tokens.`]}),E?c.jsx(N0,{result:E,onDismiss:()=>b(null)}):null,m.kind==="ok"&&D&&!E?c.jsx(R0,{vaultName:f,onMinted:B=>{b(B),R(q=>q+1)}}):null,c.jsxs("div",{className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Existing tokens"}),m.kind==="loading"?c.jsx("p",{className:"muted",children:"Loading…"}):null,m.kind==="auth-required"?c.jsx(or,{vaultName:f,status:m.status,onRecovered:k}):null,m.kind==="error"?c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:m.message})}):null,m.kind==="ok"?c.jsx(z0,{tokens:m.tokens,allowRevoke:D,confirmingJti:v,onAskConfirm:_,onRevoked:()=>{_(null),R(B=>B+1)}}):null]})]})}function N0({result:i,onDismiss:s}){const[f,r]=S.useState(!1),h=async()=>{try{await navigator.clipboard.writeText(i.token),r(!0),setTimeout(()=>r(!1),2e3)}catch{}};return c.jsxs("div",{className:"mint-banner",children:[c.jsx("h3",{children:"New token (shown once)"}),c.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."}),c.jsxs("div",{className:"token-box",children:[c.jsx("code",{children:i.token}),c.jsx("button",{type:"button",onClick:h,className:"secondary",children:f?"Copied":"Copy"})]}),c.jsx("p",{className:"warn",children:"⚠ Don't dismiss this banner until you've saved the token."}),c.jsx("div",{className:"actions",children:c.jsx("button",{type:"button",onClick:s,children:"Done — I've saved the token"})})]})}function R0({vaultName:i,onMinted:s}){const[f,r]=S.useState(""),[h,m]=S.useState("admin"),[y,E]=S.useState(qh),[b,v]=S.useState(!1),[_,g]=S.useState(null),[R,k]=S.useState([]),[D,B]=S.useState(null),[q,L]=S.useState(new Set);S.useEffect(()=>{let K=!1;return E0(i).then(G=>{if(K)return;const te=G.map(ye=>ye.name).filter(ye=>!ye.includes("/")).sort();k(te)}).catch(G=>{K||B(G instanceof Error?G.message:String(G))}),()=>{K=!0}},[i]);const X=f.trim(),J=X.length===0,V=K=>{L(G=>{const te=new Set(G);return te.has(K)?te.delete(K):te.add(K),te})},Y=async K=>{if(K.preventDefault(),J){g("label required — give the token a recognizable name");return}v(!0),g(null);try{const G=await S0(i,{verb:h,label:X,scopedTags:[...q],ttlDays:y});s(G),r(""),m("admin"),E(qh),L(new Set)}catch(G){if(G instanceof Ga&&G.disposition==="forbidden"){dr();return}g(G instanceof Error?G.message:String(G))}finally{v(!1)}};return c.jsxs("form",{onSubmit:Y,className:"section",children:[c.jsx("h3",{style:{margin:"0 0 0.85rem",fontSize:"1rem",fontWeight:500},children:"Mint a token"}),c.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."}),_?c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:_})}):null,c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{htmlFor:"mint-label",children:["Label ",c.jsx("span",{className:"dim",children:"(required)"})]}),c.jsx("input",{id:"mint-label",type:"text",value:f,onChange:K=>r(K.target.value),placeholder:"e.g. ci, paraclaw-prod, my-laptop",maxLength:120,required:!0})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"mint-scope",children:"Scope"}),c.jsx("select",{id:"mint-scope",value:h,onChange:K=>m(K.target.value),children:T0.map(K=>c.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))}),c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Issued as ",c.jsxs("code",{children:["vault:",i,":",h]}),". Lower scopes inherit narrower powers."]})]}),c.jsxs("div",{className:"form-row",children:[c.jsx("label",{htmlFor:"mint-ttl",children:"Expires after"}),c.jsx("select",{id:"mint-ttl",value:y,onChange:K=>E(Number(K.target.value)),children:y0.map(K=>c.jsx("option",{value:K,children:_0[K]??`${K} days`},K))}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"The token stops working after this. Rotate before it lapses."})]}),c.jsxs("div",{className:"form-row",children:[c.jsxs("label",{children:["Tag scope ",c.jsx("span",{className:"dim",children:"(optional)"})]}),D?c.jsxs("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:["Couldn't load tags: ",c.jsx("code",{children:D}),". Token will be unscoped."]}):R.length===0?c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:"No root tags in this vault yet — token will see the full vault."}):c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"tag-picker",children:R.map(K=>c.jsxs("label",{className:"tag-checkbox",children:[c.jsx("input",{type:"checkbox",checked:q.has(K),onChange:()=>V(K)}),c.jsx("code",{children:K})]},K))}),c.jsx("p",{className:"dim",style:{margin:"0.35rem 0 0"},children:q.size===0?"Nothing selected — token sees the full vault (unscoped).":`Token limited to: ${[...q].join(", ")}. Sub-tags (e.g. health/food) are reachable when their root is selected.`})]})]}),c.jsx("div",{className:"actions",children:c.jsx("button",{type:"submit",disabled:b||J,children:b?"Minting…":"Mint token"})})]})}function z0({tokens:i,allowRevoke:s,confirmingJti:f,onAskConfirm:r,onRevoked:h}){return i.length===0?c.jsx("p",{className:"muted",children:"No tokens yet. Mint one above to get started."}):c.jsx("div",{className:"token-list",children:i.map(m=>c.jsx(C0,{token:m,allowRevoke:s,confirming:f===m.jti,onAskConfirm:r,onRevoked:h},m.jti))})}function C0({token:i,allowRevoke:s,confirming:f,onAskConfirm:r,onRevoked:h}){const[m,y]=S.useState(!1),[E,b]=S.useState(null),v=i.revoked_at!==null,_=async()=>{y(!0),b(null);try{await j0(i.jti),h()}catch(g){if(g instanceof Ga&&g.disposition==="forbidden"){dr();return}b(g instanceof Error?g.message:String(g)),y(!1)}};return c.jsxs("div",{className:"token-row",children:[c.jsxs("div",{className:"body",children:[c.jsxs("div",{className:"name",children:[c.jsx("strong",{children:i.label??"(unlabeled)"}),c.jsx("code",{className:"dim",children:i.jti}),v?c.jsx("code",{className:"scope-tag",title:"This token has been revoked and no longer works.",children:"revoked"}):null]}),c.jsxs("div",{className:"meta",children:[c.jsx("span",{className:"dim",children:"scopes:"})," ",i.scopes.length>0?i.scopes.map(g=>c.jsx("code",{className:"scope-tag",children:g},g)):c.jsx("span",{className:"dim",children:"(none)"})]}),i.scoped_tags&&i.scoped_tags.length>0?c.jsxs("div",{className:"meta",children:[c.jsx("span",{className:"dim",children:"tags:"})," ",i.scoped_tags.map(g=>c.jsxs("code",{className:"scope-tag tag-pill",children:["#",g]},g))]}):null,c.jsxs("div",{className:"meta dim",children:["created ",i.created_at,i.expires_at?` · expires ${i.expires_at}`:"",v&&i.revoked_at?` · revoked ${i.revoked_at}`:""]}),E?c.jsx("div",{className:"error-banner",style:{marginTop:"0.5rem"},children:c.jsx("code",{children:E})}):null]}),s&&!v?f?c.jsxs("div",{className:"actions",children:[c.jsx("button",{type:"button",onClick:_,disabled:m,children:m?"Revoking…":"Confirm revoke"}),c.jsx("button",{type:"button",className:"secondary",onClick:()=>r(null),disabled:m,children:"Cancel"})]}):c.jsx("button",{type:"button",className:"secondary",onClick:()=>r(i.jti),children:"Revoke"}):null]})}function w0(){const[i,s]=S.useState({kind:"loading"});return S.useEffect(()=>{let f=!1;return Bg().then(r=>{f||s({kind:"ok",vaults:r})}).catch(r=>{if(f)return;const h=r instanceof _e?`${r.status}: ${r.message}`:r instanceof Error?r.message:String(r);s({kind:"error",message:h})}),()=>{f=!0}},[]),i.kind==="loading"?c.jsxs("div",{children:[c.jsx("h2",{children:"Vaults"}),c.jsx("p",{className:"muted",children:"Loading…"})]}):i.kind==="error"?c.jsxs("div",{children:[c.jsx("h2",{children:"Vaults"}),c.jsx("div",{className:"error-banner",children:c.jsx("code",{children:i.message})})]}):i.vaults.length===0?c.jsxs("div",{children:[c.jsx("h2",{children:"Vaults"}),c.jsxs("div",{className:"empty",children:["No vaults yet. Run ",c.jsx("code",{children:"parachute-vault create <name>"})," on the host to create one."]})]}):c.jsxs("div",{children:[c.jsx("div",{className:"list-header",children:c.jsx("h2",{children:"Vaults"})}),i.vaults.map(f=>c.jsxs(Je,{to:`/vault/${f}`,className:"vault-row",children:[c.jsx("div",{className:"body",children:c.jsx("div",{className:"name",children:c.jsx("code",{children:f})})}),c.jsx("div",{className:"chev",children:"→"})]},f))]})}function M0(){const i=om();return c.jsxs("div",{className:"page",children:[c.jsxs("nav",{className:"nav",children:[c.jsxs(Je,{to:"/",className:"brand",children:["Parachute Vault ",c.jsx("span",{className:"sub",children:"admin"})]}),i?c.jsx(Je,{to:"/",children:c.jsx("code",{children:i})}):c.jsx(Je,{to:"/",children:"Vaults"})]}),i?c.jsxs(Mh,{children:[c.jsx(Yt,{path:"/",element:c.jsx(Hh,{vaultName:i})}),c.jsx(Yt,{path:"/tokens",element:c.jsx(Yh,{vaultName:i})}),c.jsx(Yt,{path:"/mirror",element:c.jsx(Bh,{vaultName:i})}),c.jsx(Yt,{path:"*",element:c.jsx(Gh,{})})]}):c.jsxs(Mh,{children:[c.jsx(Yt,{path:"/",element:c.jsx(w0,{})}),c.jsx(Yt,{path:"/vault/:name",element:c.jsx(Hh,{})}),c.jsx(Yt,{path:"/vault/:name/tokens",element:c.jsx(Yh,{})}),c.jsx(Yt,{path:"/vault/:name/mirror",element:c.jsx(Bh,{})}),c.jsx(Yt,{path:"*",element:c.jsx(Gh,{})})]})]})}function Gh(){return c.jsxs("div",{className:"empty",children:["404 — back to ",c.jsx(Je,{to:"/",children:"vault"}),"."]})}wg();const pm=document.getElementById("root");if(!pm)throw new Error("#root not found");function $s(){Fy.createRoot(pm).render(c.jsx(S.StrictMode,{children:c.jsx(pg,{basename:Ng(),children:c.jsx(M0,{})})}))}const Xh=om();Xh?Dg(Xh).then($s,$s):$s();
|
package/web/ui/dist/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Parachute Vault — Admin</title>
|
|
7
7
|
<meta name="description" content="Manage vaults hosted by this Parachute Vault server." />
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-DJL6Az--.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="./assets/index-DBe8Xiah.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|