laneyard 0.5.0 → 0.6.1

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.
@@ -57,6 +57,6 @@ Error generating stack: `+a.message+`
57
57
  * @license MIT
58
58
  */var nf=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,lm=/^[\\/]{2}/;function Av(e,t){return t+e.replace(/\\/g,"/")}var Gr="popstate";function Xr(e){return typeof e=="object"&&e!=null&&"pathname"in e&&"search"in e&&"hash"in e&&"state"in e&&"key"in e}function zv(e={}){function t(a,n){var r;let u=(r=n.state)==null?void 0:r.masked,{pathname:i,search:c,hash:f}=u||a.location;return ts("",{pathname:i,search:c,hash:f},n.state&&n.state.usr||null,n.state&&n.state.key||"default",u?{pathname:a.location.pathname,search:a.location.search,hash:a.location.hash}:void 0)}function l(a,n){return typeof n=="string"?n:vn(n)}return _v(t,l,null,e)}function ae(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function yt(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function Cv(){return Math.random().toString(36).substring(2,10)}function Qr(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function ts(e,t,l=null,a,n){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?Ta(t):t,state:l,key:t&&t.key||a||Cv(),mask:n}}function vn({pathname:e="/",search:t="",hash:l=""}){return t&&t!=="?"&&(e+=t.charAt(0)==="?"?t:"?"+t),l&&l!=="#"&&(e+=l.charAt(0)==="#"?l:"#"+l),e}function Ta(e){let t={};if(e){let l=e.indexOf("#");l>=0&&(t.hash=e.substring(l),e=e.substring(0,l));let a=e.indexOf("?");a>=0&&(t.search=e.substring(a),e=e.substring(0,a)),e&&(t.pathname=e)}return t}function _v(e,t,l,a={}){let{window:n=document.defaultView,v5Compat:u=!1}=a,i=n.history,c="POP",f=null,r=h();r==null&&(r=0,i.replaceState({...i.state,idx:r},""));function h(){return(i.state||{idx:null}).idx}function y(){c="POP";let E=h(),d=E==null?null:E-r;r=E,f&&f({action:c,location:x.location,delta:d})}function o(E,d){c="PUSH";let m=Xr(E)?E:ts(x.location,E,d);r=h()+1;let g=Qr(m,r),b=x.createHref(m.mask||m);try{i.pushState(g,"",b)}catch(A){if(A instanceof DOMException&&A.name==="DataCloneError")throw A;n.location.assign(b)}u&&f&&f({action:c,location:x.location,delta:1})}function v(E,d){c="REPLACE";let m=Xr(E)?E:ts(x.location,E,d);r=h();let g=Qr(m,r),b=x.createHref(m.mask||m);i.replaceState(g,"",b),u&&f&&f({action:c,location:x.location,delta:0})}function S(E){return Ov(n,E)}let x={get action(){return c},get location(){return e(n,i)},listen(E){if(f)throw new Error("A history only accepts one active listener");return n.addEventListener(Gr,y),f=E,()=>{n.removeEventListener(Gr,y),f=null}},createHref(E){return t(n,E)},createURL:S,encodeLocation(E){let d=S(E);return{pathname:d.pathname,search:d.search,hash:d.hash}},push:o,replace:v,go(E){return i.go(E)}};return x}function Ov(e,t,l=!1){let a="http://localhost";e&&(a=e.location.origin!=="null"?e.location.origin:e.location.href),ae(a,"No window.location.(origin|href) available to create URL");let n=typeof t=="string"?t:vn(t);return n=n.replace(/ $/,"%20"),!l&&lm.test(n)&&(n=a+n),new URL(n,a)}function am(e,t,l="/"){return Rv(e,t,l,!1)}function Rv(e,t,l,a,n){let u=typeof t=="string"?Ta(t):t,i=Yt(u.pathname||"/",l);if(i==null)return null;let c=Dv(e),f=null,r=sm(i);for(let h=0;f==null&&h<c.length;++h)f=Xv(c[h],r,a);return f}function Dv(e){let t=nm(e);return Mv(t),t}function nm(e,t=[],l=[],a="",n=!1){let u=(i,c,f=n,r)=>{let h={relativePath:r===void 0?i.path||"":r,caseSensitive:i.caseSensitive===!0,childrenIndex:c,route:i};if(h.relativePath.startsWith("/")){if(!h.relativePath.startsWith(a)&&f)return;ae(h.relativePath.startsWith(a),`Absolute route path "${h.relativePath}" nested under path "${a}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),h.relativePath=h.relativePath.slice(a.length)}let y=it([a,h.relativePath]),o=l.concat(h);i.children&&i.children.length>0&&(ae(i.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${y}".`),nm(i.children,t,o,y,f)),!(i.path==null&&!i.index)&&t.push({path:y,score:qv(y,i.index),routesMeta:o.map((v,S)=>{let[x,E]=cm(v.relativePath,v.caseSensitive,S===o.length-1);return{...v,matcher:x,compiledParams:E}})})};return e.forEach((i,c)=>{var f;if(i.path===""||!((f=i.path)!=null&&f.includes("?")))u(i,c);else for(let r of um(i.path))u(i,c,!0,r)}),t}function um(e){let t=e.split("/");if(t.length===0)return[];let[l,...a]=t,n=l.endsWith("?"),u=l.replace(/\?$/,"");if(a.length===0)return n?[u,""]:[u];let i=um(a.join("/")),c=[];return c.push(...i.map(f=>f===""?u:[u,f].join("/"))),n&&c.push(...i),c.map(f=>e.startsWith("/")&&f===""?"/":f)}function Mv(e){e.sort((t,l)=>t.score!==l.score?l.score-t.score:Gv(t.routesMeta.map(a=>a.childrenIndex),l.routesMeta.map(a=>a.childrenIndex)))}var Uv=/^:[\w-]+$/,Hv=3,wv=2,Bv=1,Lv=10,Yv=-2,Zr=e=>e==="*";function qv(e,t){let l=e.split("/"),a=l.length;return l.some(Zr)&&(a+=Yv),t&&(a+=wv),l.filter(n=>!Zr(n)).reduce((n,u)=>n+(Uv.test(u)?Hv:u===""?Bv:Lv),a)}function Gv(e,t){return e.length===t.length&&e.slice(0,-1).every((a,n)=>a===t[n])?e[e.length-1]-t[t.length-1]:0}function Xv(e,t,l=!1){let{routesMeta:a}=e,n={},u="/",i=[];for(let c=0;c<a.length;++c){let f=a[c],r=c===a.length-1,h=u==="/"?t:t.slice(u.length)||"/",y={path:f.relativePath,caseSensitive:f.caseSensitive,end:r},o=f.matcher&&f.compiledParams?im(y,h,f.matcher,f.compiledParams):gn(y,h),v=f.route;if(!o&&r&&l&&!a[a.length-1].route.index&&(o=gn({path:f.relativePath,caseSensitive:f.caseSensitive,end:!1},h)),!o)return null;Object.assign(n,o.params),i.push({params:n,pathname:it([u,o.pathname]),pathnameBase:Vv(it([u,o.pathnameBase])),route:v}),o.pathnameBase!=="/"&&(u=it([u,o.pathnameBase]))}return i}function gn(e,t){typeof e=="string"&&(e={path:e,caseSensitive:!1,end:!0});let[l,a]=cm(e.path,e.caseSensitive,e.end);return im(e,t,l,a)}function im(e,t,l,a){let n=t.match(l);if(!n)return null;let u=n[0],i=u.replace(/(.)\/+$/,"$1"),c=n.slice(1);return{params:a.reduce((r,{paramName:h,isOptional:y},o)=>{if(h==="*"){let S=c[o]||"";i=u.slice(0,u.length-S.length).replace(/(.)\/+$/,"$1")}const v=c[o];return y&&!v?r[h]=void 0:r[h]=(v||"").replace(/%2F/g,"/"),r},{}),pathname:u,pathnameBase:i,pattern:e}}function cm(e,t=!1,l=!0){yt(e==="*"||!e.endsWith("*")||e.endsWith("/*"),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,"/*")}".`);let a=[],n="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(i,c,f,r,h)=>{if(a.push({paramName:c,isOptional:f!=null}),f){let y=h.charAt(r+i.length);return y&&y!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return e.endsWith("*")?(a.push({paramName:"*"}),n+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):l?n+="\\/*$":e!==""&&e!=="/"&&(n+="(?:(?=\\/|$))"),[new RegExp(n,t?void 0:"i"),a]}function sm(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return yt(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Yt(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let l=t.endsWith("/")?t.length-1:t.length,a=e.charAt(l);return a&&a!=="/"?null:e.slice(l)||"/"}function Qv(e,t="/"){let{pathname:l,search:a="",hash:n=""}=typeof e=="string"?Ta(e):e,u;return l?(l=rm(l),l.startsWith("/")?u=Vr(l.substring(1),"/"):u=Vr(l,t)):u=t,{pathname:u,search:Kv(a),hash:Jv(n)}}function Vr(e,t){let l=Ju(t).split("/");return e.split("/").forEach(n=>{n===".."?l.length>1&&l.pop():n!=="."&&l.push(n)}),l.length>1?l.join("/"):"/"}function lc(e,t,l,a){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(a)}]. Please separate it out to the \`to.${l}\` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.`}function Zv(e){return e.filter((t,l)=>l===0||t.route.path&&t.route.path.length>0)}function fm(e){let t=Zv(e);return t.map((l,a)=>a===t.length-1?l.pathname:l.pathnameBase)}function uf(e,t,l,a=!1){let n;typeof e=="string"?n=Ta(e):(n={...e},ae(!n.pathname||!n.pathname.includes("?"),lc("?","pathname","search",n)),ae(!n.pathname||!n.pathname.includes("#"),lc("#","pathname","hash",n)),ae(!n.search||!n.search.includes("#"),lc("#","search","hash",n)));let u=e===""||n.pathname==="",i=u?"/":n.pathname,c;if(i==null)c=l;else{let y=t.length-1;if(!a&&i.startsWith("..")){let o=i.split("/");for(;o[0]==="..";)o.shift(),y-=1;n.pathname=o.join("/")}c=y>=0?t[y]:"/"}let f=Qv(n,c),r=i&&i!=="/"&&i.endsWith("/"),h=(u||i===".")&&l.endsWith("/");return!f.pathname.endsWith("/")&&(r||h)&&(f.pathname+="/"),f}var rm=e=>e.replace(/[\\/]{2,}/g,"/"),it=e=>rm(e.join("/")),Ju=e=>e.replace(/\/+$/,""),Vv=e=>Ju(e).replace(/^\/*/,"/"),Kv=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Jv=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e,kv=class{constructor(e,t,l,a=!1){this.status=e,this.statusText=t||"",this.internal=a,l instanceof Error?(this.data=l.toString(),this.error=l):this.data=l}};function $v(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}function Wv(e){let t=e.map(l=>l.route.path).filter(Boolean);return it(t)||"/"}var om=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function dm(e,t){let l=e;if(typeof l!="string"||!nf.test(l))return{absoluteURL:void 0,isExternal:!1,to:l};let a=l,n=!1;if(om)try{let u=new URL(window.location.href),i=lm.test(l)?new URL(Av(l,u.protocol)):new URL(l),c=Yt(i.pathname,t);i.origin===u.origin&&c!=null?l=c+i.search+i.hash:n=!0}catch{yt(!1,`<Link to="${l}"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:a,isExternal:n,to:l}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var hm=["POST","PUT","PATCH","DELETE"];new Set(hm);var Fv=["GET",...hm];new Set(Fv);var Iv=["about:","blob:","chrome:","chrome-untrusted:","content:","data:","devtools:","file:","filesystem:","javascript:"];function Pv(e){try{return Iv.includes(new URL(e).protocol)}catch{return!1}}var Aa=p.createContext(null);Aa.displayName="DataRouter";var mi=p.createContext(null);mi.displayName="DataRouterState";var mm=p.createContext(!1);function eg(){return p.useContext(mm)}var ym=p.createContext({isTransitioning:!1});ym.displayName="ViewTransition";var tg=p.createContext(new Map);tg.displayName="Fetchers";var lg=p.createContext(null);lg.displayName="Await";var at=p.createContext(null);at.displayName="Navigation";var Dn=p.createContext(null);Dn.displayName="Location";var ft=p.createContext({outlet:null,matches:[],isDataRoute:!1});ft.displayName="Route";var cf=p.createContext(null);cf.displayName="RouteError";var pm="REACT_ROUTER_ERROR",ag="REDIRECT",ng="ROUTE_ERROR_RESPONSE";function ug(e){if(e.startsWith(`${pm}:${ag}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string"&&typeof t.location=="string"&&typeof t.reloadDocument=="boolean"&&typeof t.replace=="boolean")return t}catch{}}function ig(e){if(e.startsWith(`${pm}:${ng}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string")return new kv(t.status,t.statusText,t.data)}catch{}}function cg(e,{relative:t}={}){ae(za(),"useHref() may be used only in the context of a <Router> component.");let{basename:l,navigator:a}=p.useContext(at),{hash:n,pathname:u,search:i}=Mn(e,{relative:t}),c=u;return l!=="/"&&(c=u==="/"?l:it([l,u])),a.createHref({pathname:c,search:i,hash:n})}function za(){return p.useContext(Dn)!=null}function gt(){return ae(za(),"useLocation() may be used only in the context of a <Router> component."),p.useContext(Dn).location}function Ha(e){ae(za(),"useMatch() may be used only in the context of a <Router> component.");let{pathname:t}=gt();return p.useMemo(()=>gn(e,sm(t)),[t,e])}var vm="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function gm(e){p.useContext(at).static||p.useLayoutEffect(e)}function Sm(){let{isDataRoute:e}=p.useContext(ft);return e?Eg():sg()}function sg(){ae(za(),"useNavigate() may be used only in the context of a <Router> component.");let e=p.useContext(Aa),{basename:t,navigator:l}=p.useContext(at),{matches:a}=p.useContext(ft),{pathname:n}=gt(),u=JSON.stringify(fm(a)),i=p.useRef(!1);return gm(()=>{i.current=!0}),p.useCallback((f,r={})=>{if(yt(i.current,vm),!i.current)return;if(typeof f=="number"){l.go(f);return}let h=uf(f,JSON.parse(u),n,r.relative==="path");e==null&&t!=="/"&&(h.pathname=h.pathname==="/"?t:it([t,h.pathname])),(r.replace?l.replace:l.push)(h,r.state,r)},[t,l,u,n,e])}var fg=p.createContext(null);function rg(e){let t=p.useContext(ft).outlet;return p.useMemo(()=>t&&p.createElement(fg.Provider,{value:e},t),[t,e])}function Hl(){let{matches:e}=p.useContext(ft),t=e[e.length-1];return(t==null?void 0:t.params)??{}}function Mn(e,{relative:t}={}){let{matches:l}=p.useContext(ft),{pathname:a}=gt(),n=JSON.stringify(fm(l));return p.useMemo(()=>uf(e,JSON.parse(n),a,t==="path"),[e,n,a,t])}function og(e,t){return bm(e,t)}function bm(e,t,l){var E;ae(za(),"useRoutes() may be used only in the context of a <Router> component.");let{navigator:a}=p.useContext(at),{matches:n}=p.useContext(ft),u=n[n.length-1],i=u?u.params:{},c=u?u.pathname:"/",f=u?u.pathnameBase:"/",r=u&&u.route;{let d=r&&r.path||"";Em(c,!r||d.endsWith("*")||d.endsWith("*?"),`You rendered descendant <Routes> (or called \`useRoutes()\`) at "${c}" (under <Route path="${d}">) 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="${d}"> to <Route path="${d==="/"?"*":`${d}/*`}">.`)}let h=gt(),y;if(t){let d=typeof t=="string"?Ta(t):t;ae(f==="/"||((E=d.pathname)==null?void 0:E.startsWith(f)),`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 "${f}" but pathname "${d.pathname}" was given in the \`location\` prop.`),y=d}else y=h;let o=y.pathname||"/",v=o;if(f!=="/"){let d=f.replace(/^\//,"").split("/");v="/"+o.replace(/^\//,"").split("/").slice(d.length).join("/")}let S=l&&l.state.matches.length?l.state.matches.map(d=>Object.assign(d,{route:l.manifest[d.route.id]||d.route})):am(e,{pathname:v});yt(r||S!=null,`No routes matched location "${y.pathname}${y.search}${y.hash}" `),yt(S==null||S[S.length-1].route.element!==void 0||S[S.length-1].route.Component!==void 0||S[S.length-1].route.lazy!==void 0,`Matched leaf route at location "${y.pathname}${y.search}${y.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 x=pg(S&&S.map(d=>Object.assign({},d,{params:Object.assign({},i,d.params),pathname:it([f,a.encodeLocation?a.encodeLocation(d.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:d.pathname]),pathnameBase:d.pathnameBase==="/"?f:it([f,a.encodeLocation?a.encodeLocation(d.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:d.pathnameBase])})),n,l);return t&&x?p.createElement(Dn.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...y},navigationType:"POP"}},x):x}function dg(){let e=xg(),t=$v(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),l=e instanceof Error?e.stack:null,a="rgba(200,200,200, 0.5)",n={padding:"0.5rem",backgroundColor:a},u={padding:"2px 4px",backgroundColor:a},i=null;return console.error("Error handled by React Router default ErrorBoundary:",e),i=p.createElement(p.Fragment,null,p.createElement("p",null,"💿 Hey developer 👋"),p.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",p.createElement("code",{style:u},"ErrorBoundary")," or"," ",p.createElement("code",{style:u},"errorElement")," prop on your route.")),p.createElement(p.Fragment,null,p.createElement("h2",null,"Unexpected Application Error!"),p.createElement("h3",{style:{fontStyle:"italic"}},t),l?p.createElement("pre",{style:n},l):null,i)}var hg=p.createElement(dg,null),xm=class extends p.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error("React Router caught the following error during render",e)}render(){let e=this.state.error;if(this.context&&typeof e=="object"&&e&&"digest"in e&&typeof e.digest=="string"){const l=ig(e.digest);l&&(e=l)}let t=e!==void 0?p.createElement(ft.Provider,{value:this.props.routeContext},p.createElement(cf.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?p.createElement(mg,{error:e},t):t}};xm.contextType=mm;var ac=new WeakMap;function mg({children:e,error:t}){let{basename:l}=p.useContext(at);if(typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){let a=ug(t.digest);if(a){let n=ac.get(t);if(n)throw n;let u=dm(a.location,l),i=u.absoluteURL||u.to;if(Pv(i))throw new Error("Invalid redirect location");if(om&&!ac.get(t))if(u.isExternal||a.reloadDocument)window.location.href=i;else{const c=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(u.to,{replace:a.replace}));throw ac.set(t,c),c}return p.createElement("meta",{httpEquiv:"refresh",content:`0;url=${i}`})}}return e}function yg({routeContext:e,match:t,children:l}){let a=p.useContext(Aa);return a&&a.static&&a.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(a.staticContext._deepestRenderedBoundaryId=t.route.id),p.createElement(ft.Provider,{value:e},l)}function pg(e,t=[],l){let a=l==null?void 0:l.state;if(e==null){if(!a)return null;if(a.errors)e=a.matches;else if(t.length===0&&!a.initialized&&a.matches.length>0)e=a.matches;else return null}let n=e,u=a==null?void 0:a.errors;if(u!=null){let h=n.findIndex(y=>y.route.id&&(u==null?void 0:u[y.route.id])!==void 0);ae(h>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(u).join(",")}`),n=n.slice(0,Math.min(n.length,h+1))}let i=!1,c=-1;if(l&&a){i=a.renderFallback;for(let h=0;h<n.length;h++){let y=n[h];if((y.route.HydrateFallback||y.route.hydrateFallbackElement)&&(c=h),y.route.id){let{loaderData:o,errors:v}=a,S=y.route.loader&&!o.hasOwnProperty(y.route.id)&&(!v||v[y.route.id]===void 0);if(y.route.lazy||S){l.isStatic&&(i=!0),c>=0?n=n.slice(0,c+1):n=[n[0]];break}}}}let f=l==null?void 0:l.onError,r=a&&f?(h,y)=>{var o,v;f(h,{location:a.location,params:((v=(o=a.matches)==null?void 0:o[0])==null?void 0:v.params)??{},pattern:Wv(a.matches),errorInfo:y})}:void 0;return n.reduceRight((h,y,o)=>{let v,S=!1,x=null,E=null;a&&(v=u&&y.route.id?u[y.route.id]:void 0,x=y.route.errorElement||hg,i&&(c<0&&o===0?(Em("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),S=!0,E=null):c===o&&(S=!0,E=y.route.hydrateFallbackElement||null)));let d=t.concat(n.slice(0,o+1)),m=()=>{let g;return v?g=x:S?g=E:y.route.Component?g=p.createElement(y.route.Component,null):y.route.element?g=y.route.element:g=h,p.createElement(yg,{match:y,routeContext:{outlet:h,matches:d,isDataRoute:a!=null},children:g})};return a&&(y.route.ErrorBoundary||y.route.errorElement||o===0)?p.createElement(xm,{location:a.location,revalidation:a.revalidation,component:x,error:v,children:m(),routeContext:{outlet:null,matches:d,isDataRoute:!0},onError:r}):m()},null)}function sf(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function vg(e){let t=p.useContext(Aa);return ae(t,sf(e)),t}function gg(e){let t=p.useContext(mi);return ae(t,sf(e)),t}function Sg(e){let t=p.useContext(ft);return ae(t,sf(e)),t}function ff(e){let t=Sg(e),l=t.matches[t.matches.length-1];return ae(l.route.id,`${e} can only be used on routes that contain a unique "id"`),l.route.id}function bg(){return ff("useRouteId")}function xg(){var a;let e=p.useContext(cf),t=gg("useRouteError"),l=ff("useRouteError");return e!==void 0?e:(a=t.errors)==null?void 0:a[l]}function Eg(){let{router:e}=vg("useNavigate"),t=ff("useNavigate"),l=p.useRef(!1);return gm(()=>{l.current=!0}),p.useCallback(async(n,u={})=>{yt(l.current,vm),l.current&&(typeof n=="number"?await e.navigate(n):await e.navigate(n,{fromRouteId:t,...u}))},[e,t])}var Kr={};function Em(e,t,l){!t&&!Kr[e]&&(Kr[e]=!0,yt(!1,l))}p.memo(jg);function jg({routes:e,manifest:t,future:l,state:a,isStatic:n,onError:u}){return bm(e,void 0,{manifest:t,state:a,isStatic:n,onError:u})}function Ng(e){return rg(e.context)}function Ke(e){ae(!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 Tg({basename:e="/",children:t=null,location:l,navigationType:a="POP",navigator:n,static:u=!1,useTransitions:i}){ae(!za(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let c=e.replace(/^\/*/,"/"),f=p.useMemo(()=>({basename:c,navigator:n,static:u,useTransitions:i,future:{}}),[c,n,u,i]);typeof l=="string"&&(l=Ta(l));let{pathname:r="/",search:h="",hash:y="",state:o=null,key:v="default",mask:S}=l,x=p.useMemo(()=>{let E=Yt(r,c);return E==null?null:{location:{pathname:E,search:h,hash:y,state:o,key:v,mask:S},navigationType:a}},[c,r,h,y,o,v,a,S]);return yt(x!=null,`<Router basename="${c}"> is not able to match the URL "${r}${h}${y}" because it does not start with the basename, so the <Router> won't render anything.`),x==null?null:p.createElement(at.Provider,{value:f},p.createElement(Dn.Provider,{children:t,value:x}))}function Ag({children:e,location:t}){return og(ls(e),t)}function ls(e,t=[]){let l=[];return p.Children.forEach(e,(a,n)=>{if(!p.isValidElement(a))return;let u=[...t,n];if(a.type===p.Fragment){l.push.apply(l,ls(a.props.children,u));return}ae(a.type===Ke,`[${typeof a.type=="string"?a.type:a.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`),ae(!a.props.index||!a.props.children,"An index route cannot have child routes.");let i={id:a.props.id||u.join("-"),caseSensitive:a.props.caseSensitive,element:a.props.element,Component:a.props.Component,index:a.props.index,path:a.props.path,middleware:a.props.middleware,loader:a.props.loader,action:a.props.action,hydrateFallbackElement:a.props.hydrateFallbackElement,HydrateFallback:a.props.HydrateFallback,errorElement:a.props.errorElement,ErrorBoundary:a.props.ErrorBoundary,hasErrorBoundary:a.props.hasErrorBoundary===!0||a.props.ErrorBoundary!=null||a.props.errorElement!=null,shouldRevalidate:a.props.shouldRevalidate,handle:a.props.handle,lazy:a.props.lazy};a.props.children&&(i.children=ls(a.props.children,u)),l.push(i)}),l}var pu="get",vu="application/x-www-form-urlencoded";function yi(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement}function zg(e){return yi(e)&&e.tagName.toLowerCase()==="button"}function Cg(e){return yi(e)&&e.tagName.toLowerCase()==="form"}function _g(e){return yi(e)&&e.tagName.toLowerCase()==="input"}function Og(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function Rg(e,t){return e.button===0&&(!t||t==="_self")&&!Og(e)}var Pn=null;function Dg(){if(Pn===null)try{new FormData(document.createElement("form"),0),Pn=!1}catch{Pn=!0}return Pn}var Mg=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function nc(e){return e!=null&&!Mg.has(e)?(yt(!1,`"${e}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${vu}"`),null):e}function Ug(e,t){let l,a,n,u,i;if(Cg(e)){let c=e.getAttribute("action");a=c?Yt(c,t):null,l=e.getAttribute("method")||pu,n=nc(e.getAttribute("enctype"))||vu,u=new FormData(e)}else if(zg(e)||_g(e)&&(e.type==="submit"||e.type==="image")){let c=e.form;if(c==null)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let f=e.getAttribute("formaction")||c.getAttribute("action");if(a=f?Yt(f,t):null,l=e.getAttribute("formmethod")||c.getAttribute("method")||pu,n=nc(e.getAttribute("formenctype"))||nc(c.getAttribute("enctype"))||vu,u=new FormData(c,e),!Dg()){let{name:r,type:h,value:y}=e;if(h==="image"){let o=r?`${r}.`:"";u.append(`${o}x`,"0"),u.append(`${o}y`,"0")}else r&&u.append(r,y)}}else{if(yi(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');l=pu,a=null,n=vu,i=e}return u&&n==="text/plain"&&(i=u,u=void 0),{action:a,method:l.toLowerCase(),encType:n,formData:u,body:i}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function rf(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function jm(e,t,l,a){let n=typeof e=="string"?new URL(e,typeof window>"u"?"server://singlefetch/":window.location.origin):e;return l?n.pathname.endsWith("/")?n.pathname=`${n.pathname}_.${a}`:n.pathname=`${n.pathname}.${a}`:n.pathname==="/"?n.pathname=`_root.${a}`:t&&Yt(n.pathname,t)==="/"?n.pathname=`${Ju(t)}/_root.${a}`:n.pathname=`${Ju(n.pathname)}.${a}`,n}async function Hg(e,t){if(e.id in t)return t[e.id];try{let l=await import(e.module);return t[e.id]=l,l}catch(l){return console.error(`Error loading route module \`${e.module}\`, reloading page...`),console.error(l),window.__reactRouterContext&&window.__reactRouterContext.isSpaMode,window.location.reload(),new Promise(()=>{})}}function wg(e){return e==null?!1:e.href==null?e.rel==="preload"&&typeof e.imageSrcSet=="string"&&typeof e.imageSizes=="string":typeof e.rel=="string"&&typeof e.href=="string"}async function Bg(e,t,l){let a=await Promise.all(e.map(async n=>{let u=t.routes[n.route.id];if(u){let i=await Hg(u,l);return i.links?i.links():[]}return[]}));return Gg(a.flat(1).filter(wg).filter(n=>n.rel==="stylesheet"||n.rel==="preload").map(n=>n.rel==="stylesheet"?{...n,rel:"prefetch",as:"style"}:{...n,rel:"prefetch"}))}function Jr(e,t,l,a,n,u){let i=(f,r)=>l[r]?f.route.id!==l[r].route.id:!0,c=(f,r)=>{var h;return l[r].pathname!==f.pathname||((h=l[r].route.path)==null?void 0:h.endsWith("*"))&&l[r].params["*"]!==f.params["*"]};return u==="assets"?t.filter((f,r)=>i(f,r)||c(f,r)):u==="data"?t.filter((f,r)=>{var y;let h=a.routes[f.route.id];if(!h||!h.hasLoader)return!1;if(i(f,r)||c(f,r))return!0;if(f.route.shouldRevalidate){let o=f.route.shouldRevalidate({currentUrl:new URL(n.pathname+n.search+n.hash,window.origin),currentParams:((y=l[0])==null?void 0:y.params)||{},nextUrl:new URL(e,window.origin),nextParams:f.params,defaultShouldRevalidate:!0});if(typeof o=="boolean")return o}return!0}):[]}function Lg(e,t,{includeHydrateFallback:l}={}){return Yg(e.map(a=>{let n=t.routes[a.route.id];if(!n)return[];let u=[n.module];return n.clientActionModule&&(u=u.concat(n.clientActionModule)),n.clientLoaderModule&&(u=u.concat(n.clientLoaderModule)),l&&n.hydrateFallbackModule&&(u=u.concat(n.hydrateFallbackModule)),n.imports&&(u=u.concat(n.imports)),u}).flat(1))}function Yg(e){return[...new Set(e)]}function qg(e){let t={},l=Object.keys(e).sort();for(let a of l)t[a]=e[a];return t}function Gg(e,t){let l=new Set;return new Set(t),e.reduce((a,n)=>{let u=JSON.stringify(qg(n));return l.has(u)||(l.add(u),a.push({key:u,link:n})),a},[])}function of(){let e=p.useContext(Aa);return rf(e,"You must render this element inside a <DataRouterContext.Provider> element"),e}function Xg(){let e=p.useContext(mi);return rf(e,"You must render this element inside a <DataRouterStateContext.Provider> element"),e}var df=p.createContext(void 0);df.displayName="FrameworkContext";function pi(){let e=p.useContext(df);return rf(e,"You must render this element inside a <HydratedRouter> element"),e}function Qg(e,t){let l=p.useContext(df),[a,n]=p.useState(!1),[u,i]=p.useState(!1),{onFocus:c,onBlur:f,onMouseEnter:r,onMouseLeave:h,onTouchStart:y}=t,o=p.useRef(null);p.useEffect(()=>{if(e==="render"&&i(!0),e==="viewport"){let x=d=>{d.forEach(m=>{i(m.isIntersecting)})},E=new IntersectionObserver(x,{threshold:.5});return o.current&&E.observe(o.current),()=>{E.disconnect()}}},[e]),p.useEffect(()=>{if(a){let x=setTimeout(()=>{i(!0)},100);return()=>{clearTimeout(x)}}},[a]);let v=()=>{n(!0)},S=()=>{n(!1),i(!1)};return l?e!=="intent"?[u,o,{}]:[u,o,{onFocus:wa(c,v),onBlur:wa(f,S),onMouseEnter:wa(r,v),onMouseLeave:wa(h,S),onTouchStart:wa(y,v)}]:[!1,o,{}]}function wa(e,t){return l=>{e&&e(l),l.defaultPrevented||t(l)}}function Zg({page:e,...t}){let l=eg(),{nonce:a}=pi(),{router:n}=of(),u=p.useMemo(()=>am(n.routes,e,n.basename),[n.routes,e,n.basename]);return u?(t.nonce==null&&a&&(t={...t,nonce:a}),l?p.createElement(Kg,{page:e,matches:u,...t}):p.createElement(Jg,{page:e,matches:u,...t})):null}function Vg(e){let{manifest:t,routeModules:l}=pi(),[a,n]=p.useState([]);return p.useEffect(()=>{let u=!1;return Bg(e,t,l).then(i=>{u||n(i)}),()=>{u=!0}},[e,t,l]),a}function Kg({page:e,matches:t,...l}){let a=gt(),{future:n}=pi(),{basename:u}=of(),i=p.useMemo(()=>{if(e===a.pathname+a.search+a.hash)return[];let c=jm(e,u,n.v8_trailingSlashAwareDataRequests,"rsc"),f=!1,r=[];for(let h of t)typeof h.route.shouldRevalidate=="function"?f=!0:r.push(h.route.id);return f&&r.length>0&&c.searchParams.set("_routes",r.join(",")),[c.pathname+c.search]},[u,n.v8_trailingSlashAwareDataRequests,e,a,t]);return p.createElement(p.Fragment,null,i.map(c=>p.createElement("link",{key:c,rel:"prefetch",as:"fetch",href:c,...l})))}function Jg({page:e,matches:t,...l}){let a=gt(),{future:n,manifest:u,routeModules:i}=pi(),{basename:c}=of(),{loaderData:f,matches:r}=Xg(),h=p.useMemo(()=>Jr(e,t,r,u,a,"data"),[e,t,r,u,a]),y=p.useMemo(()=>Jr(e,t,r,u,a,"assets"),[e,t,r,u,a]),o=p.useMemo(()=>{if(e===a.pathname+a.search+a.hash)return[];let x=new Set,E=!1;if(t.forEach(m=>{var b;let g=u.routes[m.route.id];!g||!g.hasLoader||(!h.some(A=>A.route.id===m.route.id)&&m.route.id in f&&((b=i[m.route.id])!=null&&b.shouldRevalidate)||g.hasClientLoader?E=!0:x.add(m.route.id))}),x.size===0)return[];let d=jm(e,c,n.v8_trailingSlashAwareDataRequests,"data");return E&&x.size>0&&d.searchParams.set("_routes",t.filter(m=>x.has(m.route.id)).map(m=>m.route.id).join(",")),[d.pathname+d.search]},[c,n.v8_trailingSlashAwareDataRequests,f,a,u,h,t,e,i]),v=p.useMemo(()=>Lg(y,u),[y,u]),S=Vg(y);return p.createElement(p.Fragment,null,o.map(x=>p.createElement("link",{key:x,rel:"prefetch",as:"fetch",href:x,...l})),v.map(x=>p.createElement("link",{key:x,rel:"modulepreload",href:x,...l})),S.map(({key:x,link:E})=>p.createElement("link",{key:x,nonce:l.nonce,...E,crossOrigin:E.crossOrigin??l.crossOrigin})))}function kg(...e){return t=>{e.forEach(l=>{typeof l=="function"?l(t):l!=null&&(l.current=t)})}}var $g=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";try{$g&&(window.__reactRouterVersion="7.18.1")}catch{}function Wg({basename:e,children:t,useTransitions:l,window:a}){let n=p.useRef();n.current==null&&(n.current=zv({window:a,v5Compat:!0}));let u=n.current,[i,c]=p.useState({action:u.action,location:u.location}),f=p.useCallback(r=>{l===!1?c(r):p.startTransition(()=>c(r))},[l]);return p.useLayoutEffect(()=>u.listen(f),[u,f]),p.createElement(Tg,{basename:e,children:t,location:i.location,navigationType:i.action,navigator:u,useTransitions:l})}var ct=p.forwardRef(function({onClick:t,discover:l="render",prefetch:a="none",relative:n,reloadDocument:u,replace:i,mask:c,state:f,target:r,to:h,preventScrollReset:y,viewTransition:o,defaultShouldRevalidate:v,...S},x){let{basename:E,navigator:d,useTransitions:m}=p.useContext(at),g=typeof h=="string"&&nf.test(h),b=dm(h,E);h=b.to;let A=cg(h,{relative:n}),C=gt(),T=null;if(c){let ge=uf(c,[],C.mask?C.mask.pathname:"/",!0);E!=="/"&&(ge.pathname=ge.pathname==="/"?E:it([E,ge.pathname])),T=d.createHref(ge)}let[N,R,O]=Qg(a,S),U=Pg(h,{replace:i,mask:c,state:f,target:r,preventScrollReset:y,relative:n,viewTransition:o,defaultShouldRevalidate:v,useTransitions:m});function Z(ge){t&&t(ge),ge.defaultPrevented||U(ge)}let rt=!(b.isExternal||u),St=p.createElement("a",{...S,...O,href:(rt?T:void 0)||b.absoluteURL||A,onClick:rt?Z:t,ref:kg(x,R),target:r,"data-discover":!g&&l==="render"?"true":void 0});return N&&!g?p.createElement(p.Fragment,null,St,p.createElement(Zg,{page:A})):St});ct.displayName="Link";var At=p.forwardRef(function({"aria-current":t="page",caseSensitive:l=!1,className:a="",end:n=!1,style:u,to:i,viewTransition:c,children:f,...r},h){let y=Mn(i,{relative:r.relative}),o=gt(),v=p.useContext(mi),{navigator:S,basename:x}=p.useContext(at),E=v!=null&&n0(y)&&c===!0,d=S.encodeLocation?S.encodeLocation(y).pathname:y.pathname,m=o.pathname,g=v&&v.navigation&&v.navigation.location?v.navigation.location.pathname:null;l||(m=m.toLowerCase(),g=g?g.toLowerCase():null,d=d.toLowerCase()),g&&x&&(g=Yt(g,x)||g);const b=d!=="/"&&d.endsWith("/")?d.length-1:d.length;let A=m===d||!n&&m.startsWith(d)&&m.charAt(b)==="/",C=g!=null&&(g===d||!n&&g.startsWith(d)&&g.charAt(d.length)==="/"),T={isActive:A,isPending:C,isTransitioning:E},N=A?t:void 0,R;typeof a=="function"?R=a(T):R=[a,A?"active":null,C?"pending":null,E?"transitioning":null].filter(Boolean).join(" ");let O=typeof u=="function"?u(T):u;return p.createElement(ct,{...r,"aria-current":N,className:R,ref:h,style:O,to:i,viewTransition:c},typeof f=="function"?f(T):f)});At.displayName="NavLink";var Fg=p.forwardRef(({discover:e="render",fetcherKey:t,navigate:l,reloadDocument:a,replace:n,state:u,method:i=pu,action:c,onSubmit:f,relative:r,preventScrollReset:h,viewTransition:y,defaultShouldRevalidate:o,...v},S)=>{let{useTransitions:x}=p.useContext(at),E=l0(),d=a0(c,{relative:r}),m=i.toLowerCase()==="get"?"get":"post",g=typeof c=="string"&&nf.test(c),b=A=>{if(f&&f(A),A.defaultPrevented)return;A.preventDefault();let C=A.nativeEvent.submitter,T=(C==null?void 0:C.getAttribute("formmethod"))||i,N=()=>E(C||A.currentTarget,{fetcherKey:t,method:T,navigate:l,replace:n,state:u,relative:r,preventScrollReset:h,viewTransition:y,defaultShouldRevalidate:o});x&&l!==!1?p.startTransition(()=>N()):N()};return p.createElement("form",{ref:S,method:m,action:d,onSubmit:a?f:b,...v,"data-discover":!g&&e==="render"?"true":void 0})});Fg.displayName="Form";function Ig(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Nm(e){let t=p.useContext(Aa);return ae(t,Ig(e)),t}function Pg(e,{target:t,replace:l,mask:a,state:n,preventScrollReset:u,relative:i,viewTransition:c,defaultShouldRevalidate:f,useTransitions:r}={}){let h=Sm(),y=gt(),o=Mn(e,{relative:i});return p.useCallback(v=>{if(Rg(v,t)){v.preventDefault();let S=l!==void 0?l:vn(y)===vn(o),x=()=>h(e,{replace:S,mask:a,state:n,preventScrollReset:u,relative:i,viewTransition:c,defaultShouldRevalidate:f});r?p.startTransition(()=>x()):x()}},[y,h,o,l,a,n,t,e,u,i,c,f,r])}var e0=0,t0=()=>`__${String(++e0)}__`;function l0(){let{router:e}=Nm("useSubmit"),{basename:t}=p.useContext(at),l=bg(),a=e.fetch,n=e.navigate;return p.useCallback(async(u,i={})=>{let{action:c,method:f,encType:r,formData:h,body:y}=Ug(u,t);if(i.navigate===!1){let o=i.fetcherKey||t0();await a(o,l,i.action||c,{defaultShouldRevalidate:i.defaultShouldRevalidate,preventScrollReset:i.preventScrollReset,formData:h,body:y,formMethod:i.method||f,formEncType:i.encType||r,flushSync:i.flushSync})}else await n(i.action||c,{defaultShouldRevalidate:i.defaultShouldRevalidate,preventScrollReset:i.preventScrollReset,formData:h,body:y,formMethod:i.method||f,formEncType:i.encType||r,replace:i.replace,state:i.state,fromRouteId:l,flushSync:i.flushSync,viewTransition:i.viewTransition})},[a,n,t,l])}function a0(e,{relative:t}={}){let{basename:l}=p.useContext(at),a=p.useContext(ft);ae(a,"useFormAction must be used inside a RouteContext");let[n]=a.matches.slice(-1),u={...Mn(e||".",{relative:t})},i=gt();if(e==null){u.search=i.search;let c=new URLSearchParams(u.search),f=c.getAll("index");if(f.some(h=>h==="")){c.delete("index"),f.filter(y=>y).forEach(y=>c.append("index",y));let h=c.toString();u.search=h?`?${h}`:""}}return(!e||e===".")&&n.route.index&&(u.search=u.search?u.search.replace(/^\?/,"?index&"):"?index"),l!=="/"&&(u.pathname=u.pathname==="/"?l:it([l,u.pathname])),vn(u)}function n0(e,{relative:t}={}){let l=p.useContext(ym);ae(l!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:a}=Nm("useViewTransitionState"),n=Mn(e,{relative:t});if(!l.isTransitioning)return!1;let u=Yt(l.currentLocation.pathname,a)||l.currentLocation.pathname,i=Yt(l.nextLocation.pathname,a)||l.nextLocation.pathname;return gn(n.pathname,i)!=null||gn(n.pathname,u)!=null}const Se=async e=>{if(!e.ok)throw new Error((await e.json()).error??e.statusText);return await e.json()},He=async e=>{if(e.ok)return;const t=await e.json().catch(()=>({}));throw new Error(t.error??e.statusText)},B={login:(e,t)=>fetch("/api/login",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:e,password:t})}).then(l=>l.ok),me:()=>fetch("/api/me").then(Se),logout:()=>fetch("/api/logout",{method:"POST"}).then(He),changeOwnPassword:(e,t)=>fetch("/api/account/password",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({current:e,next:t})}).then(He),setAccountName:(e,t)=>fetch("/api/account/name",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({current:e,next:t})}).then(Se),requiredSecrets:e=>fetch(`/api/projects/${e}/required-secrets`).then(Se),revealSecret:(e,t)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}/value`).then(Se),setSecretMasked:(e,t,l)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({masked:l})}).then(He),users:()=>fetch("/api/users").then(Se),setUserProjects:(e,t)=>fetch(`/api/users/${encodeURIComponent(e)}/projects`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({projects:t})}).then(He),createUser:(e,t,l)=>fetch("/api/users",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:e,role:t,password:l})}).then(Se),removeUser:e=>fetch(`/api/users/${encodeURIComponent(e)}`,{method:"DELETE"}).then(He),projects:()=>fetch("/api/projects").then(Se),lanes:e=>fetch(`/api/projects/${e}/lanes`).then(Se),runsOf:e=>fetch(`/api/projects/${e}/runs`).then(Se),run:e=>fetch(`/api/runs/${e}`).then(Se),log:(e,t=0)=>fetch(`/api/runs/${e}/log?from=${t}`).then(l=>l.text()),removeProject:e=>fetch(`/api/projects/${e}?confirm=${encodeURIComponent(e)}`,{method:"DELETE"}).then(Se),secrets:e=>fetch(`/api/projects/${e}/secrets`).then(Se),readiness:e=>fetch(`/api/projects/${e}/readiness`).then(Se),setSecret:(e,t,l,a)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({value:l,masked:a})}).then(He),deleteSecret:(e,t)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}`,{method:"DELETE"}).then(He),listCredentials:e=>fetch(`/api/projects/${e}/credentials`).then(Se),putCredential:(e,t,l)=>fetch(`/api/projects/${e}/credentials/${t}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(l)}).then(He),deleteCredential:(e,t)=>fetch(`/api/projects/${e}/credentials/${t}`,{method:"DELETE"}).then(He),fastfile:e=>fetch(`/api/projects/${e}/fastfile`).then(Se),saveFastfile:(e,t)=>fetch(`/api/projects/${e}/fastfile`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:t})}).then(He),changes:e=>fetch(`/api/projects/${e}/changes`).then(Se),commit:(e,t)=>fetch(`/api/projects/${e}/commit`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({message:t})}).then(He),push:e=>fetch(`/api/projects/${e}/push`,{method:"POST"}).then(He),trigger:(e,t,l,a)=>fetch(`/api/projects/${e}/runs`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({lane:t,platform:l,params:a})}).then(Se),cancel:e=>fetch(`/api/runs/${e}/cancel`,{method:"POST"}).then(He)};function u0({onSuccess:e}){const[t,l]=p.useState(""),[a,n]=p.useState(""),[u,i]=p.useState(!1),c=async f=>{f.preventDefault(),await B.login(t.trim(),a)?e():i(!0)};return s.jsx("div",{className:"login",children:s.jsxs("form",{className:"panel",onSubmit:f=>void c(f),children:[s.jsx("p",{className:"brand",children:"laneyard"}),s.jsxs("label",{children:["name ",s.jsx("input",{type:"text",value:t,onChange:f=>l(f.target.value),autoFocus:!0,spellCheck:!1,autoComplete:"username"})]}),s.jsxs("label",{children:["password"," ",s.jsx("input",{type:"password",value:a,onChange:f=>n(f.target.value),autoComplete:"current-password"})]}),s.jsx("button",{type:"submit",children:"enter"}),u&&s.jsx("p",{className:"status-failed",children:"incorrect name or password"})]})})}function i0(){const[e,t]=p.useState(()=>localStorage.getItem("laneyard-theme")??"dark");return p.useEffect(()=>{document.documentElement.dataset.theme=e,localStorage.setItem("laneyard-theme",e)},[e]),s.jsx("button",{onClick:()=>t(e==="dark"?"light":"dark"),children:e==="dark"?"paper":"dark"})}function c0(){const e=p.useContext(vi),t=p.useContext(Cm),[l,a]=p.useState(""),[n,u]=p.useState(""),[i,c]=p.useState(""),[f,r]=p.useState(!1),[h,y]=p.useState(null),[o,v]=p.useState(!1),[S,x]=p.useState(""),[E,d]=p.useState(""),[m,g]=p.useState(!1),[b,A]=p.useState(null),[C,T]=p.useState(!1),N=i!==""&&n!==i,R=async U=>{U.preventDefault(),r(!0),y(null);try{await B.changeOwnPassword(l,n),a(""),u(""),c(""),v(!0)}catch(Z){v(!1),y(Z.message)}finally{r(!1)}},O=async U=>{U.preventDefault(),g(!0),A(null);try{await B.setAccountName(S,E),x(""),d(""),T(!0),t()}catch(Z){T(!1),A(Z.message)}finally{g(!1)}};return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"your account"}),s.jsxs("p",{className:"dim",children:["signed in as ",s.jsx("span",{className:"bright",children:e==null?void 0:e.name})," ",s.jsx("span",{className:"dim",children:e==null?void 0:e.role}),". your password and your name are the two things this page changes, and the two things nobody else can change for you."]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"change password"}),s.jsxs("form",{className:"secret-form",onSubmit:U=>void R(U),children:[s.jsx("input",{type:"password",value:l,onChange:U=>a(U.target.value),placeholder:"current password",autoComplete:"current-password","aria-label":"current password"}),s.jsx("input",{type:"password",value:n,onChange:U=>u(U.target.value),placeholder:"new password",autoComplete:"new-password","aria-label":"new password"}),s.jsx("input",{type:"password",value:i,onChange:U=>c(U.target.value),placeholder:"again",autoComplete:"new-password","aria-label":"new password again"}),s.jsx("button",{type:"submit",disabled:f||l===""||n===""||n!==i,children:"change"})]}),N&&s.jsx("p",{className:"status-failed",children:"the two new passwords are not the same."}),s.jsx("p",{className:"dim",children:"the new password is hashed into this machine's config.yml. every other session this account has ends at once — a phone, another browser — and this page stays signed in."}),s.jsx("p",{className:"dim",children:"the current password is asked for even though you are already signed in: a session is a cookie in a browser that may have been left open."}),o&&s.jsxs("p",{children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"dim",children:"password changed."})]}),h&&s.jsxs("p",{className:"status-failed",children:["refused — ",h]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"change your identifier"}),s.jsxs("form",{className:"secret-form",onSubmit:U=>void O(U),children:[s.jsx("input",{type:"password",value:S,onChange:U=>x(U.target.value),placeholder:"current password",autoComplete:"current-password","aria-label":"current password to change name"}),s.jsx("input",{type:"text",value:E,onChange:U=>d(U.target.value),placeholder:"new name",autoComplete:"off","aria-label":"new name"}),s.jsx("button",{type:"submit",disabled:m||S===""||E===""||E===(e==null?void 0:e.name),children:"change"})]}),s.jsx("p",{className:"dim",children:"your name is what you type into the login form. changing it here edits this machine's config.yml and keeps your role and your project access exactly as they were. every other session ends, and this page stays signed in under the new name."}),s.jsx("p",{className:"dim",children:"the current password is asked for here too: a session is a cookie in a browser that may have been left open."}),C&&s.jsxs("p",{children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"dim",children:"name changed."})]}),b&&s.jsxs("p",{className:"status-failed",children:["refused — ",b]})]})}const s0="modulepreload",f0=function(e){return"/"+e},kr={},r0=function(t,l,a){let n=Promise.resolve();if(l&&l.length>0){document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),c=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));n=Promise.allSettled(l.map(f=>{if(f=f0(f),f in kr)return;kr[f]=!0;const r=f.endsWith(".css"),h=r?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${f}"]${h}`))return;const y=document.createElement("link");if(y.rel=r?"stylesheet":s0,r||(y.as="script"),y.crossOrigin="",y.href=f,c&&y.setAttribute("nonce",c),document.head.appendChild(y),r)return new Promise((o,v)=>{y.addEventListener("load",o),y.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${f}`)))})}))}function u(i){const c=new Event("vite:preloadError",{cancelable:!0});if(c.payload=i,window.dispatchEvent(c),!c.defaultPrevented)throw i}return n.then(i=>{for(const c of i||[])c.status==="rejected"&&u(c.reason);return t().catch(u)})},o0=p.lazy(()=>r0(()=>import("./Editor-Bqz_dClT.js"),[]).then(e=>({default:e.Editor})));function d0(e){return e.startsWith("+++")||e.startsWith("---")||e.startsWith("@@")?"dim":e.startsWith("+")?"status-success":e.startsWith("-")?"status-failed":""}function h0({text:e}){return s.jsx("pre",{className:"diff panel",children:e.split(`
60
+ Please change the parent <Route path="${d}"> to <Route path="${d==="/"?"*":`${d}/*`}">.`)}let h=gt(),y;if(t){let d=typeof t=="string"?Ta(t):t;ae(f==="/"||((E=d.pathname)==null?void 0:E.startsWith(f)),`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 "${f}" but pathname "${d.pathname}" was given in the \`location\` prop.`),y=d}else y=h;let o=y.pathname||"/",v=o;if(f!=="/"){let d=f.replace(/^\//,"").split("/");v="/"+o.replace(/^\//,"").split("/").slice(d.length).join("/")}let S=l&&l.state.matches.length?l.state.matches.map(d=>Object.assign(d,{route:l.manifest[d.route.id]||d.route})):am(e,{pathname:v});yt(r||S!=null,`No routes matched location "${y.pathname}${y.search}${y.hash}" `),yt(S==null||S[S.length-1].route.element!==void 0||S[S.length-1].route.Component!==void 0||S[S.length-1].route.lazy!==void 0,`Matched leaf route at location "${y.pathname}${y.search}${y.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 x=pg(S&&S.map(d=>Object.assign({},d,{params:Object.assign({},i,d.params),pathname:it([f,a.encodeLocation?a.encodeLocation(d.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:d.pathname]),pathnameBase:d.pathnameBase==="/"?f:it([f,a.encodeLocation?a.encodeLocation(d.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:d.pathnameBase])})),n,l);return t&&x?p.createElement(Dn.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...y},navigationType:"POP"}},x):x}function dg(){let e=xg(),t=$v(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),l=e instanceof Error?e.stack:null,a="rgba(200,200,200, 0.5)",n={padding:"0.5rem",backgroundColor:a},u={padding:"2px 4px",backgroundColor:a},i=null;return console.error("Error handled by React Router default ErrorBoundary:",e),i=p.createElement(p.Fragment,null,p.createElement("p",null,"💿 Hey developer 👋"),p.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",p.createElement("code",{style:u},"ErrorBoundary")," or"," ",p.createElement("code",{style:u},"errorElement")," prop on your route.")),p.createElement(p.Fragment,null,p.createElement("h2",null,"Unexpected Application Error!"),p.createElement("h3",{style:{fontStyle:"italic"}},t),l?p.createElement("pre",{style:n},l):null,i)}var hg=p.createElement(dg,null),xm=class extends p.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error("React Router caught the following error during render",e)}render(){let e=this.state.error;if(this.context&&typeof e=="object"&&e&&"digest"in e&&typeof e.digest=="string"){const l=ig(e.digest);l&&(e=l)}let t=e!==void 0?p.createElement(ft.Provider,{value:this.props.routeContext},p.createElement(cf.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?p.createElement(mg,{error:e},t):t}};xm.contextType=mm;var ac=new WeakMap;function mg({children:e,error:t}){let{basename:l}=p.useContext(at);if(typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){let a=ug(t.digest);if(a){let n=ac.get(t);if(n)throw n;let u=dm(a.location,l),i=u.absoluteURL||u.to;if(Pv(i))throw new Error("Invalid redirect location");if(om&&!ac.get(t))if(u.isExternal||a.reloadDocument)window.location.href=i;else{const c=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(u.to,{replace:a.replace}));throw ac.set(t,c),c}return p.createElement("meta",{httpEquiv:"refresh",content:`0;url=${i}`})}}return e}function yg({routeContext:e,match:t,children:l}){let a=p.useContext(Aa);return a&&a.static&&a.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(a.staticContext._deepestRenderedBoundaryId=t.route.id),p.createElement(ft.Provider,{value:e},l)}function pg(e,t=[],l){let a=l==null?void 0:l.state;if(e==null){if(!a)return null;if(a.errors)e=a.matches;else if(t.length===0&&!a.initialized&&a.matches.length>0)e=a.matches;else return null}let n=e,u=a==null?void 0:a.errors;if(u!=null){let h=n.findIndex(y=>y.route.id&&(u==null?void 0:u[y.route.id])!==void 0);ae(h>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(u).join(",")}`),n=n.slice(0,Math.min(n.length,h+1))}let i=!1,c=-1;if(l&&a){i=a.renderFallback;for(let h=0;h<n.length;h++){let y=n[h];if((y.route.HydrateFallback||y.route.hydrateFallbackElement)&&(c=h),y.route.id){let{loaderData:o,errors:v}=a,S=y.route.loader&&!o.hasOwnProperty(y.route.id)&&(!v||v[y.route.id]===void 0);if(y.route.lazy||S){l.isStatic&&(i=!0),c>=0?n=n.slice(0,c+1):n=[n[0]];break}}}}let f=l==null?void 0:l.onError,r=a&&f?(h,y)=>{var o,v;f(h,{location:a.location,params:((v=(o=a.matches)==null?void 0:o[0])==null?void 0:v.params)??{},pattern:Wv(a.matches),errorInfo:y})}:void 0;return n.reduceRight((h,y,o)=>{let v,S=!1,x=null,E=null;a&&(v=u&&y.route.id?u[y.route.id]:void 0,x=y.route.errorElement||hg,i&&(c<0&&o===0?(Em("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),S=!0,E=null):c===o&&(S=!0,E=y.route.hydrateFallbackElement||null)));let d=t.concat(n.slice(0,o+1)),m=()=>{let g;return v?g=x:S?g=E:y.route.Component?g=p.createElement(y.route.Component,null):y.route.element?g=y.route.element:g=h,p.createElement(yg,{match:y,routeContext:{outlet:h,matches:d,isDataRoute:a!=null},children:g})};return a&&(y.route.ErrorBoundary||y.route.errorElement||o===0)?p.createElement(xm,{location:a.location,revalidation:a.revalidation,component:x,error:v,children:m(),routeContext:{outlet:null,matches:d,isDataRoute:!0},onError:r}):m()},null)}function sf(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function vg(e){let t=p.useContext(Aa);return ae(t,sf(e)),t}function gg(e){let t=p.useContext(mi);return ae(t,sf(e)),t}function Sg(e){let t=p.useContext(ft);return ae(t,sf(e)),t}function ff(e){let t=Sg(e),l=t.matches[t.matches.length-1];return ae(l.route.id,`${e} can only be used on routes that contain a unique "id"`),l.route.id}function bg(){return ff("useRouteId")}function xg(){var a;let e=p.useContext(cf),t=gg("useRouteError"),l=ff("useRouteError");return e!==void 0?e:(a=t.errors)==null?void 0:a[l]}function Eg(){let{router:e}=vg("useNavigate"),t=ff("useNavigate"),l=p.useRef(!1);return gm(()=>{l.current=!0}),p.useCallback(async(n,u={})=>{yt(l.current,vm),l.current&&(typeof n=="number"?await e.navigate(n):await e.navigate(n,{fromRouteId:t,...u}))},[e,t])}var Kr={};function Em(e,t,l){!t&&!Kr[e]&&(Kr[e]=!0,yt(!1,l))}p.memo(jg);function jg({routes:e,manifest:t,future:l,state:a,isStatic:n,onError:u}){return bm(e,void 0,{manifest:t,state:a,isStatic:n,onError:u})}function Ng(e){return rg(e.context)}function Ke(e){ae(!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 Tg({basename:e="/",children:t=null,location:l,navigationType:a="POP",navigator:n,static:u=!1,useTransitions:i}){ae(!za(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let c=e.replace(/^\/*/,"/"),f=p.useMemo(()=>({basename:c,navigator:n,static:u,useTransitions:i,future:{}}),[c,n,u,i]);typeof l=="string"&&(l=Ta(l));let{pathname:r="/",search:h="",hash:y="",state:o=null,key:v="default",mask:S}=l,x=p.useMemo(()=>{let E=Yt(r,c);return E==null?null:{location:{pathname:E,search:h,hash:y,state:o,key:v,mask:S},navigationType:a}},[c,r,h,y,o,v,a,S]);return yt(x!=null,`<Router basename="${c}"> is not able to match the URL "${r}${h}${y}" because it does not start with the basename, so the <Router> won't render anything.`),x==null?null:p.createElement(at.Provider,{value:f},p.createElement(Dn.Provider,{children:t,value:x}))}function Ag({children:e,location:t}){return og(ls(e),t)}function ls(e,t=[]){let l=[];return p.Children.forEach(e,(a,n)=>{if(!p.isValidElement(a))return;let u=[...t,n];if(a.type===p.Fragment){l.push.apply(l,ls(a.props.children,u));return}ae(a.type===Ke,`[${typeof a.type=="string"?a.type:a.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`),ae(!a.props.index||!a.props.children,"An index route cannot have child routes.");let i={id:a.props.id||u.join("-"),caseSensitive:a.props.caseSensitive,element:a.props.element,Component:a.props.Component,index:a.props.index,path:a.props.path,middleware:a.props.middleware,loader:a.props.loader,action:a.props.action,hydrateFallbackElement:a.props.hydrateFallbackElement,HydrateFallback:a.props.HydrateFallback,errorElement:a.props.errorElement,ErrorBoundary:a.props.ErrorBoundary,hasErrorBoundary:a.props.hasErrorBoundary===!0||a.props.ErrorBoundary!=null||a.props.errorElement!=null,shouldRevalidate:a.props.shouldRevalidate,handle:a.props.handle,lazy:a.props.lazy};a.props.children&&(i.children=ls(a.props.children,u)),l.push(i)}),l}var pu="get",vu="application/x-www-form-urlencoded";function yi(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement}function zg(e){return yi(e)&&e.tagName.toLowerCase()==="button"}function Cg(e){return yi(e)&&e.tagName.toLowerCase()==="form"}function _g(e){return yi(e)&&e.tagName.toLowerCase()==="input"}function Og(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function Rg(e,t){return e.button===0&&(!t||t==="_self")&&!Og(e)}var Pn=null;function Dg(){if(Pn===null)try{new FormData(document.createElement("form"),0),Pn=!1}catch{Pn=!0}return Pn}var Mg=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function nc(e){return e!=null&&!Mg.has(e)?(yt(!1,`"${e}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${vu}"`),null):e}function Ug(e,t){let l,a,n,u,i;if(Cg(e)){let c=e.getAttribute("action");a=c?Yt(c,t):null,l=e.getAttribute("method")||pu,n=nc(e.getAttribute("enctype"))||vu,u=new FormData(e)}else if(zg(e)||_g(e)&&(e.type==="submit"||e.type==="image")){let c=e.form;if(c==null)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let f=e.getAttribute("formaction")||c.getAttribute("action");if(a=f?Yt(f,t):null,l=e.getAttribute("formmethod")||c.getAttribute("method")||pu,n=nc(e.getAttribute("formenctype"))||nc(c.getAttribute("enctype"))||vu,u=new FormData(c,e),!Dg()){let{name:r,type:h,value:y}=e;if(h==="image"){let o=r?`${r}.`:"";u.append(`${o}x`,"0"),u.append(`${o}y`,"0")}else r&&u.append(r,y)}}else{if(yi(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');l=pu,a=null,n=vu,i=e}return u&&n==="text/plain"&&(i=u,u=void 0),{action:a,method:l.toLowerCase(),encType:n,formData:u,body:i}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function rf(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function jm(e,t,l,a){let n=typeof e=="string"?new URL(e,typeof window>"u"?"server://singlefetch/":window.location.origin):e;return l?n.pathname.endsWith("/")?n.pathname=`${n.pathname}_.${a}`:n.pathname=`${n.pathname}.${a}`:n.pathname==="/"?n.pathname=`_root.${a}`:t&&Yt(n.pathname,t)==="/"?n.pathname=`${Ju(t)}/_root.${a}`:n.pathname=`${Ju(n.pathname)}.${a}`,n}async function Hg(e,t){if(e.id in t)return t[e.id];try{let l=await import(e.module);return t[e.id]=l,l}catch(l){return console.error(`Error loading route module \`${e.module}\`, reloading page...`),console.error(l),window.__reactRouterContext&&window.__reactRouterContext.isSpaMode,window.location.reload(),new Promise(()=>{})}}function wg(e){return e==null?!1:e.href==null?e.rel==="preload"&&typeof e.imageSrcSet=="string"&&typeof e.imageSizes=="string":typeof e.rel=="string"&&typeof e.href=="string"}async function Bg(e,t,l){let a=await Promise.all(e.map(async n=>{let u=t.routes[n.route.id];if(u){let i=await Hg(u,l);return i.links?i.links():[]}return[]}));return Gg(a.flat(1).filter(wg).filter(n=>n.rel==="stylesheet"||n.rel==="preload").map(n=>n.rel==="stylesheet"?{...n,rel:"prefetch",as:"style"}:{...n,rel:"prefetch"}))}function Jr(e,t,l,a,n,u){let i=(f,r)=>l[r]?f.route.id!==l[r].route.id:!0,c=(f,r)=>{var h;return l[r].pathname!==f.pathname||((h=l[r].route.path)==null?void 0:h.endsWith("*"))&&l[r].params["*"]!==f.params["*"]};return u==="assets"?t.filter((f,r)=>i(f,r)||c(f,r)):u==="data"?t.filter((f,r)=>{var y;let h=a.routes[f.route.id];if(!h||!h.hasLoader)return!1;if(i(f,r)||c(f,r))return!0;if(f.route.shouldRevalidate){let o=f.route.shouldRevalidate({currentUrl:new URL(n.pathname+n.search+n.hash,window.origin),currentParams:((y=l[0])==null?void 0:y.params)||{},nextUrl:new URL(e,window.origin),nextParams:f.params,defaultShouldRevalidate:!0});if(typeof o=="boolean")return o}return!0}):[]}function Lg(e,t,{includeHydrateFallback:l}={}){return Yg(e.map(a=>{let n=t.routes[a.route.id];if(!n)return[];let u=[n.module];return n.clientActionModule&&(u=u.concat(n.clientActionModule)),n.clientLoaderModule&&(u=u.concat(n.clientLoaderModule)),l&&n.hydrateFallbackModule&&(u=u.concat(n.hydrateFallbackModule)),n.imports&&(u=u.concat(n.imports)),u}).flat(1))}function Yg(e){return[...new Set(e)]}function qg(e){let t={},l=Object.keys(e).sort();for(let a of l)t[a]=e[a];return t}function Gg(e,t){let l=new Set;return new Set(t),e.reduce((a,n)=>{let u=JSON.stringify(qg(n));return l.has(u)||(l.add(u),a.push({key:u,link:n})),a},[])}function of(){let e=p.useContext(Aa);return rf(e,"You must render this element inside a <DataRouterContext.Provider> element"),e}function Xg(){let e=p.useContext(mi);return rf(e,"You must render this element inside a <DataRouterStateContext.Provider> element"),e}var df=p.createContext(void 0);df.displayName="FrameworkContext";function pi(){let e=p.useContext(df);return rf(e,"You must render this element inside a <HydratedRouter> element"),e}function Qg(e,t){let l=p.useContext(df),[a,n]=p.useState(!1),[u,i]=p.useState(!1),{onFocus:c,onBlur:f,onMouseEnter:r,onMouseLeave:h,onTouchStart:y}=t,o=p.useRef(null);p.useEffect(()=>{if(e==="render"&&i(!0),e==="viewport"){let x=d=>{d.forEach(m=>{i(m.isIntersecting)})},E=new IntersectionObserver(x,{threshold:.5});return o.current&&E.observe(o.current),()=>{E.disconnect()}}},[e]),p.useEffect(()=>{if(a){let x=setTimeout(()=>{i(!0)},100);return()=>{clearTimeout(x)}}},[a]);let v=()=>{n(!0)},S=()=>{n(!1),i(!1)};return l?e!=="intent"?[u,o,{}]:[u,o,{onFocus:wa(c,v),onBlur:wa(f,S),onMouseEnter:wa(r,v),onMouseLeave:wa(h,S),onTouchStart:wa(y,v)}]:[!1,o,{}]}function wa(e,t){return l=>{e&&e(l),l.defaultPrevented||t(l)}}function Zg({page:e,...t}){let l=eg(),{nonce:a}=pi(),{router:n}=of(),u=p.useMemo(()=>am(n.routes,e,n.basename),[n.routes,e,n.basename]);return u?(t.nonce==null&&a&&(t={...t,nonce:a}),l?p.createElement(Kg,{page:e,matches:u,...t}):p.createElement(Jg,{page:e,matches:u,...t})):null}function Vg(e){let{manifest:t,routeModules:l}=pi(),[a,n]=p.useState([]);return p.useEffect(()=>{let u=!1;return Bg(e,t,l).then(i=>{u||n(i)}),()=>{u=!0}},[e,t,l]),a}function Kg({page:e,matches:t,...l}){let a=gt(),{future:n}=pi(),{basename:u}=of(),i=p.useMemo(()=>{if(e===a.pathname+a.search+a.hash)return[];let c=jm(e,u,n.v8_trailingSlashAwareDataRequests,"rsc"),f=!1,r=[];for(let h of t)typeof h.route.shouldRevalidate=="function"?f=!0:r.push(h.route.id);return f&&r.length>0&&c.searchParams.set("_routes",r.join(",")),[c.pathname+c.search]},[u,n.v8_trailingSlashAwareDataRequests,e,a,t]);return p.createElement(p.Fragment,null,i.map(c=>p.createElement("link",{key:c,rel:"prefetch",as:"fetch",href:c,...l})))}function Jg({page:e,matches:t,...l}){let a=gt(),{future:n,manifest:u,routeModules:i}=pi(),{basename:c}=of(),{loaderData:f,matches:r}=Xg(),h=p.useMemo(()=>Jr(e,t,r,u,a,"data"),[e,t,r,u,a]),y=p.useMemo(()=>Jr(e,t,r,u,a,"assets"),[e,t,r,u,a]),o=p.useMemo(()=>{if(e===a.pathname+a.search+a.hash)return[];let x=new Set,E=!1;if(t.forEach(m=>{var b;let g=u.routes[m.route.id];!g||!g.hasLoader||(!h.some(A=>A.route.id===m.route.id)&&m.route.id in f&&((b=i[m.route.id])!=null&&b.shouldRevalidate)||g.hasClientLoader?E=!0:x.add(m.route.id))}),x.size===0)return[];let d=jm(e,c,n.v8_trailingSlashAwareDataRequests,"data");return E&&x.size>0&&d.searchParams.set("_routes",t.filter(m=>x.has(m.route.id)).map(m=>m.route.id).join(",")),[d.pathname+d.search]},[c,n.v8_trailingSlashAwareDataRequests,f,a,u,h,t,e,i]),v=p.useMemo(()=>Lg(y,u),[y,u]),S=Vg(y);return p.createElement(p.Fragment,null,o.map(x=>p.createElement("link",{key:x,rel:"prefetch",as:"fetch",href:x,...l})),v.map(x=>p.createElement("link",{key:x,rel:"modulepreload",href:x,...l})),S.map(({key:x,link:E})=>p.createElement("link",{key:x,nonce:l.nonce,...E,crossOrigin:E.crossOrigin??l.crossOrigin})))}function kg(...e){return t=>{e.forEach(l=>{typeof l=="function"?l(t):l!=null&&(l.current=t)})}}var $g=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";try{$g&&(window.__reactRouterVersion="7.18.1")}catch{}function Wg({basename:e,children:t,useTransitions:l,window:a}){let n=p.useRef();n.current==null&&(n.current=zv({window:a,v5Compat:!0}));let u=n.current,[i,c]=p.useState({action:u.action,location:u.location}),f=p.useCallback(r=>{l===!1?c(r):p.startTransition(()=>c(r))},[l]);return p.useLayoutEffect(()=>u.listen(f),[u,f]),p.createElement(Tg,{basename:e,children:t,location:i.location,navigationType:i.action,navigator:u,useTransitions:l})}var ct=p.forwardRef(function({onClick:t,discover:l="render",prefetch:a="none",relative:n,reloadDocument:u,replace:i,mask:c,state:f,target:r,to:h,preventScrollReset:y,viewTransition:o,defaultShouldRevalidate:v,...S},x){let{basename:E,navigator:d,useTransitions:m}=p.useContext(at),g=typeof h=="string"&&nf.test(h),b=dm(h,E);h=b.to;let A=cg(h,{relative:n}),C=gt(),T=null;if(c){let ge=uf(c,[],C.mask?C.mask.pathname:"/",!0);E!=="/"&&(ge.pathname=ge.pathname==="/"?E:it([E,ge.pathname])),T=d.createHref(ge)}let[N,R,O]=Qg(a,S),U=Pg(h,{replace:i,mask:c,state:f,target:r,preventScrollReset:y,relative:n,viewTransition:o,defaultShouldRevalidate:v,useTransitions:m});function Z(ge){t&&t(ge),ge.defaultPrevented||U(ge)}let rt=!(b.isExternal||u),St=p.createElement("a",{...S,...O,href:(rt?T:void 0)||b.absoluteURL||A,onClick:rt?Z:t,ref:kg(x,R),target:r,"data-discover":!g&&l==="render"?"true":void 0});return N&&!g?p.createElement(p.Fragment,null,St,p.createElement(Zg,{page:A})):St});ct.displayName="Link";var At=p.forwardRef(function({"aria-current":t="page",caseSensitive:l=!1,className:a="",end:n=!1,style:u,to:i,viewTransition:c,children:f,...r},h){let y=Mn(i,{relative:r.relative}),o=gt(),v=p.useContext(mi),{navigator:S,basename:x}=p.useContext(at),E=v!=null&&n0(y)&&c===!0,d=S.encodeLocation?S.encodeLocation(y).pathname:y.pathname,m=o.pathname,g=v&&v.navigation&&v.navigation.location?v.navigation.location.pathname:null;l||(m=m.toLowerCase(),g=g?g.toLowerCase():null,d=d.toLowerCase()),g&&x&&(g=Yt(g,x)||g);const b=d!=="/"&&d.endsWith("/")?d.length-1:d.length;let A=m===d||!n&&m.startsWith(d)&&m.charAt(b)==="/",C=g!=null&&(g===d||!n&&g.startsWith(d)&&g.charAt(d.length)==="/"),T={isActive:A,isPending:C,isTransitioning:E},N=A?t:void 0,R;typeof a=="function"?R=a(T):R=[a,A?"active":null,C?"pending":null,E?"transitioning":null].filter(Boolean).join(" ");let O=typeof u=="function"?u(T):u;return p.createElement(ct,{...r,"aria-current":N,className:R,ref:h,style:O,to:i,viewTransition:c},typeof f=="function"?f(T):f)});At.displayName="NavLink";var Fg=p.forwardRef(({discover:e="render",fetcherKey:t,navigate:l,reloadDocument:a,replace:n,state:u,method:i=pu,action:c,onSubmit:f,relative:r,preventScrollReset:h,viewTransition:y,defaultShouldRevalidate:o,...v},S)=>{let{useTransitions:x}=p.useContext(at),E=l0(),d=a0(c,{relative:r}),m=i.toLowerCase()==="get"?"get":"post",g=typeof c=="string"&&nf.test(c),b=A=>{if(f&&f(A),A.defaultPrevented)return;A.preventDefault();let C=A.nativeEvent.submitter,T=(C==null?void 0:C.getAttribute("formmethod"))||i,N=()=>E(C||A.currentTarget,{fetcherKey:t,method:T,navigate:l,replace:n,state:u,relative:r,preventScrollReset:h,viewTransition:y,defaultShouldRevalidate:o});x&&l!==!1?p.startTransition(()=>N()):N()};return p.createElement("form",{ref:S,method:m,action:d,onSubmit:a?f:b,...v,"data-discover":!g&&e==="render"?"true":void 0})});Fg.displayName="Form";function Ig(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Nm(e){let t=p.useContext(Aa);return ae(t,Ig(e)),t}function Pg(e,{target:t,replace:l,mask:a,state:n,preventScrollReset:u,relative:i,viewTransition:c,defaultShouldRevalidate:f,useTransitions:r}={}){let h=Sm(),y=gt(),o=Mn(e,{relative:i});return p.useCallback(v=>{if(Rg(v,t)){v.preventDefault();let S=l!==void 0?l:vn(y)===vn(o),x=()=>h(e,{replace:S,mask:a,state:n,preventScrollReset:u,relative:i,viewTransition:c,defaultShouldRevalidate:f});r?p.startTransition(()=>x()):x()}},[y,h,o,l,a,n,t,e,u,i,c,f,r])}var e0=0,t0=()=>`__${String(++e0)}__`;function l0(){let{router:e}=Nm("useSubmit"),{basename:t}=p.useContext(at),l=bg(),a=e.fetch,n=e.navigate;return p.useCallback(async(u,i={})=>{let{action:c,method:f,encType:r,formData:h,body:y}=Ug(u,t);if(i.navigate===!1){let o=i.fetcherKey||t0();await a(o,l,i.action||c,{defaultShouldRevalidate:i.defaultShouldRevalidate,preventScrollReset:i.preventScrollReset,formData:h,body:y,formMethod:i.method||f,formEncType:i.encType||r,flushSync:i.flushSync})}else await n(i.action||c,{defaultShouldRevalidate:i.defaultShouldRevalidate,preventScrollReset:i.preventScrollReset,formData:h,body:y,formMethod:i.method||f,formEncType:i.encType||r,replace:i.replace,state:i.state,fromRouteId:l,flushSync:i.flushSync,viewTransition:i.viewTransition})},[a,n,t,l])}function a0(e,{relative:t}={}){let{basename:l}=p.useContext(at),a=p.useContext(ft);ae(a,"useFormAction must be used inside a RouteContext");let[n]=a.matches.slice(-1),u={...Mn(e||".",{relative:t})},i=gt();if(e==null){u.search=i.search;let c=new URLSearchParams(u.search),f=c.getAll("index");if(f.some(h=>h==="")){c.delete("index"),f.filter(y=>y).forEach(y=>c.append("index",y));let h=c.toString();u.search=h?`?${h}`:""}}return(!e||e===".")&&n.route.index&&(u.search=u.search?u.search.replace(/^\?/,"?index&"):"?index"),l!=="/"&&(u.pathname=u.pathname==="/"?l:it([l,u.pathname])),vn(u)}function n0(e,{relative:t}={}){let l=p.useContext(ym);ae(l!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:a}=Nm("useViewTransitionState"),n=Mn(e,{relative:t});if(!l.isTransitioning)return!1;let u=Yt(l.currentLocation.pathname,a)||l.currentLocation.pathname,i=Yt(l.nextLocation.pathname,a)||l.nextLocation.pathname;return gn(n.pathname,i)!=null||gn(n.pathname,u)!=null}const Se=async e=>{if(!e.ok)throw new Error((await e.json()).error??e.statusText);return await e.json()},He=async e=>{if(e.ok)return;const t=await e.json().catch(()=>({}));throw new Error(t.error??e.statusText)},B={login:(e,t)=>fetch("/api/login",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:e,password:t})}).then(l=>l.ok),me:()=>fetch("/api/me").then(Se),logout:()=>fetch("/api/logout",{method:"POST"}).then(He),changeOwnPassword:(e,t)=>fetch("/api/account/password",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({current:e,next:t})}).then(He),setAccountName:(e,t)=>fetch("/api/account/name",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({current:e,next:t})}).then(Se),requiredSecrets:e=>fetch(`/api/projects/${e}/required-secrets`).then(Se),revealSecret:(e,t)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}/value`).then(Se),setSecretMasked:(e,t,l)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({masked:l})}).then(He),users:()=>fetch("/api/users").then(Se),setUserProjects:(e,t)=>fetch(`/api/users/${encodeURIComponent(e)}/projects`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({projects:t})}).then(He),createUser:(e,t,l)=>fetch("/api/users",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:e,role:t,password:l})}).then(Se),removeUser:e=>fetch(`/api/users/${encodeURIComponent(e)}`,{method:"DELETE"}).then(He),projects:()=>fetch("/api/projects").then(Se),lanes:e=>fetch(`/api/projects/${e}/lanes`).then(Se),runsOf:e=>fetch(`/api/projects/${e}/runs`).then(Se),run:e=>fetch(`/api/runs/${e}`).then(Se),log:(e,t=0)=>fetch(`/api/runs/${e}/log?from=${t}`).then(l=>l.text()),removeProject:e=>fetch(`/api/projects/${e}?confirm=${encodeURIComponent(e)}`,{method:"DELETE"}).then(Se),secrets:e=>fetch(`/api/projects/${e}/secrets`).then(Se),readiness:e=>fetch(`/api/projects/${e}/readiness`).then(Se),setSecret:(e,t,l,a)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({value:l,masked:a})}).then(He),deleteSecret:(e,t)=>fetch(`/api/projects/${e}/secrets/${encodeURIComponent(t)}`,{method:"DELETE"}).then(He),listCredentials:e=>fetch(`/api/projects/${e}/credentials`).then(Se),putCredential:(e,t,l)=>fetch(`/api/projects/${e}/credentials/${t}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(l)}).then(He),deleteCredential:(e,t)=>fetch(`/api/projects/${e}/credentials/${t}`,{method:"DELETE"}).then(He),fastfile:e=>fetch(`/api/projects/${e}/fastfile`).then(Se),saveFastfile:(e,t)=>fetch(`/api/projects/${e}/fastfile`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({content:t})}).then(He),changes:e=>fetch(`/api/projects/${e}/changes`).then(Se),commit:(e,t)=>fetch(`/api/projects/${e}/commit`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({message:t})}).then(He),push:e=>fetch(`/api/projects/${e}/push`,{method:"POST"}).then(He),trigger:(e,t,l,a)=>fetch(`/api/projects/${e}/runs`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({lane:t,platform:l,params:a})}).then(Se),cancel:e=>fetch(`/api/runs/${e}/cancel`,{method:"POST"}).then(He)};function u0({onSuccess:e}){const[t,l]=p.useState(""),[a,n]=p.useState(""),[u,i]=p.useState(!1),c=async f=>{f.preventDefault(),await B.login(t.trim(),a)?e():i(!0)};return s.jsx("div",{className:"login",children:s.jsxs("form",{className:"panel",onSubmit:f=>void c(f),children:[s.jsx("p",{className:"brand",children:"laneyard"}),s.jsxs("label",{children:["name ",s.jsx("input",{type:"text",value:t,onChange:f=>l(f.target.value),autoFocus:!0,spellCheck:!1,autoComplete:"username"})]}),s.jsxs("label",{children:["password"," ",s.jsx("input",{type:"password",value:a,onChange:f=>n(f.target.value),autoComplete:"current-password"})]}),s.jsx("button",{type:"submit",children:"enter"}),u&&s.jsx("p",{className:"status-failed",children:"incorrect name or password"})]})})}function i0(){const[e,t]=p.useState(()=>localStorage.getItem("laneyard-theme")??"dark");return p.useEffect(()=>{document.documentElement.dataset.theme=e,localStorage.setItem("laneyard-theme",e)},[e]),s.jsx("button",{onClick:()=>t(e==="dark"?"light":"dark"),children:e==="dark"?"paper":"dark"})}function c0(){const e=p.useContext(vi),t=p.useContext(Cm),[l,a]=p.useState(""),[n,u]=p.useState(""),[i,c]=p.useState(""),[f,r]=p.useState(!1),[h,y]=p.useState(null),[o,v]=p.useState(!1),[S,x]=p.useState(""),[E,d]=p.useState(""),[m,g]=p.useState(!1),[b,A]=p.useState(null),[C,T]=p.useState(!1),N=i!==""&&n!==i,R=async U=>{U.preventDefault(),r(!0),y(null);try{await B.changeOwnPassword(l,n),a(""),u(""),c(""),v(!0)}catch(Z){v(!1),y(Z.message)}finally{r(!1)}},O=async U=>{U.preventDefault(),g(!0),A(null);try{await B.setAccountName(S,E),x(""),d(""),T(!0),t()}catch(Z){T(!1),A(Z.message)}finally{g(!1)}};return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"your account"}),s.jsxs("p",{className:"dim",children:["signed in as ",s.jsx("span",{className:"bright",children:e==null?void 0:e.name})," ",s.jsx("span",{className:"dim",children:e==null?void 0:e.role}),". your password and your name are the two things this page changes, and the two things nobody else can change for you."]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"change password"}),s.jsxs("form",{className:"secret-form",onSubmit:U=>void R(U),children:[s.jsx("input",{type:"password",value:l,onChange:U=>a(U.target.value),placeholder:"current password",autoComplete:"current-password","aria-label":"current password"}),s.jsx("input",{type:"password",value:n,onChange:U=>u(U.target.value),placeholder:"new password",autoComplete:"new-password","aria-label":"new password"}),s.jsx("input",{type:"password",value:i,onChange:U=>c(U.target.value),placeholder:"again",autoComplete:"new-password","aria-label":"new password again"}),s.jsx("button",{type:"submit",disabled:f||l===""||n===""||n!==i,children:"change"})]}),N&&s.jsx("p",{className:"status-failed",children:"the two new passwords are not the same."}),s.jsx("p",{className:"dim",children:"the new password is hashed into this machine's config.yml. every other session this account has ends at once — a phone, another browser — and this page stays signed in."}),s.jsx("p",{className:"dim",children:"the current password is asked for even though you are already signed in: a session is a cookie in a browser that may have been left open."}),o&&s.jsxs("p",{children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"dim",children:"password changed."})]}),h&&s.jsxs("p",{className:"status-failed",children:["refused — ",h]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"change your identifier"}),s.jsxs("form",{className:"secret-form",onSubmit:U=>void O(U),children:[s.jsx("input",{type:"password",value:S,onChange:U=>x(U.target.value),placeholder:"current password",autoComplete:"current-password","aria-label":"current password to change name"}),s.jsx("input",{type:"text",value:E,onChange:U=>d(U.target.value),placeholder:"new name",autoComplete:"off","aria-label":"new name"}),s.jsx("button",{type:"submit",disabled:m||S===""||E===""||E===(e==null?void 0:e.name),children:"change"})]}),s.jsx("p",{className:"dim",children:"your name is what you type into the login form. changing it here edits this machine's config.yml and keeps your role and your project access exactly as they were. every other session ends, and this page stays signed in under the new name."}),s.jsx("p",{className:"dim",children:"the current password is asked for here too: a session is a cookie in a browser that may have been left open."}),C&&s.jsxs("p",{children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"dim",children:"name changed."})]}),b&&s.jsxs("p",{className:"status-failed",children:["refused — ",b]})]})}const s0="modulepreload",f0=function(e){return"/"+e},kr={},r0=function(t,l,a){let n=Promise.resolve();if(l&&l.length>0){document.getElementsByTagName("link");const i=document.querySelector("meta[property=csp-nonce]"),c=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));n=Promise.allSettled(l.map(f=>{if(f=f0(f),f in kr)return;kr[f]=!0;const r=f.endsWith(".css"),h=r?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${f}"]${h}`))return;const y=document.createElement("link");if(y.rel=r?"stylesheet":s0,r||(y.as="script"),y.crossOrigin="",y.href=f,c&&y.setAttribute("nonce",c),document.head.appendChild(y),r)return new Promise((o,v)=>{y.addEventListener("load",o),y.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${f}`)))})}))}function u(i){const c=new Event("vite:preloadError",{cancelable:!0});if(c.payload=i,window.dispatchEvent(c),!c.defaultPrevented)throw i}return n.then(i=>{for(const c of i||[])c.status==="rejected"&&u(c.reason);return t().catch(u)})},o0=p.lazy(()=>r0(()=>import("./Editor-CMa4-4N3.js"),[]).then(e=>({default:e.Editor})));function d0(e){return e.startsWith("+++")||e.startsWith("---")||e.startsWith("@@")?"dim":e.startsWith("+")?"status-success":e.startsWith("-")?"status-failed":""}function h0({text:e}){return s.jsx("pre",{className:"diff panel",children:e.split(`
61
61
  `).map((t,l)=>s.jsx("div",{className:d0(t),children:t===""?" ":t},l))})}function m0(){const{slug:e=""}=Hl(),[t,l]=p.useState(null),[a,n]=p.useState(""),[u,i]=p.useState(null),c=p.useRef(null),[f,r]=p.useState(!1),[h,y]=p.useState(!1),[o,v]=p.useState(null),[S,x]=p.useState(null),[E,d]=p.useState(null),[m,g]=p.useState(""),[b,A]=p.useState(!1),[C,T]=p.useState(null),[N,R]=p.useState(null),[O,U]=p.useState(!1),Z=()=>{B.changes(e).then(d).catch(_=>T(_.message))};p.useEffect(()=>{l(null),i(null),r(!1),v(null),x(null),U(!1),g(""),B.fastfile(e).then(_=>{l(_.content),n(_.content)}).catch(_=>i(_.message)),Z()},[e]);const rt=async()=>{var z;const _=(z=c.current)==null?void 0:z.call(c);if(_!==void 0){y(!0),v(null);try{await B.saveFastfile(e,_),n(_),r(!1),x(new Date().toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit"})),Z()}catch(D){v(D.message)}finally{y(!1)}}},St=async()=>{A(!0),T(null),R(null);try{await B.commit(e,m.trim()),g(""),U(!0),R("committed."),Z()}catch(_){T(_.message)}finally{A(!1)}},ge=async()=>{A(!0),T(null),R(null);try{await B.push(e),U(!1),R("pushed.")}catch(_){T(_.message)}finally{A(!1)}};return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"fastfile"}),s.jsx("p",{className:"dim",children:"the file every run of this project builds from. this is a text editor — saving is explicit, and the server parses what you send before it counts."}),u&&s.jsxs("p",{className:"status-failed",children:["unreadable fastfile — ",u]}),s.jsxs("p",{className:"dim editor-bar",children:[s.jsxs("span",{className:"grow",children:[t===null&&!u&&"reading repository…",t!==null&&f&&"unsaved changes",t!==null&&!f&&S&&`saved at ${S}`,t!==null&&!f&&!S&&"unchanged"]}),s.jsx("button",{onClick:()=>void rt(),disabled:h||!f,title:"write and verify",children:h?"verifying…":"save"})]}),o&&s.jsxs("p",{className:"status-failed save-error",children:["not saved — ",o,s.jsx("br",{}),s.jsx("span",{className:"dim",children:"the file on disk is unchanged, and your edits are still in the box below."})]}),t!==null&&s.jsx(p.Suspense,{fallback:s.jsx("div",{className:"editor panel"}),children:s.jsx(o0,{initial:t,baseline:a,read:c,onChange:r,onSave:()=>void rt()})}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"changes"}),E===null&&s.jsx("p",{className:"dim",children:"reading git…"}),E!==null&&E.files.length===0&&s.jsx("p",{className:"dim",children:"nothing uncommitted in this workspace."}),E!==null&&E.files.length>0&&s.jsxs(s.Fragment,{children:[s.jsx("ul",{className:"rows",children:E.files.map(_=>s.jsxs("li",{children:[s.jsx("span",{className:"mark status-running",children:"▸"}),s.jsx("span",{className:"grow",children:_})]},_))}),s.jsx(h0,{text:E.diff})]}),s.jsxs("p",{className:"dim commit-bar",children:[s.jsx("input",{type:"text",value:m,onChange:_=>g(_.target.value),placeholder:"commit message",spellCheck:!1,autoComplete:"off","aria-label":"commit message"}),s.jsx("button",{onClick:()=>void St(),disabled:b||m.trim()===""||((E==null?void 0:E.files.length)??0)===0,children:"commit"}),O&&s.jsx("button",{onClick:()=>void ge(),disabled:b,children:"push"})]}),N&&s.jsx("p",{className:"dim",children:N}),C&&s.jsxs("p",{className:"status-failed",children:["refused — ",C]})]})}const y0={success:"✓",failed:"✗",interrupted:"✗",cancelled:"✗",running:"▸",preparing:"▸",queued:"○"},Sn=e=>y0[e??"queued"]??"○";function p0(e){const t=e%100>=11&&e%100<=13;return`${e}${t?"th":["th","st","nd","rd"][e%10]??"th"}`}function Tm(e,t){return e!=="queued"?e:t===null?"waiting":t===1?"waiting · next in queue":`waiting · ${p0(t)} in queue`}const v0={ok:"✓",warn:"▸",unknown:"○"},$r=e=>v0[e]??"○",Wr=e=>e==="ok"?"status-success":e==="warn"?"status-running":"status-queued",eu=e=>e==="queued"||e==="preparing"||e==="running";function g0(){var T;const{slug:e=""}=Hl(),t=((T=p.useContext(vi))==null?void 0:T.role)==="admin",l=Sm(),[a,n]=p.useState([]),[u,i]=p.useState([]),[c,f]=p.useState(null),[r,h]=p.useState(!0),[y,o]=p.useState(null),[v,S]=p.useState(null),x=Ha("/p/:slug/fastfile")!==null,E=Ha("/p/:slug/secrets")!==null,d=Ha("/p/:slug/signing")!==null,m=Ha("/p/:slug/readiness")!==null,g=Ha("/p/:slug/settings")!==null,b=x||E||d||m||g;p.useEffect(()=>{b||(n([]),f(null),h(!0),B.lanes(e).then(n).catch(N=>f(N.message)).finally(()=>h(!1)),B.runsOf(e).then(i).catch(()=>{}))},[e,b]);const A=async N=>{o(N.name),S(null);try{const{id:R}=await B.trigger(e,N.name,N.platform,{});l(`/r/${R}`)}catch(R){S(R.message),o(null)}},C=s.jsxs("nav",{className:"tabs",children:[s.jsx(At,{to:`/p/${e}`,end:!0,className:({isActive:N})=>N?"current":"",children:"lanes"}),t&&s.jsx(At,{to:`/p/${e}/fastfile`,className:({isActive:N})=>N?"current":"",children:"fastfile"}),t&&s.jsx(At,{to:`/p/${e}/secrets`,className:({isActive:N})=>N?"current":"",children:"secrets"}),t&&s.jsx(At,{to:`/p/${e}/signing`,className:({isActive:N})=>N?"current":"",children:"signing"}),s.jsx(At,{to:`/p/${e}/readiness`,className:({isActive:N})=>N?"current":"",children:"readiness"}),t&&s.jsx(At,{to:`/p/${e}/settings`,className:({isActive:N})=>N?"current":"",children:"settings"})]});return b?s.jsxs(s.Fragment,{children:[C,s.jsx(Ng,{})]}):s.jsxs(s.Fragment,{children:[C,s.jsx("h2",{className:"section",children:"lanes"}),c&&s.jsxs("p",{className:"status-failed",children:["unreadable lanes — ",c]}),r&&s.jsx("p",{className:"dim",children:"reading repository…"}),!r&&!c&&a.filter(N=>!N.private).length===0&&s.jsx("p",{className:"dim",children:"no public lane in this Fastfile."}),s.jsx("ul",{className:"rows",children:a.filter(N=>!N.private).map(N=>s.jsxs("li",{children:[s.jsx("button",{onClick:()=>void A(N),disabled:y!==null,title:"run",children:"▶"}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright",children:N.name})," ",N.platform&&s.jsx("span",{className:"dim",children:N.platform}),N.description&&s.jsx("div",{className:"dim",children:N.description})]})]},`${N.platform??""}:${N.name}`))}),v&&s.jsxs("p",{className:"status-failed",children:["launch refused — ",v]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"runs"}),u.length===0&&s.jsx("p",{className:"dim",children:"no runs yet."}),s.jsx("ul",{className:"rows",children:u.map(N=>s.jsxs("li",{children:[s.jsxs(ct,{to:`/r/${N.id}`,className:"grow",children:[s.jsx("span",{className:`mark status-${N.status}`,children:Sn(N.status)})," ",s.jsxs("span",{className:"dim",children:["#",N.id]})," ",N.lane]}),s.jsx("span",{className:`status-${N.status}`,children:Tm(N.status,N.queuePosition)})]},N.id))})]})}function S0(){const[e,t]=p.useState([]),[l,a]=p.useState(null);return p.useEffect(()=>{B.projects().then(t).catch(n=>a(n.message))},[]),l?s.jsx("p",{className:"status-failed",children:l}):e.length===0?s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"projects"}),s.jsxs("p",{className:"dim",children:["no projects. run ",s.jsx("code",{children:"laneyard setup"})," from a project's folder to declare it."]})]}):s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"projects"}),s.jsx("ul",{className:"projects rows",children:e.map(n=>{var u,i;return s.jsxs("li",{children:[s.jsxs(ct,{to:`/p/${n.slug}`,className:"grow",children:[s.jsx("span",{className:`mark status-${((u=n.lastRun)==null?void 0:u.status)??"queued"}`,children:Sn((i=n.lastRun)==null?void 0:i.status)})," ",n.name]}),n.lastRun&&s.jsxs("span",{className:"dim",children:[" ",n.lastRun.lane]})]},n.slug)})})]})}const b0={all:"always",ios:"ios",android:"android"};function x0(e){const t={ok:0,warn:0,unknown:0};for(const l of(e==null?void 0:e.sections)??[])for(const a of l.checks)t[a.state]=(t[a.state]??0)+1;return t}const E0=[{state:"warn",one:"needs a look",many:"need a look"},{state:"unknown",one:"could not be told",many:"could not be told"},{state:"ok",one:"settled",many:"settled"}],j0=e=>new Date(e).toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit"});function N0(){const{slug:e=""}=Hl(),[t,l]=p.useState(null),[a,n]=p.useState(null),[u,i]=p.useState(!0),c=()=>{i(!0),B.readiness(e).then(r=>{l(r),n(null)}).catch(r=>n(r.message)).finally(()=>i(!1))};p.useEffect(c,[e]);const f=x0(t);return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"readiness"}),s.jsx("p",{className:"dim",children:"what stands between this project and a build that runs while nobody watches. nothing here blocks a run — every line is a warning you decide what to do about."}),s.jsxs("p",{className:"dim",children:[u?"running the checks…":t?`checked at ${j0(t.checkedAt)}`:"not checked yet"," ",s.jsx("button",{onClick:c,disabled:u,title:"run the checks again",children:"refresh"})]}),a&&s.jsxs("p",{className:"status-failed",children:["checklist unavailable — ",a]}),t&&s.jsx("p",{className:"tally",children:E0.map(({state:r,one:h,many:y})=>{const o=f[r]??0;return s.jsxs("span",{className:o===0?"none":void 0,children:[s.jsx("span",{className:`mark ${o===0?"":Wr(r)}`,children:$r(r)})," ",s.jsx("span",{className:o===0?void 0:"bright",children:o})," ",s.jsx("span",{className:"dim",children:o===1?h:y})]},r)})}),((t==null?void 0:t.sections)??[]).map(r=>s.jsxs(p.Fragment,{children:[s.jsx("h2",{className:"section",style:{marginTop:20},children:b0[r.platform]}),s.jsx("ul",{className:"rows checks",children:r.checks.map(h=>s.jsxs("li",{className:`check-${h.state}`,children:[s.jsx("span",{className:`mark ${Wr(h.state)}`,children:$r(h.state)}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright check-title",children:h.title})," ",s.jsx("span",{className:"dim",children:h.detail}),h.fix&&s.jsxs("div",{className:"dim",children:[h.fix,h.fixIn&&s.jsxs(s.Fragment,{children:[" ",s.jsxs(ct,{to:`/p/${e}/${h.fixIn}`,className:"accent",children:[h.fixIn," →"]})]})]})]})]},h.id))})]},r.platform))]})}const T0=/\x1b\[([0-9;]*)m/,A0=/\x1b\][\s\S]*?(?:\x07|\x1b\\)|\x1b\[[0-9;?]*[A-Za-z]|\x1b[()][0-9A-Za-z]|\x1b./g,z0=/[\x00-\x08\x0b-\x1f\x7f]/g,Fr=["black","red","green","yellow","blue","magenta","cyan","white"],C0=e=>[e.fg?`a-${e.fg}`:"",e.bold?"a-bold":"",e.dim?"a-dim":""].filter(Boolean).join(" ");function _0(e,t){const l={...e};for(const a of t.split(";")){const n=Number(a===""?"0":a);n===0?(l.fg=null,l.bold=!1,l.dim=!1):n===1?l.bold=!0:n===2?l.dim=!0:n===22?(l.bold=!1,l.dim=!1):n>=30&&n<=37?l.fg=Fr[n-30]??null:n===39?l.fg=null:n>=90&&n<=97&&(l.fg=`bright-${Fr[n-90]??"white"}`)}return l}function O0(e){const t=[];let l={fg:null,bold:!1,dim:!1},a=e;const n=u=>{if(!u)return;const i=u.replace(A0,"").replace(z0,"");if(!i)return;const c=C0(l),f=t[t.length-1];f&&f.className===c?f.text+=i:t.push({text:i,className:c})};for(;;){const u=T0.exec(a);if(!u)break;n(a.slice(0,u.index)),l=_0(l,u[1]??""),a=a.slice(u.index+u[0].length)}return n(a),t}function R0(e,t){const l=new TextEncoder;let a=0,n=0;for(const u of e.split(`
62
- `)){if(a+=l.encode(u).byteLength+1,a>t)return n;n+=1}return n}function D0({text:e,handle:t,emptyLabel:l="waiting for output…"}){const a=p.useRef(null),[n,u]=p.useState(!0),i=p.useMemo(()=>O0(e),[e]);p.useLayoutEffect(()=>{const f=a.current;f&&n&&(f.scrollTop=f.scrollHeight)},[i,n]),p.useImperativeHandle(t,()=>({scrollToOffset:f=>{const r=a.current;if(!r)return;const h=parseFloat(getComputedStyle(r).lineHeight)||20;u(!1),r.scrollTop=R0(e,f)*h}}));const c=()=>{const f=a.current;f&&u(f.scrollHeight-f.scrollTop-f.clientHeight<8)};return s.jsxs("div",{className:"terminal panel",children:[s.jsxs("div",{className:"pane-title",children:[s.jsx("span",{className:"section",children:"output"}),!n&&s.jsx("span",{className:"dim",children:"following suspended — scroll to bottom to resume"})]}),s.jsxs("pre",{ref:a,onScroll:c,children:[i.map((f,r)=>s.jsx("span",{className:f.className,children:f.text},r)),e===""&&s.jsx("span",{className:"dim",children:l})]}),s.jsxs("div",{className:"terminal-input",children:[s.jsx("span",{className:"prompt",children:"$"}),s.jsx("input",{disabled:!0,value:"",readOnly:!0,"aria-label":"terminal input"}),s.jsx("span",{className:"reason",children:"interactive mode disabled"})]})]})}function M0(e){const[t,l]=p.useState(""),[a,n]=p.useState(null),u=p.useRef(0),i=p.useRef(null);return p.useEffect(()=>{let c=!1,f,r;u.current=0,i.current=null,l(""),n(null);const h=async o=>{const v=await B.log(e,u.current);if(c||!v)return;const S=new TextEncoder().encode(v).byteLength;u.current+S<o||(u.current+=S,l(x=>x+v))},y=async()=>{if(c)return;const o=await B.log(e,u.current);if(c)return;o&&(u.current+=new TextEncoder().encode(o).byteLength,l(S=>S+o));const v=location.protocol==="https:"?"wss":"ws";f=new WebSocket(`${v}://${location.host}/api/runs/${e}/stream`),f.onmessage=S=>{const x=JSON.parse(S.data);if(x.type==="chunk"){if(x.offset<u.current)return;if(x.offset>u.current){h(x.offset);return}u.current=x.offset+new TextEncoder().encode(x.data).byteLength,l(E=>E+x.data)}else i.current=x.status,n(x.status)},f.onclose=()=>{!c&&!i.current&&(r=setTimeout(()=>void y(),1e3))}};return y(),()=>{c=!0,r&&clearTimeout(r),f==null||f.close()}},[e]),{log:t,finished:a}}function U0(e,t){if(!e)return"—";const l=(t?Date.parse(t):Date.now())-Date.parse(e);if(l<0)return"—";const a=Math.floor(l/1e3);return a<60?`${a}s`:`${Math.floor(a/60)}m ${String(a%60).padStart(2,"0")}s`}const H0=e=>e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`;function w0(){const e=Number(Hl().id),[t,l]=p.useState(null),[a,n]=p.useState(null),[u,i]=p.useState(null),[c,f]=p.useState(!1),[,r]=p.useState(0),h=p.useRef(null),{log:y,finished:o}=M0(e);p.useEffect(()=>{let S=!1;const x=()=>B.run(e).then(d=>{S||(l(d),eu(d.status)&&(E=setTimeout(x,1500)))}).catch(d=>n(d.message));let E;return x(),()=>{S=!0,E&&clearTimeout(E)}},[e,o]),p.useEffect(()=>{if(!t||!eu(t.status))return;const S=setInterval(()=>r(x=>x+1),1e3);return()=>clearInterval(S)},[t]);const v=async()=>{f(!0),i(null);try{await B.cancel(e),l(await B.run(e))}catch(S){i(S.message)}finally{f(!1)}};return a?s.jsx("p",{className:"status-failed",children:a}):t?s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"run-head panel",children:[s.jsxs("span",{children:[s.jsx("span",{className:`mark status-${t.status}`,children:Sn(t.status)})," ",s.jsx(ct,{to:`/p/${t.projectSlug}`,className:"dim",children:t.projectSlug})," ",s.jsx("span",{className:"bright",children:t.lane})]}),s.jsxs("span",{className:"dim",children:["run ",s.jsxs("span",{className:"bright",children:["#",t.id]})]}),s.jsxs("span",{className:"dim",children:["branch ",s.jsx("span",{className:"bright",children:t.branch??"—"})]}),s.jsxs("span",{className:"dim",children:["commit ",s.jsx("span",{className:"bright",children:t.commitSha?t.commitSha.slice(0,7):"—"})]}),s.jsxs("span",{className:"dim",children:["duration ",s.jsx("span",{className:"bright",children:U0(t.startedAt,t.finishedAt)})]}),s.jsx("span",{className:`status-${t.status}`,children:Tm(t.status,t.queuePosition)}),eu(t.status)&&s.jsx("button",{onClick:()=>void v(),disabled:c,title:"stop this run",children:"cancel"})]}),u&&s.jsxs("p",{className:"status-failed",children:["cancel refused — ",u]}),t.errorSummary&&s.jsx("p",{className:"status-failed",children:t.errorSummary}),s.jsxs("div",{className:"run-body",children:[s.jsxs("div",{className:"panel",children:[s.jsxs("div",{className:"pane-title",children:[s.jsx("span",{className:"section",children:"steps"}),s.jsx("span",{className:"dim",children:t.steps.length})]}),t.steps.length===0&&s.jsx("p",{className:"dim",style:{padding:"6px 12px"},children:t.status==="queued"?"not started yet":eu(t.status)?"spotting in progress…":"no step recorded"}),s.jsx("ul",{className:"steps",children:t.steps.map(S=>{const x=S.logOffset!==null;return s.jsxs("li",{className:x?"clickable":"inert",title:x?"view in output":"unknown position in output",onClick:x?()=>{var E;return(E=h.current)==null?void 0:E.scrollToOffset(S.logOffset)}:void 0,children:[s.jsx("span",{className:`mark status-${S.status}`,children:Sn(S.status)}),s.jsx("span",{className:"grow",children:S.name}),s.jsx("span",{className:"dim",children:S.durationMs===null?"":`${(S.durationMs/1e3).toFixed(1)}s`})]},S.idx)})})]}),s.jsx(D0,{text:y,handle:h,emptyLabel:t.status==="queued"?"waiting for its turn…":void 0})]}),t.artifacts.length>0&&s.jsxs("div",{className:"panel",style:{marginTop:12},children:[s.jsxs("div",{className:"pane-title",children:[s.jsx("span",{className:"section",children:"artifacts"}),s.jsx("span",{className:"dim",children:t.artifacts.length})]}),s.jsx("ul",{className:"rows",style:{padding:"0 12px"},children:t.artifacts.map(S=>s.jsxs("li",{children:[s.jsxs("a",{className:"grow accent",href:`/api/runs/${t.id}/artifacts/${S.id}`,download:!0,children:["↓ ",S.filename]}),s.jsx("span",{className:"dim",children:S.kind}),s.jsx("span",{className:"dim",children:H0(S.size)})]},S.id))})]})]}):s.jsx("p",{className:"dim",children:"loading…"})}function B0({slug:e,refresh:t,onStored:l}){const[a,n]=p.useState([]),[u,i]=p.useState({}),[c,f]=p.useState(null),[r,h]=p.useState(null);p.useEffect(()=>{B.requiredSecrets(e).then(o=>n(o.missing)).catch(()=>n([]))},[e,t]);const y=async o=>{const v=(u[o]??"").trim();if(v!==""){f(o),h(null);try{await B.setSecret(e,o,v,!0),i(S=>({...S,[o]:""})),l()}catch(S){h(S.message)}finally{f(null)}}};return a.length===0?null:s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",style:{marginTop:20},children:"needed by the lanes"}),s.jsxs("p",{className:"dim",children:["read by a lane, named in ",s.jsx("code",{children:".env.example"}),", or listed under"," ",s.jsx("code",{children:"required_secrets"})," — and not stored yet. type the value; the name is already the one fastlane looks for."]}),s.jsx("ul",{className:"rows needed",children:a.map(o=>s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"needed-name bright",children:o}),s.jsx("input",{type:"password",className:"grow",value:u[o]??"",onChange:v=>i(S=>({...S,[o]:v.target.value})),onKeyDown:v=>{v.key==="Enter"&&y(o)},placeholder:"value",autoComplete:"new-password","aria-label":o}),s.jsx("button",{onClick:()=>void y(o),disabled:c!==null||(u[o]??"").trim()==="",children:"store"})]},o))}),r&&s.jsxs("p",{className:"status-failed",children:["refused — ",r]})]})}function L0(){const{slug:e=""}=Hl(),[t,l]=p.useState([]),[a,n]=p.useState([]),[u,i]=p.useState(null),[c,f]=p.useState(!0),[r,h]=p.useState(0),[y,o]=p.useState(""),[v,S]=p.useState(""),[x,E]=p.useState(!0),[d,m]=p.useState(!1),[g,b]=p.useState(null),A=()=>{f(!0),B.secrets(e).then(z=>{l(z),i(null)}).catch(z=>i(z.message)).finally(()=>f(!1)),B.listCredentials(e).then(n).catch(()=>n([])),h(z=>z+1)};p.useEffect(A,[e]);const C=async z=>{z.preventDefault(),m(!0),b(null);try{await B.setSecret(e,y.trim(),v,x),o(""),S(""),E(!0),A()}catch(D){b(D.message)}finally{m(!1)}},[T,N]=p.useState({}),R=async z=>{b(null);try{const{value:D}=await B.revealSecret(e,z.key);N(W=>({...W,[z.key]:D}))}catch(D){b(D.message)}},O=z=>N(D=>{const W={...D};return delete W[z],W}),U=async z=>{b(null);try{await B.setSecretMasked(e,z.key,!z.masked),z.masked||O(z.key),A()}catch(D){b(D.message)}},Z=async z=>{b(null);try{await B.deleteSecret(e,z.key),A()}catch(D){b(D.message)}},rt=z=>z.key==="APP_STORE_CONNECT_API_KEY_P8"?"nothing reads this. no action in fastlane looks for that name — an earlier version of this interface asked for it, which was our mistake. the .p8 belongs on the signing tab, as an app store connect key block.":z.key==="SUPPLY_JSON_KEY_DATA"&&a.some(D=>D.kind==="play_service_account")?"superseded by the play store service account block on the signing tab. this still works — but the same credential is now stored twice, and nothing says which one a build used.":null,St=z=>{const D=rt(z);return s.jsxs("li",{className:D?"superseded":void 0,children:[s.jsx("span",{className:`mark ${z.masked?"accent":"dim"}`,children:z.masked?"✓":"○"}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright",children:z.key})," ",z.masked?s.jsx("span",{className:"dim",children:"••••••"}):T[z.key]!==void 0?s.jsx("span",{className:"revealed",children:T[z.key]}):s.jsx("span",{className:"dim",children:"stored as it is"}),z.masked&&s.jsx("span",{className:"dim",children:" — kept out of the logs, so never shown here either"}),D&&s.jsx("span",{className:"superseded-note",children:D})]}),z.scope!=="global"&&s.jsxs("label",{className:"row-flag",title:"a secret is removed from build logs, and never shown here",children:[s.jsx("input",{type:"checkbox",checked:z.masked,onChange:()=>void U(z)}),"keep out of the logs"]}),!z.masked&&z.scope!=="global"&&(T[z.key]===void 0?s.jsx("button",{onClick:()=>void R(z),title:"show the value",children:"show"}):s.jsx("button",{onClick:()=>O(z.key),title:"hide it again",children:"hide"})),z.scope==="global"?s.jsx("span",{className:"dim",title:"set for every project — laneyard secret set",children:"global"}):s.jsx("button",{onClick:()=>void Z(z),title:D?"remove this row":"remove",children:D?"remove":"✗"})]},z.key)},ge=t.filter(z=>!z.masked),_=t.filter(z=>z.masked);return s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"dim",children:"the values this project's lanes read. typed here, encrypted at rest, and handed to every run as environment variables."}),s.jsx("h2",{className:"section",style:{marginTop:16},children:"variables"}),s.jsx("p",{className:"dim",children:"stored as they are — printed in the logs, and readable here on request."}),u&&s.jsxs("p",{className:"status-failed",children:["unreadable secrets — ",u]}),c&&s.jsx("p",{className:"dim",children:"reading vault…"}),!c&&!u&&ge.length===0&&s.jsx("p",{className:"dim",children:"nothing stored in the clear."}),s.jsx("ul",{className:"rows",children:ge.map(St)}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"secrets"}),s.jsx("p",{className:"dim",children:"the same variables, kept out of the build logs — and never sent back, not even to this page."}),!c&&!u&&_.length===0&&s.jsx("p",{className:"dim",children:"no secrets yet."}),s.jsx("ul",{className:"rows",children:_.map(St)}),s.jsxs("p",{className:"dim",style:{marginTop:10},children:["a file rather than a value — an app store connect key, a keystore, a play store service account — is stored on its own tab."," ",s.jsx(ct,{to:`/p/${e}/signing`,className:"accent",children:"signing →"})]}),s.jsx(B0,{slug:e,refresh:r,onStored:A}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"add"}),s.jsxs("form",{className:"secret-form",onSubmit:z=>void C(z),children:[s.jsx("input",{type:"text",value:y,onChange:z=>o(z.target.value),placeholder:"MATCH_PASSWORD",spellCheck:!1,autoComplete:"off","aria-label":"name"}),s.jsx("input",{type:"password",value:v,onChange:z=>S(z.target.value),placeholder:"value",autoComplete:"new-password","aria-label":"value"}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:x,onChange:z=>E(z.target.checked)}),"keep this out of the logs"]}),s.jsx("button",{type:"submit",disabled:d||y.trim()===""||v==="",children:"store"})]}),s.jsx("p",{className:"dim",children:"an existing name is replaced."}),g&&s.jsxs("p",{className:"status-failed",children:["refused — ",g]})]})}function Y0(){const{slug:e=""}=Hl(),t=p.useContext(zm),[l,a]=p.useState(null),[n,u]=p.useState(""),[i,c]=p.useState(!1),[f,r]=p.useState(null),[h,y]=p.useState(null),[o,v]=p.useState(null),[S,x]=p.useState(null);p.useEffect(()=>{u(""),r(null),y(null),v(null),x(null),B.projects().then(d=>{var m;return a(((m=d.find(g=>g.slug===e))==null?void 0:m.name)??e)}).catch(()=>a(e)),Promise.all([B.secrets(e),B.listCredentials(e)]).then(([d,m])=>v({secrets:d.filter(g=>g.scope==="project").length,blocks:m.filter(g=>g.scope==="project").length})).catch(()=>v(null)),B.runsOf(e).then(d=>x(d.length)).catch(()=>x(null))},[e]);const E=async d=>{d.preventDefault(),c(!0),r(null);try{const m=await B.removeProject(e);y(m),t()}catch(m){r(m.message)}finally{c(!1)}};if(h){const d=h.removed,m=d.secrets+d.signingBlocks,g=h.untouched.globalSecrets+h.untouched.globalSigningBlocks;return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"removed"}),s.jsxs("p",{children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"bright",children:h.name})," ",s.jsx("span",{className:"dim",children:"and everything laneyard held for it is gone."})]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"what was removed"}),s.jsxs("ul",{className:"rows consequences",children:[s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"grow dim",children:d.runs===0?"no run history: this project never built anything.":s.jsxs(s.Fragment,{children:[s.jsxs("span",{className:"bright",children:[d.runs," ",d.runs===1?"run":"runs"]})," ","and everything they produced — their logs and"," ",d.artifacts===0?"no artifacts":`${d.artifacts} artifact ${d.artifacts===1?"folder":"folders"}`," ","— deleted. this is the part nothing can rebuild."]})})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"grow dim",children:d.workspace?s.jsxs(s.Fragment,{children:["the ",s.jsx("span",{className:"bright",children:"clone"})," is gone from disk."]}):"nothing on disk: this project was never cloned."})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"grow dim",children:m===0?"nothing was in the vault under this name.":s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"bright",children:q0(d)})," forgotten from the vault."]})})]})]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"what was not touched"}),s.jsxs("p",{className:"dim",children:["the ",s.jsx("span",{className:"bright",children:"git remote"})," is untouched — the repository is on your host and your disk, not laneyard's. the ",s.jsx("span",{className:"bright",children:"credential originals"})," ","are untouched — the ",s.jsx("code",{children:".p8"})," and the keystore you uploaded are wherever you keep them; laneyard removed only its own encrypted copy.",g>0&&s.jsxs(s.Fragment,{children:[" ",G0(h)," shared by every project on this machine,"," ",s.jsx("span",{className:"bright",children:"left alone"}),"."]})]}),s.jsx("p",{className:"dim",style:{marginTop:20},children:s.jsx(ct,{to:"/",className:"accent",children:"projects →"})})]})}return s.jsxs("div",{className:"danger",children:[s.jsx("h2",{className:"section",children:"remove this project"}),s.jsxs("p",{className:"irreversible",children:[s.jsx("span",{className:"mark",children:"!"})," this removes everything laneyard holds for"," ",s.jsx("span",{className:"bright",children:l??e})," and cannot be undone. its run history is the one thing nothing can rebuild."]}),s.jsx("p",{className:"dim",children:"what removal takes:"}),s.jsxs("ul",{className:"rows consequences",children:[s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["its"," ",s.jsx("span",{className:"bright",children:S===null?"run history":`${S} ${S===1?"run":"runs"}`})," ","— the rows, their logs and their artifacts. removing a project destroys its past here, and only here."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["the ",s.jsx("span",{className:"bright",children:"clone on disk"}),", if it was ever cloned."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["its"," ",s.jsx("span",{className:"bright",children:o===null?"secrets and signing blocks":`${o.secrets} ${o.secrets===1?"secret":"secrets"} and ${o.blocks} ${o.blocks===1?"signing block":"signing blocks"}`})," ","in the vault — laneyard's own encrypted copies, forgotten. the originals you uploaded are untouched."]})]})]}),s.jsx("p",{className:"dim",style:{marginTop:16},children:"what it does not touch:"}),s.jsxs("ul",{className:"rows consequences",children:[s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["the ",s.jsx("span",{className:"bright",children:"git remote"})," — the repository is on your host and your disk. laneyard neither reads nor writes it."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["the ",s.jsx("span",{className:"bright",children:"credential originals"})," — the ",s.jsx("code",{children:".p8"}),", the keystore. laneyard removes its copy; you would upload them again from wherever you keep them."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["any ",s.jsx("span",{className:"bright",children:"global secrets and signing blocks"})," — shared by every project on this machine, not this one's to take."]})]})]}),s.jsx("p",{className:"dim",style:{marginTop:20},children:"a run in flight holds the workspace: removal is refused until it finishes. a run still waiting in the queue will not start — it ends as failed, saying its project is gone."}),s.jsxs("form",{className:"confirm-form",onSubmit:d=>void E(d),children:[s.jsxs("label",{htmlFor:"confirm-name",className:"dim",children:["type ",s.jsx("span",{className:"bright",children:l??e})," to confirm"]}),s.jsx("input",{id:"confirm-name",type:"text",value:n,onChange:d=>u(d.target.value),spellCheck:!1,autoComplete:"off"}),s.jsx("button",{type:"submit",disabled:i||l===null||n!==l,children:"remove"})]}),f&&s.jsxs("p",{className:"status-failed",children:["refused — ",f]})]})}function q0(e){return Am([ku(e.secrets,"secret"),ku(e.signingBlocks,"signing block")])}function G0(e){const t=Am([ku(e.untouched.globalSecrets,"global secret"),ku(e.untouched.globalSigningBlocks,"global signing block")]),l=e.untouched.globalSecrets+e.untouched.globalSigningBlocks===1;return`${t} ${l?"is":"are"}`}const ku=(e,t)=>e===0?null:`${e} ${e===1?t:`${t}s`}`,Am=e=>e.filter(t=>t!==null).join(" and "),Ir=(e,t)=>{var l;return t==="path"?"the file":((l=e.fields.find(a=>a.name===t))==null?void 0:l.label)??t},X0=e=>{let t="";for(const l of e)t+=String.fromCharCode(l);return btoa(t)};function Q0({slug:e,spec:t,stored:l,open:a,onToggle:n,onChanged:u,onError:i}){const[c,f]=p.useState(null),[r,h]=p.useState(0),[y,o]=p.useState({}),[v,S]=p.useState({}),[x,E]=p.useState(!1),[d,m]=p.useState(!1),g={...t.defaults,...(l==null?void 0:l.varNames)??{},...v},b=l===void 0||x,A=t.fields.every(O=>O.optional||(y[O.name]??"").trim()!==""),C=O=>y[O.name]??O.suggested??"",T=()=>{f(null),h(O=>O+1)},N=async()=>{if(c!==null){m(!0),i(null);try{await B.putCredential(e,t.kind,{fileName:c.name,fileBase64:X0(new Uint8Array(await c.arrayBuffer())),fields:Object.fromEntries(t.fields.map(O=>[O.name,C(O)])),varNames:g}),T(),o({}),S({}),E(!1),u()}catch(O){i(O.message)}finally{m(!1)}}},R=async()=>{i(null);try{await B.deleteCredential(e,t.kind),u()}catch(O){i(O.message)}};return s.jsxs("li",{children:[s.jsxs("button",{type:"button",className:"block-head",onClick:n,"aria-expanded":a,children:[s.jsx("span",{className:`mark ${l?"status-success":"dim"}`,children:l?"✓":"○"}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright",children:t.what})," ",s.jsxs("span",{className:"dim",children:[l?l.fileName:"nothing stored",(l==null?void 0:l.scope)==="global"&&" — set for every project"]})]}),s.jsx("span",{className:"dim",children:a?"close":l?"open":"add"})]}),s.jsxs("div",{className:"block-body",hidden:!a,children:[l&&!b&&s.jsxs(s.Fragment,{children:[t.fields.some(O=>!O.optional)&&s.jsx("div",{className:"dim",children:t.fields.filter(O=>!O.optional).map(O=>`${O.label} ${O.secret?"••••••":"stored"}`).join(" · ")}),s.jsxs("div",{className:"dim",children:["exported as"," ",Object.entries(g).map(([O,U],Z)=>s.jsxs("span",{children:[Z>0&&", ",s.jsx("code",{children:U})]},O))]})]}),b&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"secret-form",children:[c===null?s.jsxs(s.Fragment,{children:[s.jsxs("label",{className:"file-pick",children:[s.jsx("input",{type:"file",accept:t.accept,onChange:O=>{var Z;const U=((Z=O.target.files)==null?void 0:Z[0])??null;U!==null&&(f(U),i(null))}},r),s.jsxs("span",{className:"accent",children:[l?"another file":"choose a file"," →"]})]}),s.jsx("span",{className:"dim",children:t.accept})]}):s.jsxs("span",{className:"file-chosen",children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"bright",children:c.name})," ",s.jsx("span",{className:"dim",children:"read when you store it"})," ",s.jsx("button",{type:"button",onClick:T,title:"choose another file",children:"✗"})]}),t.fields.map(O=>s.jsx("input",{type:O.secret?"password":"text",value:C(O),onChange:U=>o(Z=>({...Z,[O.name]:U.target.value})),placeholder:O.label,"aria-label":O.label,autoComplete:O.secret?"new-password":"off",spellCheck:!1},O.name))]}),s.jsx("div",{className:"dim",children:"reaches the lanes as — change one if your Fastfile reads another name"}),s.jsxs("div",{className:"secret-form",children:[Object.keys(t.defaults).map(O=>s.jsxs("label",{children:[Ir(t,O),s.jsx("input",{type:"text",style:{width:"42ch"},value:g[O]??"",onChange:U=>S(Z=>({...Z,[O]:U.target.value})),"aria-label":`${Ir(t,O)} variable name`,spellCheck:!1,autoComplete:"off"})]},O)),s.jsx("button",{onClick:()=>void N(),disabled:d||c===null||!A,children:"store"}),l&&s.jsx("button",{type:"button",onClick:()=>E(!1),children:"cancel"})]})]}),l&&!b&&s.jsxs("div",{className:"secret-form",children:[s.jsx("button",{type:"button",onClick:()=>E(!0),title:"upload it again",children:"replace"}),l.scope==="global"?s.jsx("span",{className:"dim",title:"set for every project, so not removed from inside one",children:"global"}):s.jsx("button",{onClick:()=>void R(),title:"remove this block",children:"remove"})]})]})]})}const Z0=[{kind:"apple_asc",platform:"ios",what:"app store connect key",accept:".p8",fields:[{name:"key_id",secret:!1,label:"Key ID"},{name:"issuer_id",secret:!1,label:"Issuer ID"}],defaults:{path:"APP_STORE_CONNECT_API_KEY_KEY_FILEPATH",key_id:"APP_STORE_CONNECT_API_KEY_KEY_ID",issuer_id:"APP_STORE_CONNECT_API_KEY_ISSUER_ID"}},{kind:"android_keystore",platform:"android",what:"android upload keystore",accept:".jks,.keystore",fields:[{name:"key_alias",secret:!1,label:"Key alias"},{name:"store_password",secret:!0,label:"Store password"},{name:"key_password",secret:!0,label:"Key password"},{name:"properties_path",secret:!1,optional:!0,label:"Properties file, relative to the app"},{name:"property_names",secret:!1,optional:!0,suggested:"storeFile,storePassword,keyPassword,keyAlias",label:"Names your build reads inside it"}],defaults:{path:"ANDROID_KEYSTORE_PATH",store_password:"ANDROID_KEYSTORE_PASSWORD",key_alias:"ANDROID_KEY_ALIAS",key_password:"ANDROID_KEY_PASSWORD"}},{kind:"play_service_account",platform:"android",what:"play store service account",accept:".json,application/json",fields:[],defaults:{path:"SUPPLY_JSON_KEY"}}],V0=["ios","android"];function K0(){const{slug:e=""}=Hl(),[t,l]=p.useState([]),[a,n]=p.useState(null),[u,i]=p.useState(null),[c,f]=p.useState(!0),r=()=>{f(!0),B.listCredentials(e).then(v=>{l(v),n(null)}).catch(v=>n(v.message)).finally(()=>f(!1))};p.useEffect(r,[e]);const[h,y]=p.useState([]),o=v=>y(S=>S.includes(v)?S.filter(x=>x!==v):[...S,v]);return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"signing"}),s.jsx("p",{className:"dim",children:"the files a lane needs to sign a build or hand it to a store. only the lanes that do that read them — taking screenshots, running tests and syncing certificates need nothing from this screen."}),s.jsx("p",{className:"dim",children:"a block is a file plus the handful of fields that make it usable, stored whole and encrypted. it reaches a run as a path plus the names the block exports."}),a&&s.jsxs("p",{className:"status-failed",children:["unreadable signing blocks — ",a]}),c&&s.jsx("p",{className:"dim",children:"reading vault…"}),V0.map(v=>s.jsxs("div",{className:"credentials-group",children:[s.jsx("p",{className:"dim platform",children:v}),s.jsx("ul",{className:"rows credentials",children:Z0.filter(S=>S.platform===v).map(S=>s.jsx(Q0,{slug:e,spec:S,stored:t.find(x=>x.kind===S.kind),open:h.includes(S.kind),onToggle:()=>o(S.kind),onChanged:r,onError:i},S.kind))})]},v)),u&&s.jsxs("p",{className:"status-failed",children:["refused — ",u]})]})}function J0(){const e=p.useContext(vi),[t,l]=p.useState([]),[a,n]=p.useState([]),[u,i]=p.useState(null),[c,f]=p.useState(!0),[r,h]=p.useState(""),[y,o]=p.useState("builder"),[v,S]=p.useState(""),[x,E]=p.useState(!1),[d,m]=p.useState(null),g=()=>{f(!0),Promise.all([B.users(),B.projects()]).then(([C,T])=>{l(C),n(T),i(null)}).catch(C=>i(C.message)).finally(()=>f(!1))};p.useEffect(g,[]);const b=async C=>{C.preventDefault(),E(!0),m(null);try{await B.createUser(r.trim(),y,v),h(""),S(""),o("builder"),g()}catch(T){m(T.message)}finally{E(!1)}},A=async C=>{m(null);try{await B.removeUser(C.name),g()}catch(T){m(T.message)}};return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"accounts"}),s.jsx("p",{className:"dim",children:"who can sign in to this server. an admin can do everything and reaches every project; a builder starts a build, watches it, cancels it and downloads what it produced — and reaches only the projects it is granted below, and never sees a secret."}),u&&s.jsxs("p",{className:"status-failed",children:["unreadable accounts — ",u]}),c&&s.jsx("p",{className:"dim",children:"reading configuration…"}),s.jsx("ul",{className:"rows",children:t.map(C=>s.jsxs("li",{style:{flexWrap:"wrap"},children:[s.jsx("span",{className:`mark ${C.role==="admin"?"accent":"dim"}`,children:C.role==="admin"?"●":"○"}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright",children:C.name})," ",C.name===(e==null?void 0:e.name)&&s.jsx("span",{className:"dim",children:"you"})]}),s.jsx("span",{className:"dim",children:C.role}),C.name===(e==null?void 0:e.name)?s.jsx(ct,{to:"/account",className:"account-link",children:"your account"}):s.jsx("button",{onClick:()=>void A(C),title:"remove",children:"✗"}),C.role==="builder"&&s.jsx(k0,{account:C,projects:a,onError:m})]},C.name))}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"add"}),s.jsxs("form",{className:"secret-form",onSubmit:C=>void b(C),children:[s.jsx("input",{type:"text",value:r,onChange:C=>h(C.target.value),placeholder:"name",spellCheck:!1,autoComplete:"off","aria-label":"name"}),s.jsxs("select",{value:y,onChange:C=>o(C.target.value),"aria-label":"role",children:[s.jsx("option",{value:"builder",children:"builder"}),s.jsx("option",{value:"admin",children:"admin"})]}),s.jsx("input",{type:"password",value:v,onChange:C=>S(C.target.value),placeholder:"password",autoComplete:"new-password","aria-label":"password"}),s.jsx("button",{type:"submit",disabled:x||r.trim()===""||v==="",children:"create"})]}),s.jsx("p",{className:"dim",children:"the account is written to this machine's config.yml, its password hashed. an existing name is replaced — and its open sessions end. a new builder starts reaching no project until you grant it one."}),s.jsx("p",{className:"dim",children:"removing an account ends its sessions at once. the last admin can be neither removed nor demoted: a server nobody can administer cannot be repaired from here. your own row leads to your account, where you change your password — nobody's password is changed from this page, and another admin is the one who removes you."}),d&&s.jsxs("p",{className:"status-failed",children:["refused — ",d]})]})}function k0({account:e,projects:t,onError:l}){const a=e.projects??t.map(S=>S.slug),[n,u]=p.useState(a),[i,c]=p.useState(a),[f,r]=p.useState(!1),h=S=>i.includes(S),y=S=>c(x=>x.includes(S)?x.filter(E=>E!==S):[...x,S]),o=i.length!==n.length||i.some(S=>!n.includes(S)),v=async()=>{r(!0),l(null);const S=t.map(x=>x.slug).filter(h);try{await B.setUserProjects(e.name,S),u(S)}catch(x){l(x.message)}finally{r(!1)}};return t.length===0?s.jsx("span",{className:"dim",style:{flexBasis:"100%",paddingLeft:"1.5em"},children:"no projects on this server yet."}):s.jsx("div",{style:{flexBasis:"100%",paddingLeft:"1.5em",marginTop:4},children:s.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:"0.25em 1em"},children:[t.map(S=>s.jsxs("label",{className:"dim",style:{display:"flex",alignItems:"center",gap:"0.4em"},children:[s.jsx("input",{type:"checkbox",checked:h(S.slug),onChange:()=>y(S.slug)}),s.jsx("span",{className:h(S.slug)?"bright":"dim",children:S.name})]},S.slug)),o&&s.jsx("button",{onClick:()=>void v(),disabled:f,children:"save"})]})})}const zm=p.createContext(()=>{}),vi=p.createContext(null),Cm=p.createContext(()=>{});function $0(){const[e,t]=p.useState(null),[l,a]=p.useState(!1),[n,u]=p.useState([]),i=()=>B.me().then(async r=>{t(r),u(await B.projects().catch(()=>[]))}).catch(()=>t(null)).finally(()=>a(!0));p.useEffect(()=>{i()},[]);const c=()=>{B.logout().finally(()=>t(null))};if(!l)return s.jsx("p",{className:"dim",children:"loading…"});if(!e)return s.jsx(u0,{onSuccess:()=>void i()});const f=e.role==="admin";return s.jsx(vi.Provider,{value:e,children:s.jsx(Cm.Provider,{value:()=>void i(),children:s.jsx(zm.Provider,{value:()=>void i(),children:s.jsxs("div",{className:"shell",children:[s.jsxs("header",{children:[s.jsx("span",{className:"brand",children:"laneyard"}),s.jsxs("span",{className:"who",children:[s.jsx("span",{className:`mark ${f?"accent":"dim"}`,children:f?"●":"○"}),s.jsx(ct,{to:"/account",className:"bright",children:e.name}),s.jsx("span",{className:"dim",children:e.role}),s.jsx(ct,{to:"/account",className:"account-link",children:"your account"}),s.jsx("button",{onClick:c,children:"sign out"}),s.jsx(i0,{})]})]}),s.jsxs("nav",{children:[s.jsx("p",{className:"section nav-head",children:"projects"}),n.length===0&&s.jsx("p",{className:"dim nav-item",children:"none"}),n.map(r=>{var h,y;return s.jsxs(At,{to:`/p/${r.slug}`,className:({isActive:o})=>`nav-item${o?" current":""}`,children:[s.jsx("span",{className:`mark status-${((h=r.lastRun)==null?void 0:h.status)??"queued"}`,children:Sn((y=r.lastRun)==null?void 0:y.status)})," ",r.name]},r.slug)}),f&&s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"section nav-head",style:{marginTop:16},children:"server"}),s.jsxs(At,{to:"/users",className:({isActive:r})=>`nav-item${r?" current":""}`,children:[s.jsx("span",{className:"mark dim",children:"●"})," accounts"]})]})]}),s.jsx("main",{children:s.jsxs(Ag,{children:[s.jsx(Ke,{path:"/",element:s.jsx(S0,{})}),s.jsxs(Ke,{path:"/p/:slug",element:s.jsx(g0,{}),children:[f&&s.jsx(Ke,{path:"fastfile",element:s.jsx(m0,{})}),f&&s.jsx(Ke,{path:"secrets",element:s.jsx(L0,{})}),f&&s.jsx(Ke,{path:"signing",element:s.jsx(K0,{})}),s.jsx(Ke,{path:"readiness",element:s.jsx(N0,{})}),f&&s.jsx(Ke,{path:"settings",element:s.jsx(Y0,{})})]}),s.jsx(Ke,{path:"/r/:id",element:s.jsx(w0,{})}),s.jsx(Ke,{path:"/account",element:s.jsx(c0,{})}),f&&s.jsx(Ke,{path:"/users",element:s.jsx(J0,{})}),s.jsx(Ke,{path:"*",element:s.jsx("p",{className:"dim",children:"unknown page."})})]})})]})})})})}Tv.createRoot(document.getElementById("root")).render(s.jsx(p.StrictMode,{children:s.jsx(Wg,{children:s.jsx($0,{})})}));export{s as j,p as r};
62
+ `)){if(a+=l.encode(u).byteLength+1,a>t)return n;n+=1}return n}function D0({text:e,handle:t,emptyLabel:l="waiting for output…"}){const a=p.useRef(null),[n,u]=p.useState(!0),i=p.useMemo(()=>O0(e),[e]);p.useLayoutEffect(()=>{const f=a.current;f&&n&&(f.scrollTop=f.scrollHeight)},[i,n]),p.useImperativeHandle(t,()=>({scrollToOffset:f=>{const r=a.current;if(!r)return;const h=parseFloat(getComputedStyle(r).lineHeight)||20;u(!1),r.scrollTop=R0(e,f)*h}}));const c=()=>{const f=a.current;f&&u(f.scrollHeight-f.scrollTop-f.clientHeight<8)};return s.jsxs("div",{className:"terminal panel",children:[s.jsxs("div",{className:"pane-title",children:[s.jsx("span",{className:"section",children:"output"}),!n&&s.jsx("span",{className:"dim",children:"following suspended — scroll to bottom to resume"})]}),s.jsxs("pre",{ref:a,onScroll:c,children:[i.map((f,r)=>s.jsx("span",{className:f.className,children:f.text},r)),e===""&&s.jsx("span",{className:"dim",children:l})]}),s.jsxs("div",{className:"terminal-input",children:[s.jsx("span",{className:"prompt",children:"$"}),s.jsx("input",{disabled:!0,value:"",readOnly:!0,"aria-label":"terminal input"}),s.jsx("span",{className:"reason",children:"interactive mode disabled"})]})]})}function M0(e){const[t,l]=p.useState(""),[a,n]=p.useState(null),u=p.useRef(0),i=p.useRef(null);return p.useEffect(()=>{let c=!1,f,r;u.current=0,i.current=null,l(""),n(null);const h=async o=>{const v=await B.log(e,u.current);if(c||!v)return;const S=new TextEncoder().encode(v).byteLength;u.current+S<o||(u.current+=S,l(x=>x+v))},y=async()=>{if(c)return;const o=await B.log(e,u.current);if(c)return;o&&(u.current+=new TextEncoder().encode(o).byteLength,l(S=>S+o));const v=location.protocol==="https:"?"wss":"ws";f=new WebSocket(`${v}://${location.host}/api/runs/${e}/stream`),f.onmessage=S=>{const x=JSON.parse(S.data);if(x.type==="chunk"){if(x.offset<u.current)return;if(x.offset>u.current){h(x.offset);return}u.current=x.offset+new TextEncoder().encode(x.data).byteLength,l(E=>E+x.data)}else i.current=x.status,n(x.status)},f.onclose=()=>{!c&&!i.current&&(r=setTimeout(()=>void y(),1e3))}};return y(),()=>{c=!0,r&&clearTimeout(r),f==null||f.close()}},[e]),{log:t,finished:a}}function U0(e,t){if(!e)return"—";const l=(t?Date.parse(t):Date.now())-Date.parse(e);if(l<0)return"—";const a=Math.floor(l/1e3);return a<60?`${a}s`:`${Math.floor(a/60)}m ${String(a%60).padStart(2,"0")}s`}const H0=e=>e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`;function w0(){const e=Number(Hl().id),[t,l]=p.useState(null),[a,n]=p.useState(null),[u,i]=p.useState(null),[c,f]=p.useState(!1),[,r]=p.useState(0),h=p.useRef(null),{log:y,finished:o}=M0(e);p.useEffect(()=>{let S=!1;const x=()=>B.run(e).then(d=>{S||(l(d),eu(d.status)&&(E=setTimeout(x,1500)))}).catch(d=>n(d.message));let E;return x(),()=>{S=!0,E&&clearTimeout(E)}},[e,o]),p.useEffect(()=>{if(!t||!eu(t.status))return;const S=setInterval(()=>r(x=>x+1),1e3);return()=>clearInterval(S)},[t]);const v=async()=>{f(!0),i(null);try{await B.cancel(e),l(await B.run(e))}catch(S){i(S.message)}finally{f(!1)}};return a?s.jsx("p",{className:"status-failed",children:a}):t?s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"run-head panel",children:[s.jsxs("span",{children:[s.jsx("span",{className:`mark status-${t.status}`,children:Sn(t.status)})," ",s.jsx(ct,{to:`/p/${t.projectSlug}`,className:"dim",children:t.projectSlug})," ",s.jsx("span",{className:"bright",children:t.lane})]}),s.jsxs("span",{className:"dim",children:["run ",s.jsxs("span",{className:"bright",children:["#",t.id]})]}),s.jsxs("span",{className:"dim",children:["branch ",s.jsx("span",{className:"bright",children:t.branch??"—"})]}),s.jsxs("span",{className:"dim",children:["commit ",s.jsx("span",{className:"bright",children:t.commitSha?t.commitSha.slice(0,7):"—"})]}),s.jsxs("span",{className:"dim",children:["duration ",s.jsx("span",{className:"bright",children:U0(t.startedAt,t.finishedAt)})]}),s.jsx("span",{className:`status-${t.status}`,children:Tm(t.status,t.queuePosition)}),eu(t.status)&&s.jsx("button",{onClick:()=>void v(),disabled:c,title:"stop this run",children:"cancel"})]}),u&&s.jsxs("p",{className:"status-failed",children:["cancel refused — ",u]}),t.errorSummary&&s.jsx("p",{className:"status-failed",children:t.errorSummary}),s.jsxs("div",{className:"run-body",children:[s.jsxs("div",{className:"panel",children:[s.jsxs("div",{className:"pane-title",children:[s.jsx("span",{className:"section",children:"steps"}),s.jsx("span",{className:"dim",children:t.steps.length})]}),t.steps.length===0&&s.jsx("p",{className:"dim",style:{padding:"6px 12px"},children:t.status==="queued"?"not started yet":eu(t.status)?"spotting in progress…":"no step recorded"}),s.jsx("ul",{className:"steps",children:t.steps.map(S=>{const x=S.logOffset!==null;return s.jsxs("li",{className:x?"clickable":"inert",title:x?"view in output":"unknown position in output",onClick:x?()=>{var E;return(E=h.current)==null?void 0:E.scrollToOffset(S.logOffset)}:void 0,children:[s.jsx("span",{className:`mark status-${S.status}`,children:Sn(S.status)}),s.jsx("span",{className:"grow",children:S.name}),s.jsx("span",{className:"dim",children:S.durationMs===null?"":`${(S.durationMs/1e3).toFixed(1)}s`})]},S.idx)})})]}),s.jsx(D0,{text:y,handle:h,emptyLabel:t.status==="queued"?"waiting for its turn…":void 0})]}),t.artifacts.length>0&&s.jsxs("div",{className:"panel",style:{marginTop:12},children:[s.jsxs("div",{className:"pane-title",children:[s.jsx("span",{className:"section",children:"artifacts"}),s.jsx("span",{className:"dim",children:t.artifacts.length})]}),s.jsx("ul",{className:"rows",style:{padding:"0 12px"},children:t.artifacts.map(S=>s.jsxs("li",{children:[s.jsxs("a",{className:"grow accent",href:`/api/runs/${t.id}/artifacts/${S.id}`,download:!0,children:["↓ ",S.filename]}),s.jsx("span",{className:"dim",children:S.kind}),s.jsx("span",{className:"dim",children:H0(S.size)})]},S.id))})]})]}):s.jsx("p",{className:"dim",children:"loading…"})}function B0({slug:e,refresh:t,onStored:l}){const[a,n]=p.useState([]),[u,i]=p.useState({}),[c,f]=p.useState(null),[r,h]=p.useState(null);p.useEffect(()=>{B.requiredSecrets(e).then(o=>n(o.missing)).catch(()=>n([]))},[e,t]);const y=async o=>{const v=(u[o]??"").trim();if(v!==""){f(o),h(null);try{await B.setSecret(e,o,v,!0),i(S=>({...S,[o]:""})),l()}catch(S){h(S.message)}finally{f(null)}}};return a.length===0?null:s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",style:{marginTop:20},children:"needed by the lanes"}),s.jsxs("p",{className:"dim",children:["read by a lane, named in ",s.jsx("code",{children:".env.example"}),", or listed under"," ",s.jsx("code",{children:"required_secrets"})," — and not stored yet. type the value; the name is already the one fastlane looks for."]}),s.jsx("ul",{className:"rows needed",children:a.map(o=>s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"needed-name bright",children:o}),s.jsx("input",{type:"password",className:"grow",value:u[o]??"",onChange:v=>i(S=>({...S,[o]:v.target.value})),onKeyDown:v=>{v.key==="Enter"&&y(o)},placeholder:"value",autoComplete:"new-password","aria-label":o}),s.jsx("button",{onClick:()=>void y(o),disabled:c!==null||(u[o]??"").trim()==="",children:"store"})]},o))}),r&&s.jsxs("p",{className:"status-failed",children:["refused — ",r]})]})}function L0(){const{slug:e=""}=Hl(),[t,l]=p.useState([]),[a,n]=p.useState([]),[u,i]=p.useState(null),[c,f]=p.useState(!0),[r,h]=p.useState(0),[y,o]=p.useState(""),[v,S]=p.useState(""),[x,E]=p.useState(!0),[d,m]=p.useState(!1),[g,b]=p.useState(null),A=()=>{f(!0),B.secrets(e).then(z=>{l(z),i(null)}).catch(z=>i(z.message)).finally(()=>f(!1)),B.listCredentials(e).then(n).catch(()=>n([])),h(z=>z+1)};p.useEffect(A,[e]);const C=async z=>{z.preventDefault(),m(!0),b(null);try{await B.setSecret(e,y.trim(),v,x),o(""),S(""),E(!0),A()}catch(D){b(D.message)}finally{m(!1)}},[T,N]=p.useState({}),R=async z=>{b(null);try{const{value:D}=await B.revealSecret(e,z.key);N(W=>({...W,[z.key]:D}))}catch(D){b(D.message)}},O=z=>N(D=>{const W={...D};return delete W[z],W}),U=async z=>{b(null);try{await B.setSecretMasked(e,z.key,!z.masked),z.masked||O(z.key),A()}catch(D){b(D.message)}},Z=async z=>{b(null);try{await B.deleteSecret(e,z.key),A()}catch(D){b(D.message)}},rt=z=>z.key==="APP_STORE_CONNECT_API_KEY_P8"?"nothing reads this. no action in fastlane looks for that name — an earlier version of this interface asked for it, which was our mistake. the .p8 belongs on the signing tab, as an app store connect key block.":z.key==="SUPPLY_JSON_KEY_DATA"&&a.some(D=>D.kind==="play_service_account")?"superseded by the play store service account block on the signing tab. this still works — but the same credential is now stored twice, and nothing says which one a build used.":null,St=z=>{const D=rt(z);return s.jsxs("li",{className:D?"superseded":void 0,children:[s.jsx("span",{className:`mark ${z.masked?"accent":"dim"}`,children:z.masked?"✓":"○"}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright",children:z.key})," ",z.masked?s.jsx("span",{className:"dim",children:"••••••"}):T[z.key]!==void 0?s.jsx("span",{className:"revealed",children:T[z.key]}):s.jsx("span",{className:"dim",children:"stored as it is"}),z.masked&&s.jsx("span",{className:"dim",children:" — kept out of the logs, so never shown here either"}),D&&s.jsx("span",{className:"superseded-note",children:D})]}),z.scope!=="global"&&s.jsxs("label",{className:"row-flag",title:"a secret is removed from build logs, and never shown here",children:[s.jsx("input",{type:"checkbox",checked:z.masked,onChange:()=>void U(z)}),"keep out of the logs"]}),!z.masked&&z.scope!=="global"&&(T[z.key]===void 0?s.jsx("button",{onClick:()=>void R(z),title:"show the value",children:"show"}):s.jsx("button",{onClick:()=>O(z.key),title:"hide it again",children:"hide"})),z.scope==="global"?s.jsx("span",{className:"dim",title:"set for every project — laneyard secret set",children:"global"}):s.jsx("button",{onClick:()=>void Z(z),title:D?"remove this row":"remove",children:D?"remove":"✗"})]},z.key)},ge=t.filter(z=>!z.masked),_=t.filter(z=>z.masked);return s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"dim",children:"the values this project's lanes read. typed here, encrypted at rest, and handed to every run as environment variables."}),s.jsx("h2",{className:"section",style:{marginTop:16},children:"variables"}),s.jsx("p",{className:"dim",children:"stored as they are — printed in the logs, and readable here on request."}),u&&s.jsxs("p",{className:"status-failed",children:["unreadable secrets — ",u]}),c&&s.jsx("p",{className:"dim",children:"reading vault…"}),!c&&!u&&ge.length===0&&s.jsx("p",{className:"dim",children:"nothing stored in the clear."}),s.jsx("ul",{className:"rows",children:ge.map(St)}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"secrets"}),s.jsx("p",{className:"dim",children:"the same variables, kept out of the build logs — and never sent back, not even to this page."}),!c&&!u&&_.length===0&&s.jsx("p",{className:"dim",children:"no secrets yet."}),s.jsx("ul",{className:"rows",children:_.map(St)}),s.jsxs("p",{className:"dim",style:{marginTop:10},children:["a file rather than a value — an app store connect key, a keystore, a play store service account — is stored on its own tab."," ",s.jsx(ct,{to:`/p/${e}/signing`,className:"accent",children:"signing →"})]}),s.jsx(B0,{slug:e,refresh:r,onStored:A}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"add"}),s.jsxs("form",{className:"secret-form",onSubmit:z=>void C(z),children:[s.jsx("input",{type:"text",value:y,onChange:z=>o(z.target.value),placeholder:"MATCH_PASSWORD",spellCheck:!1,autoComplete:"off","aria-label":"name"}),s.jsx("input",{type:"password",value:v,onChange:z=>S(z.target.value),placeholder:"value",autoComplete:"new-password","aria-label":"value"}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:x,onChange:z=>E(z.target.checked)}),"keep this out of the logs"]}),s.jsx("button",{type:"submit",disabled:d||y.trim()===""||v==="",children:"store"})]}),s.jsx("p",{className:"dim",children:"an existing name is replaced."}),g&&s.jsxs("p",{className:"status-failed",children:["refused — ",g]})]})}function Y0(){const{slug:e=""}=Hl(),t=p.useContext(zm),[l,a]=p.useState(null),[n,u]=p.useState(""),[i,c]=p.useState(!1),[f,r]=p.useState(null),[h,y]=p.useState(null),[o,v]=p.useState(null),[S,x]=p.useState(null);p.useEffect(()=>{u(""),r(null),y(null),v(null),x(null),B.projects().then(d=>{var m;return a(((m=d.find(g=>g.slug===e))==null?void 0:m.name)??e)}).catch(()=>a(e)),Promise.all([B.secrets(e),B.listCredentials(e)]).then(([d,m])=>v({secrets:d.filter(g=>g.scope==="project").length,blocks:m.filter(g=>g.scope==="project").length})).catch(()=>v(null)),B.runsOf(e).then(d=>x(d.length)).catch(()=>x(null))},[e]);const E=async d=>{d.preventDefault(),c(!0),r(null);try{const m=await B.removeProject(e);y(m),t()}catch(m){r(m.message)}finally{c(!1)}};if(h){const d=h.removed,m=d.secrets+d.signingBlocks,g=h.untouched.globalSecrets+h.untouched.globalSigningBlocks;return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"removed"}),s.jsxs("p",{children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"bright",children:h.name})," ",s.jsx("span",{className:"dim",children:"and everything laneyard held for it is gone."})]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"what was removed"}),s.jsxs("ul",{className:"rows consequences",children:[s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"grow dim",children:d.runs===0?"no run history: this project never built anything.":s.jsxs(s.Fragment,{children:[s.jsxs("span",{className:"bright",children:[d.runs," ",d.runs===1?"run":"runs"]})," ","and everything they produced — their logs and"," ",d.artifacts===0?"no artifacts":`${d.artifacts} artifact ${d.artifacts===1?"folder":"folders"}`," ","— deleted. this is the part nothing can rebuild."]})})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"grow dim",children:d.workspace?s.jsxs(s.Fragment,{children:["the ",s.jsx("span",{className:"bright",children:"clone"})," is gone from disk."]}):"nothing on disk: this project was never cloned."})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsx("span",{className:"grow dim",children:m===0?"nothing was in the vault under this name.":s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"bright",children:q0(d)})," forgotten from the vault."]})})]})]}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"what was not touched"}),s.jsxs("p",{className:"dim",children:["the ",s.jsx("span",{className:"bright",children:"git remote"})," is untouched — the repository is on your host, not laneyard's. the ",s.jsx("span",{className:"bright",children:"credential originals"})," are untouched — the ",s.jsx("code",{children:".p8"})," and keystore you uploaded are wherever you keep them; laneyard removed only its own encrypted copy.",g>0&&s.jsxs(s.Fragment,{children:[" ",G0(h)," shared by every project on this machine,"," ",s.jsx("span",{className:"bright",children:"left alone"}),"."]})]}),s.jsx("p",{className:"dim",style:{marginTop:20},children:s.jsx(ct,{to:"/",className:"accent",children:"projects →"})})]})}return s.jsxs("div",{className:"danger",children:[s.jsx("h2",{className:"section",children:"remove this project"}),s.jsxs("p",{className:"irreversible",children:[s.jsx("span",{className:"mark",children:"!"})," this removes everything laneyard holds for"," ",s.jsx("span",{className:"bright",children:l??e})," and cannot be undone. its run history is the one thing nothing can rebuild."]}),s.jsx("p",{className:"dim",children:"what removal takes:"}),s.jsxs("ul",{className:"rows consequences",children:[s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["its"," ",s.jsx("span",{className:"bright",children:S===null?"run history":`${S} ${S===1?"run":"runs"}`})," ","— the rows, their logs and their artifacts. removing a project destroys its past here, and only here."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["the ",s.jsx("span",{className:"bright",children:"clone on disk"}),", if it was ever cloned."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["its"," ",s.jsx("span",{className:"bright",children:o===null?"secrets and signing blocks":`${o.secrets} ${o.secrets===1?"secret":"secrets"} and ${o.blocks} ${o.blocks===1?"signing block":"signing blocks"}`})," ","in the vault — laneyard's own encrypted copies, forgotten. the originals you uploaded are untouched."]})]})]}),s.jsx("p",{className:"dim",style:{marginTop:16},children:"what it does not touch:"}),s.jsxs("ul",{className:"rows consequences",children:[s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["the ",s.jsx("span",{className:"bright",children:"git remote"})," — the repository is on your host and your disk. laneyard neither reads nor writes it."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["the ",s.jsx("span",{className:"bright",children:"credential originals"})," — the ",s.jsx("code",{children:".p8"}),", the keystore. laneyard removes its copy; you would upload them again from wherever you keep them."]})]}),s.jsxs("li",{children:[s.jsx("span",{className:"mark dim",children:"○"}),s.jsxs("span",{className:"grow dim",children:["any ",s.jsx("span",{className:"bright",children:"global secrets and signing blocks"})," — shared by every project on this machine, not this one's to take."]})]})]}),s.jsx("p",{className:"dim",style:{marginTop:20},children:"a run in flight holds the workspace: removal is refused until it finishes. a queued run will not start — it ends as failed, saying its project is gone."}),s.jsxs("form",{className:"confirm-form",onSubmit:d=>void E(d),children:[s.jsxs("label",{htmlFor:"confirm-name",className:"dim",children:["type ",s.jsx("span",{className:"bright",children:l??e})," to confirm"]}),s.jsx("input",{id:"confirm-name",type:"text",value:n,onChange:d=>u(d.target.value),spellCheck:!1,autoComplete:"off"}),s.jsx("button",{type:"submit",disabled:i||l===null||n!==l,children:"remove"})]}),f&&s.jsxs("p",{className:"status-failed",children:["refused — ",f]})]})}function q0(e){return Am([ku(e.secrets,"secret"),ku(e.signingBlocks,"signing block")])}function G0(e){const t=Am([ku(e.untouched.globalSecrets,"global secret"),ku(e.untouched.globalSigningBlocks,"global signing block")]),l=e.untouched.globalSecrets+e.untouched.globalSigningBlocks===1;return`${t} ${l?"is":"are"}`}const ku=(e,t)=>e===0?null:`${e} ${e===1?t:`${t}s`}`,Am=e=>e.filter(t=>t!==null).join(" and "),Ir=(e,t)=>{var l;return t==="path"?"the file":((l=e.fields.find(a=>a.name===t))==null?void 0:l.label)??t},X0=e=>{let t="";for(const l of e)t+=String.fromCharCode(l);return btoa(t)};function Q0({slug:e,spec:t,stored:l,open:a,onToggle:n,onChanged:u,onError:i}){const[c,f]=p.useState(null),[r,h]=p.useState(0),[y,o]=p.useState({}),[v,S]=p.useState({}),[x,E]=p.useState(!1),[d,m]=p.useState(!1),g={...t.defaults,...(l==null?void 0:l.varNames)??{},...v},b=l===void 0||x,A=t.fields.every(O=>O.optional||(y[O.name]??"").trim()!==""),C=O=>y[O.name]??O.suggested??"",T=()=>{f(null),h(O=>O+1)},N=async()=>{if(c!==null){m(!0),i(null);try{await B.putCredential(e,t.kind,{fileName:c.name,fileBase64:X0(new Uint8Array(await c.arrayBuffer())),fields:Object.fromEntries(t.fields.map(O=>[O.name,C(O)])),varNames:g}),T(),o({}),S({}),E(!1),u()}catch(O){i(O.message)}finally{m(!1)}}},R=async()=>{i(null);try{await B.deleteCredential(e,t.kind),u()}catch(O){i(O.message)}};return s.jsxs("li",{children:[s.jsxs("button",{type:"button",className:"block-head",onClick:n,"aria-expanded":a,children:[s.jsx("span",{className:`mark ${l?"status-success":"dim"}`,children:l?"✓":"○"}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright",children:t.what})," ",s.jsxs("span",{className:"dim",children:[l?l.fileName:"nothing stored",(l==null?void 0:l.scope)==="global"&&" — set for every project"]})]}),s.jsx("span",{className:"dim",children:a?"close":l?"open":"add"})]}),s.jsxs("div",{className:"block-body",hidden:!a,children:[l&&!b&&s.jsxs(s.Fragment,{children:[t.fields.some(O=>!O.optional)&&s.jsx("div",{className:"dim",children:t.fields.filter(O=>!O.optional).map(O=>`${O.label} ${O.secret?"••••••":"stored"}`).join(" · ")}),s.jsxs("div",{className:"dim",children:["exported as"," ",Object.entries(g).map(([O,U],Z)=>s.jsxs("span",{children:[Z>0&&", ",s.jsx("code",{children:U})]},O))]})]}),b&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"secret-form",children:[c===null?s.jsxs(s.Fragment,{children:[s.jsxs("label",{className:"file-pick",children:[s.jsx("input",{type:"file",accept:t.accept,onChange:O=>{var Z;const U=((Z=O.target.files)==null?void 0:Z[0])??null;U!==null&&(f(U),i(null))}},r),s.jsxs("span",{className:"accent",children:[l?"another file":"choose a file"," →"]})]}),s.jsx("span",{className:"dim",children:t.accept})]}):s.jsxs("span",{className:"file-chosen",children:[s.jsx("span",{className:"mark accent",children:"✓"})," ",s.jsx("span",{className:"bright",children:c.name})," ",s.jsx("span",{className:"dim",children:"read when you store it"})," ",s.jsx("button",{type:"button",onClick:T,title:"choose another file",children:"✗"})]}),t.fields.map(O=>s.jsx("input",{type:O.secret?"password":"text",value:C(O),onChange:U=>o(Z=>({...Z,[O.name]:U.target.value})),placeholder:O.label,"aria-label":O.label,autoComplete:O.secret?"new-password":"off",spellCheck:!1},O.name))]}),s.jsx("div",{className:"dim",children:"reaches the lanes as — change one if your Fastfile reads another name"}),s.jsxs("div",{className:"secret-form",children:[Object.keys(t.defaults).map(O=>s.jsxs("label",{children:[Ir(t,O),s.jsx("input",{type:"text",style:{width:"42ch"},value:g[O]??"",onChange:U=>S(Z=>({...Z,[O]:U.target.value})),"aria-label":`${Ir(t,O)} variable name`,spellCheck:!1,autoComplete:"off"})]},O)),s.jsx("button",{onClick:()=>void N(),disabled:d||c===null||!A,children:"store"}),l&&s.jsx("button",{type:"button",onClick:()=>E(!1),children:"cancel"})]})]}),l&&!b&&s.jsxs("div",{className:"secret-form",children:[s.jsx("button",{type:"button",onClick:()=>E(!0),title:"upload it again",children:"replace"}),l.scope==="global"?s.jsx("span",{className:"dim",title:"set for every project, so not removed from inside one",children:"global"}):s.jsx("button",{onClick:()=>void R(),title:"remove this block",children:"remove"})]})]})]})}const Z0=[{kind:"apple_asc",platform:"ios",what:"app store connect key",accept:".p8",fields:[{name:"key_id",secret:!1,label:"Key ID"},{name:"issuer_id",secret:!1,label:"Issuer ID"}],defaults:{path:"APP_STORE_CONNECT_API_KEY_KEY_FILEPATH",key_id:"APP_STORE_CONNECT_API_KEY_KEY_ID",issuer_id:"APP_STORE_CONNECT_API_KEY_ISSUER_ID"}},{kind:"android_keystore",platform:"android",what:"android upload keystore",accept:".jks,.keystore",fields:[{name:"key_alias",secret:!1,label:"Key alias"},{name:"store_password",secret:!0,label:"Store password"},{name:"key_password",secret:!0,label:"Key password"},{name:"properties_path",secret:!1,optional:!0,label:"Properties file, relative to the app"},{name:"property_names",secret:!1,optional:!0,suggested:"storeFile,storePassword,keyPassword,keyAlias",label:"Names your build reads inside it"}],defaults:{path:"ANDROID_KEYSTORE_PATH",store_password:"ANDROID_KEYSTORE_PASSWORD",key_alias:"ANDROID_KEY_ALIAS",key_password:"ANDROID_KEY_PASSWORD"}},{kind:"play_service_account",platform:"android",what:"play store service account",accept:".json,application/json",fields:[],defaults:{path:"SUPPLY_JSON_KEY"}}],V0=["ios","android"];function K0(){const{slug:e=""}=Hl(),[t,l]=p.useState([]),[a,n]=p.useState(null),[u,i]=p.useState(null),[c,f]=p.useState(!0),r=()=>{f(!0),B.listCredentials(e).then(v=>{l(v),n(null)}).catch(v=>n(v.message)).finally(()=>f(!1))};p.useEffect(r,[e]);const[h,y]=p.useState([]),o=v=>y(S=>S.includes(v)?S.filter(x=>x!==v):[...S,v]);return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"signing"}),s.jsx("p",{className:"dim",children:"the files a lane needs to sign a build or hand it to a store. only the lanes that do that read them — screenshots, tests and cert syncing need nothing here."}),s.jsx("p",{className:"dim",children:"a block is a file plus the fields that make it usable, stored whole and encrypted. it reaches a run as a path plus the names the block exports."}),a&&s.jsxs("p",{className:"status-failed",children:["unreadable signing blocks — ",a]}),c&&s.jsx("p",{className:"dim",children:"reading vault…"}),V0.map(v=>s.jsxs("div",{className:"credentials-group",children:[s.jsx("p",{className:"dim platform",children:v}),s.jsx("ul",{className:"rows credentials",children:Z0.filter(S=>S.platform===v).map(S=>s.jsx(Q0,{slug:e,spec:S,stored:t.find(x=>x.kind===S.kind),open:h.includes(S.kind),onToggle:()=>o(S.kind),onChanged:r,onError:i},S.kind))})]},v)),u&&s.jsxs("p",{className:"status-failed",children:["refused — ",u]})]})}function J0(){const e=p.useContext(vi),[t,l]=p.useState([]),[a,n]=p.useState([]),[u,i]=p.useState(null),[c,f]=p.useState(!0),[r,h]=p.useState(""),[y,o]=p.useState("builder"),[v,S]=p.useState(""),[x,E]=p.useState(!1),[d,m]=p.useState(null),g=()=>{f(!0),Promise.all([B.users(),B.projects()]).then(([C,T])=>{l(C),n(T),i(null)}).catch(C=>i(C.message)).finally(()=>f(!1))};p.useEffect(g,[]);const b=async C=>{C.preventDefault(),E(!0),m(null);try{await B.createUser(r.trim(),y,v),h(""),S(""),o("builder"),g()}catch(T){m(T.message)}finally{E(!1)}},A=async C=>{m(null);try{await B.removeUser(C.name),g()}catch(T){m(T.message)}};return s.jsxs(s.Fragment,{children:[s.jsx("h2",{className:"section",children:"accounts"}),s.jsx("p",{className:"dim",children:"who can sign in to this server. an admin does everything and reaches every project; a builder starts, watches, cancels and downloads a build, reaches only the projects granted below, and never sees a secret."}),u&&s.jsxs("p",{className:"status-failed",children:["unreadable accounts — ",u]}),c&&s.jsx("p",{className:"dim",children:"reading configuration…"}),s.jsx("ul",{className:"rows",children:t.map(C=>s.jsxs("li",{style:{flexWrap:"wrap"},children:[s.jsx("span",{className:`mark ${C.role==="admin"?"accent":"dim"}`,children:C.role==="admin"?"●":"○"}),s.jsxs("span",{className:"grow",children:[s.jsx("span",{className:"bright",children:C.name})," ",C.name===(e==null?void 0:e.name)&&s.jsx("span",{className:"dim",children:"you"})]}),s.jsx("span",{className:"dim",children:C.role}),C.name===(e==null?void 0:e.name)?s.jsx(ct,{to:"/account",className:"account-link",children:"your account"}):s.jsx("button",{onClick:()=>void A(C),title:"remove",children:"✗"}),C.role==="builder"&&s.jsx(k0,{account:C,projects:a,onError:m})]},C.name))}),s.jsx("h2",{className:"section",style:{marginTop:20},children:"add"}),s.jsxs("form",{className:"secret-form",onSubmit:C=>void b(C),children:[s.jsx("input",{type:"text",value:r,onChange:C=>h(C.target.value),placeholder:"name",spellCheck:!1,autoComplete:"off","aria-label":"name"}),s.jsxs("select",{value:y,onChange:C=>o(C.target.value),"aria-label":"role",children:[s.jsx("option",{value:"builder",children:"builder"}),s.jsx("option",{value:"admin",children:"admin"})]}),s.jsx("input",{type:"password",value:v,onChange:C=>S(C.target.value),placeholder:"password",autoComplete:"new-password","aria-label":"password"}),s.jsx("button",{type:"submit",disabled:x||r.trim()===""||v==="",children:"create"})]}),s.jsx("p",{className:"dim",children:"the account is written to this machine's config.yml, its password hashed. an existing name is replaced — and its open sessions end. a new builder starts reaching no project until you grant it one."}),s.jsx("p",{className:"dim",children:"removing an account ends its sessions at once. the last admin can be neither removed nor demoted: a server nobody can administer cannot be repaired from here. your own row leads to your account, where you change your password — nobody's password is changed from this page, and another admin is the one who removes you."}),d&&s.jsxs("p",{className:"status-failed",children:["refused — ",d]})]})}function k0({account:e,projects:t,onError:l}){const a=e.projects??t.map(S=>S.slug),[n,u]=p.useState(a),[i,c]=p.useState(a),[f,r]=p.useState(!1),h=S=>i.includes(S),y=S=>c(x=>x.includes(S)?x.filter(E=>E!==S):[...x,S]),o=i.length!==n.length||i.some(S=>!n.includes(S)),v=async()=>{r(!0),l(null);const S=t.map(x=>x.slug).filter(h);try{await B.setUserProjects(e.name,S),u(S)}catch(x){l(x.message)}finally{r(!1)}};return t.length===0?s.jsx("span",{className:"dim",style:{flexBasis:"100%",paddingLeft:"1.5em"},children:"no projects on this server yet."}):s.jsx("div",{style:{flexBasis:"100%",paddingLeft:"1.5em",marginTop:4},children:s.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:"0.25em 1em"},children:[t.map(S=>s.jsxs("label",{className:"dim",style:{display:"flex",alignItems:"center",gap:"0.4em"},children:[s.jsx("input",{type:"checkbox",checked:h(S.slug),onChange:()=>y(S.slug)}),s.jsx("span",{className:h(S.slug)?"bright":"dim",children:S.name})]},S.slug)),o&&s.jsx("button",{onClick:()=>void v(),disabled:f,children:"save"})]})})}const zm=p.createContext(()=>{}),vi=p.createContext(null),Cm=p.createContext(()=>{});function $0(){const[e,t]=p.useState(null),[l,a]=p.useState(!1),[n,u]=p.useState([]),i=()=>B.me().then(async r=>{t(r),u(await B.projects().catch(()=>[]))}).catch(()=>t(null)).finally(()=>a(!0));p.useEffect(()=>{i()},[]);const c=()=>{B.logout().finally(()=>t(null))};if(!l)return s.jsx("p",{className:"dim",children:"loading…"});if(!e)return s.jsx(u0,{onSuccess:()=>void i()});const f=e.role==="admin";return s.jsx(vi.Provider,{value:e,children:s.jsx(Cm.Provider,{value:()=>void i(),children:s.jsx(zm.Provider,{value:()=>void i(),children:s.jsxs("div",{className:"shell",children:[s.jsxs("header",{children:[s.jsx("span",{className:"brand",children:"laneyard"}),s.jsxs("span",{className:"who",children:[s.jsx("span",{className:`mark ${f?"accent":"dim"}`,children:f?"●":"○"}),s.jsx(ct,{to:"/account",className:"bright",children:e.name}),s.jsx("span",{className:"dim",children:e.role}),s.jsx(ct,{to:"/account",className:"account-link",children:"your account"}),s.jsx("button",{onClick:c,children:"sign out"}),s.jsx(i0,{})]})]}),s.jsxs("nav",{children:[s.jsx("p",{className:"section nav-head",children:"projects"}),n.length===0&&s.jsx("p",{className:"dim nav-item",children:"none"}),n.map(r=>{var h,y;return s.jsxs(At,{to:`/p/${r.slug}`,className:({isActive:o})=>`nav-item${o?" current":""}`,children:[s.jsx("span",{className:`mark status-${((h=r.lastRun)==null?void 0:h.status)??"queued"}`,children:Sn((y=r.lastRun)==null?void 0:y.status)})," ",r.name]},r.slug)}),f&&s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"section nav-head",style:{marginTop:16},children:"server"}),s.jsxs(At,{to:"/users",className:({isActive:r})=>`nav-item${r?" current":""}`,children:[s.jsx("span",{className:"mark dim",children:"●"})," accounts"]})]})]}),s.jsx("main",{children:s.jsxs(Ag,{children:[s.jsx(Ke,{path:"/",element:s.jsx(S0,{})}),s.jsxs(Ke,{path:"/p/:slug",element:s.jsx(g0,{}),children:[f&&s.jsx(Ke,{path:"fastfile",element:s.jsx(m0,{})}),f&&s.jsx(Ke,{path:"secrets",element:s.jsx(L0,{})}),f&&s.jsx(Ke,{path:"signing",element:s.jsx(K0,{})}),s.jsx(Ke,{path:"readiness",element:s.jsx(N0,{})}),f&&s.jsx(Ke,{path:"settings",element:s.jsx(Y0,{})})]}),s.jsx(Ke,{path:"/r/:id",element:s.jsx(w0,{})}),s.jsx(Ke,{path:"/account",element:s.jsx(c0,{})}),f&&s.jsx(Ke,{path:"/users",element:s.jsx(J0,{})}),s.jsx(Ke,{path:"*",element:s.jsx("p",{className:"dim",children:"unknown page."})})]})})]})})})})}Tv.createRoot(document.getElementById("root")).render(s.jsx(p.StrictMode,{children:s.jsx(Wg,{children:s.jsx($0,{})})}));export{s as j,p as r};
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>laneyard</title>
7
- <script type="module" crossorigin src="/assets/index-CMEreqtd.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-B8lAQPEM.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-DsjxZtsO.css">
9
9
  </head>
10
10
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "laneyard",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "laneyard": "dist/src/main.js"