From 3f22521f49662bb9b503cdee2eae82b381902c99 Mon Sep 17 00:00:00 2001 From: allanice001 Date: Mon, 1 Sep 2025 13:45:09 +0100 Subject: [PATCH] feat: add master keys back --- cmd/cli/keys.go | 85 +++++++++++ internal/db/database.go | 1 + internal/db/models/master-key.go | 10 ++ internal/ui/dist/assets/index-DrmAfy-p.js | 157 +++++++++++++++++++++ internal/ui/dist/assets/index-Nf4c5zdA.css | 1 + ui/src/components/ui/alert-dialog.tsx | 155 ++++++++++++++++++++ ui/src/components/ui/collapsible.tsx | 31 ++++ ui/src/components/ui/dialog.tsx | 141 ++++++++++++++++++ 8 files changed, 581 insertions(+) create mode 100644 cmd/cli/keys.go create mode 100644 internal/db/models/master-key.go create mode 100644 internal/ui/dist/assets/index-DrmAfy-p.js create mode 100644 internal/ui/dist/assets/index-Nf4c5zdA.css create mode 100644 ui/src/components/ui/alert-dialog.tsx create mode 100644 ui/src/components/ui/collapsible.tsx create mode 100644 ui/src/components/ui/dialog.tsx diff --git a/cmd/cli/keys.go b/cmd/cli/keys.go new file mode 100644 index 0000000..c174797 --- /dev/null +++ b/cmd/cli/keys.go @@ -0,0 +1,85 @@ +package cli + +import ( + "crypto/rand" + "encoding/base64" + "fmt" + "io" + + "github.com/glueops/autoglue/internal/db" + "github.com/glueops/autoglue/internal/db/models" + "github.com/spf13/cobra" +) + +var rotateMasterCmd = &cobra.Command{ + Use: "rotate-master", + Short: "Generate and activate a new master encryption key", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + key := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, key); err != nil { + return fmt.Errorf("generating random key: %w", err) + } + + encoded := base64.StdEncoding.EncodeToString(key) + + if err := db.DB.Model(&models.MasterKey{}). + Where("is_active = ?", true). + Update("is_active", false).Error; err != nil { + return fmt.Errorf("deactivating previous key: %w", err) + } + + if err := db.DB.Create(&models.MasterKey{ + Key: encoded, + IsActive: true, + }).Error; err != nil { + return fmt.Errorf("creating new master key: %w", err) + } + + fmt.Println("Master key rotated successfully") + return nil + }, +} + +var createMasterCmd = &cobra.Command{ + Use: "create-master", + Short: "Generate and activate a new master encryption key", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + key := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, key); err != nil { + return fmt.Errorf("generating random key: %w", err) + } + + encoded := base64.StdEncoding.EncodeToString(key) + + if err := db.DB.Create(&models.MasterKey{ + Key: encoded, + IsActive: true, + }).Error; err != nil { + return fmt.Errorf("creating master key: %w", err) + } + + fmt.Println("Master key created successfully") + return nil + }, +} + +var keysCmd = &cobra.Command{ + Use: "keys", + Short: "Manage autoglue encryption keys", + Long: "Manage autoglue master encryption keys used for securing data.", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if db.DB != nil { + return nil + } + db.Connect() + return nil + }, +} + +func init() { + keysCmd.AddCommand(rotateMasterCmd) + keysCmd.AddCommand(createMasterCmd) + rootCmd.AddCommand(keysCmd) +} diff --git a/internal/db/database.go b/internal/db/database.go index 41c4243..fb94414 100644 --- a/internal/db/database.go +++ b/internal/db/database.go @@ -28,6 +28,7 @@ func Connect() { err = DB.AutoMigrate( &models.EmailVerification{}, &models.Invitation{}, + &models.MasterKey{}, &models.Member{}, &models.Organization{}, &models.PasswordReset{}, diff --git a/internal/db/models/master-key.go b/internal/db/models/master-key.go new file mode 100644 index 0000000..cac162a --- /dev/null +++ b/internal/db/models/master-key.go @@ -0,0 +1,10 @@ +package models + +import "github.com/google/uuid" + +type MasterKey struct { + ID uuid.UUID `gorm:"type:uuid;default:gen_random_uuid();primaryKey" json:"id"` + Key string `gorm:"not null"` + IsActive bool `gorm:"default:true"` + Timestamped +} diff --git a/internal/ui/dist/assets/index-DrmAfy-p.js b/internal/ui/dist/assets/index-DrmAfy-p.js new file mode 100644 index 0000000..7fdde25 --- /dev/null +++ b/internal/ui/dist/assets/index-DrmAfy-p.js @@ -0,0 +1,157 @@ +function U1(t,a){for(var l=0;lo[s]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}(function(){const a=document.createElement("link").relList;if(a&&a.supports&&a.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))o(s);new MutationObserver(s=>{for(const c of s)if(c.type==="childList")for(const d of c.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&o(d)}).observe(document,{childList:!0,subtree:!0});function l(s){const c={};return s.integrity&&(c.integrity=s.integrity),s.referrerPolicy&&(c.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?c.credentials="include":s.crossOrigin==="anonymous"?c.credentials="omit":c.credentials="same-origin",c}function o(s){if(s.ep)return;s.ep=!0;const c=l(s);fetch(s.href,c)}})();function ky(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var Zf={exports:{}},Qo={};/** + * @license React + * react-jsx-runtime.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var ev;function L1(){if(ev)return Qo;ev=1;var t=Symbol.for("react.transitional.element"),a=Symbol.for("react.fragment");function l(o,s,c){var d=null;if(c!==void 0&&(d=""+c),s.key!==void 0&&(d=""+s.key),"key"in s){c={};for(var m in s)m!=="key"&&(c[m]=s[m])}else c=s;return s=c.ref,{$$typeof:t,type:o,key:d,ref:s!==void 0?s:null,props:c}}return Qo.Fragment=a,Qo.jsx=l,Qo.jsxs=l,Qo}var tv;function B1(){return tv||(tv=1,Zf.exports=L1()),Zf.exports}var w=B1(),$f={exports:{}},ze={};/** + * @license React + * react.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var nv;function H1(){if(nv)return ze;nv=1;var t=Symbol.for("react.transitional.element"),a=Symbol.for("react.portal"),l=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),s=Symbol.for("react.profiler"),c=Symbol.for("react.consumer"),d=Symbol.for("react.context"),m=Symbol.for("react.forward_ref"),p=Symbol.for("react.suspense"),h=Symbol.for("react.memo"),y=Symbol.for("react.lazy"),g=Symbol.iterator;function S(R){return R===null||typeof R!="object"?null:(R=g&&R[g]||R["@@iterator"],typeof R=="function"?R:null)}var E={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},O=Object.assign,A={};function z(R,F,re){this.props=R,this.context=F,this.refs=A,this.updater=re||E}z.prototype.isReactComponent={},z.prototype.setState=function(R,F){if(typeof R!="object"&&typeof R!="function"&&R!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,R,F,"setState")},z.prototype.forceUpdate=function(R){this.updater.enqueueForceUpdate(this,R,"forceUpdate")};function _(){}_.prototype=z.prototype;function C(R,F,re){this.props=R,this.context=F,this.refs=A,this.updater=re||E}var k=C.prototype=new _;k.constructor=C,O(k,z.prototype),k.isPureReactComponent=!0;var Y=Array.isArray,L={H:null,A:null,T:null,S:null,V:null},te=Object.prototype.hasOwnProperty;function ee(R,F,re,P,ne,fe){return re=fe.ref,{$$typeof:t,type:R,key:F,ref:re!==void 0?re:null,props:fe}}function W(R,F){return ee(R.type,F,void 0,void 0,void 0,R.props)}function ue(R){return typeof R=="object"&&R!==null&&R.$$typeof===t}function Se(R){var F={"=":"=0",":":"=2"};return"$"+R.replace(/[=:]/g,function(re){return F[re]})}var Ee=/\/+/g;function ie(R,F){return typeof R=="object"&&R!==null&&R.key!=null?Se(""+R.key):F.toString(36)}function ce(){}function ye(R){switch(R.status){case"fulfilled":return R.value;case"rejected":throw R.reason;default:switch(typeof R.status=="string"?R.then(ce,ce):(R.status="pending",R.then(function(F){R.status==="pending"&&(R.status="fulfilled",R.value=F)},function(F){R.status==="pending"&&(R.status="rejected",R.reason=F)})),R.status){case"fulfilled":return R.value;case"rejected":throw R.reason}}throw R}function be(R,F,re,P,ne){var fe=typeof R;(fe==="undefined"||fe==="boolean")&&(R=null);var me=!1;if(R===null)me=!0;else switch(fe){case"bigint":case"string":case"number":me=!0;break;case"object":switch(R.$$typeof){case t:case a:me=!0;break;case y:return me=R._init,be(me(R._payload),F,re,P,ne)}}if(me)return ne=ne(R),me=P===""?"."+ie(R,0):P,Y(ne)?(re="",me!=null&&(re=me.replace(Ee,"$&/")+"/"),be(ne,F,re,"",function(Ke){return Ke})):ne!=null&&(ue(ne)&&(ne=W(ne,re+(ne.key==null||R&&R.key===ne.key?"":(""+ne.key).replace(Ee,"$&/")+"/")+me)),F.push(ne)),1;me=0;var Te=P===""?".":P+":";if(Y(R))for(var xe=0;xe"u")throw new Error(a)}function An(t,a){if(!t){typeof console<"u"&&console.warn(a);try{throw new Error(a)}catch{}}}function Z1(){return Math.random().toString(36).substring(2,10)}function lv(t,a){return{usr:t.state,key:t.key,idx:a}}function cd(t,a,l=null,o){return{pathname:typeof t=="string"?t:t.pathname,search:"",hash:"",...typeof a=="string"?ql(a):a,state:l,key:a&&a.key||o||Z1()}}function ri({pathname:t="/",search:a="",hash:l=""}){return a&&a!=="?"&&(t+=a.charAt(0)==="?"?a:"?"+a),l&&l!=="#"&&(t+=l.charAt(0)==="#"?l:"#"+l),t}function ql(t){let a={};if(t){let l=t.indexOf("#");l>=0&&(a.hash=t.substring(l),t=t.substring(0,l));let o=t.indexOf("?");o>=0&&(a.search=t.substring(o),t=t.substring(0,o)),t&&(a.pathname=t)}return a}function $1(t,a,l,o={}){let{window:s=document.defaultView,v5Compat:c=!1}=o,d=s.history,m="POP",p=null,h=y();h==null&&(h=0,d.replaceState({...d.state,idx:h},""));function y(){return(d.state||{idx:null}).idx}function g(){m="POP";let z=y(),_=z==null?null:z-h;h=z,p&&p({action:m,location:A.location,delta:_})}function S(z,_){m="PUSH";let C=cd(A.location,z,_);h=y()+1;let k=lv(C,h),Y=A.createHref(C);try{d.pushState(k,"",Y)}catch(L){if(L instanceof DOMException&&L.name==="DataCloneError")throw L;s.location.assign(Y)}c&&p&&p({action:m,location:A.location,delta:1})}function E(z,_){m="REPLACE";let C=cd(A.location,z,_);h=y();let k=lv(C,h),Y=A.createHref(C);d.replaceState(k,"",Y),c&&p&&p({action:m,location:A.location,delta:0})}function O(z){return Y1(z)}let A={get action(){return m},get location(){return t(s,d)},listen(z){if(p)throw new Error("A history only accepts one active listener");return s.addEventListener(rv,g),p=z,()=>{s.removeEventListener(rv,g),p=null}},createHref(z){return a(s,z)},createURL:O,encodeLocation(z){let _=O(z);return{pathname:_.pathname,search:_.search,hash:_.hash}},push:S,replace:E,go(z){return d.go(z)}};return A}function Y1(t,a=!1){let l="http://localhost";typeof window<"u"&&(l=window.location.origin!=="null"?window.location.origin:window.location.href),tt(l,"No window.location.(origin|href) available to create URL");let o=typeof t=="string"?t:ri(t);return o=o.replace(/ $/,"%20"),!a&&o.startsWith("//")&&(o=l+o),new URL(o,l)}function Ly(t,a,l="/"){return q1(t,a,l,!1)}function q1(t,a,l,o){let s=typeof a=="string"?ql(a):a,c=za(s.pathname||"/",l);if(c==null)return null;let d=By(t);G1(d);let m=null;for(let p=0;m==null&&p{let y={relativePath:h===void 0?d.path||"":h,caseSensitive:d.caseSensitive===!0,childrenIndex:m,route:d};if(y.relativePath.startsWith("/")){if(!y.relativePath.startsWith(o)&&p)return;tt(y.relativePath.startsWith(o),`Absolute route path "${y.relativePath}" nested under path "${o}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),y.relativePath=y.relativePath.slice(o.length)}let g=_a([o,y.relativePath]),S=l.concat(y);d.children&&d.children.length>0&&(tt(d.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${g}".`),By(d.children,a,S,g,p)),!(d.path==null&&!d.index)&&a.push({path:g,score:W1(g,d.index),routesMeta:S})};return t.forEach((d,m)=>{if(d.path===""||!d.path?.includes("?"))c(d,m);else for(let p of Hy(d.path))c(d,m,!0,p)}),a}function Hy(t){let a=t.split("/");if(a.length===0)return[];let[l,...o]=a,s=l.endsWith("?"),c=l.replace(/\?$/,"");if(o.length===0)return s?[c,""]:[c];let d=Hy(o.join("/")),m=[];return m.push(...d.map(p=>p===""?c:[c,p].join("/"))),s&&m.push(...d),m.map(p=>t.startsWith("/")&&p===""?"/":p)}function G1(t){t.sort((a,l)=>a.score!==l.score?l.score-a.score:I1(a.routesMeta.map(o=>o.childrenIndex),l.routesMeta.map(o=>o.childrenIndex)))}var P1=/^:[\w-]+$/,X1=3,F1=2,Q1=1,K1=10,J1=-2,ov=t=>t==="*";function W1(t,a){let l=t.split("/"),o=l.length;return l.some(ov)&&(o+=J1),a&&(o+=F1),l.filter(s=>!ov(s)).reduce((s,c)=>s+(P1.test(c)?X1:c===""?Q1:K1),o)}function I1(t,a){return t.length===a.length&&t.slice(0,-1).every((o,s)=>o===a[s])?t[t.length-1]-a[a.length-1]:0}function eS(t,a,l=!1){let{routesMeta:o}=t,s={},c="/",d=[];for(let m=0;m{if(y==="*"){let O=m[S]||"";d=c.slice(0,c.length-O.length).replace(/(.)\/+$/,"$1")}const E=m[S];return g&&!E?h[y]=void 0:h[y]=(E||"").replace(/%2F/g,"/"),h},{}),pathname:c,pathnameBase:d,pattern:t}}function tS(t,a=!1,l=!0){An(t==="*"||!t.endsWith("*")||t.endsWith("/*"),`Route path "${t}" will be treated as if it were "${t.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${t.replace(/\*$/,"/*")}".`);let o=[],s="^"+t.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(d,m,p)=>(o.push({paramName:m,isOptional:p!=null}),p?"/?([^\\/]+)?":"/([^\\/]+)")).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return t.endsWith("*")?(o.push({paramName:"*"}),s+=t==="*"||t==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):l?s+="\\/*$":t!==""&&t!=="/"&&(s+="(?:(?=\\/|$))"),[new RegExp(s,a?void 0:"i"),o]}function nS(t){try{return t.split("/").map(a=>decodeURIComponent(a).replace(/\//g,"%2F")).join("/")}catch(a){return An(!1,`The URL path "${t}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${a}).`),t}}function za(t,a){if(a==="/")return t;if(!t.toLowerCase().startsWith(a.toLowerCase()))return null;let l=a.endsWith("/")?a.length-1:a.length,o=t.charAt(l);return o&&o!=="/"?null:t.slice(l)||"/"}function aS(t,a="/"){let{pathname:l,search:o="",hash:s=""}=typeof t=="string"?ql(t):t;return{pathname:l?l.startsWith("/")?l:rS(l,a):a,search:iS(o),hash:sS(s)}}function rS(t,a){let l=a.replace(/\/+$/,"").split("/");return t.split("/").forEach(s=>{s===".."?l.length>1&&l.pop():s!=="."&&l.push(s)}),l.length>1?l.join("/"):"/"}function Yf(t,a,l,o){return`Cannot include a '${t}' character in a manually specified \`to.${a}\` field [${JSON.stringify(o)}]. Please separate it out to the \`to.${l}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function lS(t){return t.filter((a,l)=>l===0||a.route.path&&a.route.path.length>0)}function Od(t){let a=lS(t);return a.map((l,o)=>o===a.length-1?l.pathname:l.pathnameBase)}function Dd(t,a,l,o=!1){let s;typeof t=="string"?s=ql(t):(s={...t},tt(!s.pathname||!s.pathname.includes("?"),Yf("?","pathname","search",s)),tt(!s.pathname||!s.pathname.includes("#"),Yf("#","pathname","hash",s)),tt(!s.search||!s.search.includes("#"),Yf("#","search","hash",s)));let c=t===""||s.pathname==="",d=c?"/":s.pathname,m;if(d==null)m=l;else{let g=a.length-1;if(!o&&d.startsWith("..")){let S=d.split("/");for(;S[0]==="..";)S.shift(),g-=1;s.pathname=S.join("/")}m=g>=0?a[g]:"/"}let p=aS(s,m),h=d&&d!=="/"&&d.endsWith("/"),y=(c||d===".")&&l.endsWith("/");return!p.pathname.endsWith("/")&&(h||y)&&(p.pathname+="/"),p}var _a=t=>t.join("/").replace(/\/\/+/g,"/"),oS=t=>t.replace(/\/+$/,"").replace(/^\/*/,"/"),iS=t=>!t||t==="?"?"":t.startsWith("?")?t:"?"+t,sS=t=>!t||t==="#"?"":t.startsWith("#")?t:"#"+t;function uS(t){return t!=null&&typeof t.status=="number"&&typeof t.statusText=="string"&&typeof t.internal=="boolean"&&"data"in t}var Vy=["POST","PUT","PATCH","DELETE"];new Set(Vy);var cS=["GET",...Vy];new Set(cS);var Gl=b.createContext(null);Gl.displayName="DataRouter";var du=b.createContext(null);du.displayName="DataRouterState";b.createContext(!1);var Zy=b.createContext({isTransitioning:!1});Zy.displayName="ViewTransition";var fS=b.createContext(new Map);fS.displayName="Fetchers";var dS=b.createContext(null);dS.displayName="Await";var kn=b.createContext(null);kn.displayName="Navigation";var ui=b.createContext(null);ui.displayName="Location";var Un=b.createContext({outlet:null,matches:[],isDataRoute:!1});Un.displayName="Route";var zd=b.createContext(null);zd.displayName="RouteError";function mS(t,{relative:a}={}){tt(Pl(),"useHref() may be used only in the context of a component.");let{basename:l,navigator:o}=b.useContext(kn),{hash:s,pathname:c,search:d}=ci(t,{relative:a}),m=c;return l!=="/"&&(m=c==="/"?l:_a([l,c])),o.createHref({pathname:m,search:d,hash:s})}function Pl(){return b.useContext(ui)!=null}function Ln(){return tt(Pl(),"useLocation() may be used only in the context of a component."),b.useContext(ui).location}var $y="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Yy(t){b.useContext(kn).static||b.useLayoutEffect(t)}function pr(){let{isDataRoute:t}=b.useContext(Un);return t?CS():hS()}function hS(){tt(Pl(),"useNavigate() may be used only in the context of a component.");let t=b.useContext(Gl),{basename:a,navigator:l}=b.useContext(kn),{matches:o}=b.useContext(Un),{pathname:s}=Ln(),c=JSON.stringify(Od(o)),d=b.useRef(!1);return Yy(()=>{d.current=!0}),b.useCallback((p,h={})=>{if(An(d.current,$y),!d.current)return;if(typeof p=="number"){l.go(p);return}let y=Dd(p,JSON.parse(c),s,h.relative==="path");t==null&&a!=="/"&&(y.pathname=y.pathname==="/"?a:_a([a,y.pathname])),(h.replace?l.replace:l.push)(y,h.state,h)},[a,l,c,s,t])}var pS=b.createContext(null);function gS(t){let a=b.useContext(Un).outlet;return a&&b.createElement(pS.Provider,{value:t},a)}function ci(t,{relative:a}={}){let{matches:l}=b.useContext(Un),{pathname:o}=Ln(),s=JSON.stringify(Od(l));return b.useMemo(()=>Dd(t,JSON.parse(s),o,a==="path"),[t,s,o,a])}function vS(t,a){return qy(t,a)}function qy(t,a,l,o,s){tt(Pl(),"useRoutes() may be used only in the context of a component.");let{navigator:c}=b.useContext(kn),{matches:d}=b.useContext(Un),m=d[d.length-1],p=m?m.params:{},h=m?m.pathname:"/",y=m?m.pathnameBase:"/",g=m&&m.route;{let C=g&&g.path||"";Gy(h,!g||C.endsWith("*")||C.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${h}" (under ) 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. + +Please change the parent to .`)}let S=Ln(),E;if(a){let C=typeof a=="string"?ql(a):a;tt(y==="/"||C.pathname?.startsWith(y),`When overriding the location using \`\` 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 "${y}" but pathname "${C.pathname}" was given in the \`location\` prop.`),E=C}else E=S;let O=E.pathname||"/",A=O;if(y!=="/"){let C=y.replace(/^\//,"").split("/");A="/"+O.replace(/^\//,"").split("/").slice(C.length).join("/")}let z=Ly(t,{pathname:A});An(g||z!=null,`No routes matched location "${E.pathname}${E.search}${E.hash}" `),An(z==null||z[z.length-1].route.element!==void 0||z[z.length-1].route.Component!==void 0||z[z.length-1].route.lazy!==void 0,`Matched leaf route at location "${E.pathname}${E.search}${E.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let _=SS(z&&z.map(C=>Object.assign({},C,{params:Object.assign({},p,C.params),pathname:_a([y,c.encodeLocation?c.encodeLocation(C.pathname).pathname:C.pathname]),pathnameBase:C.pathnameBase==="/"?y:_a([y,c.encodeLocation?c.encodeLocation(C.pathnameBase).pathname:C.pathnameBase])})),d,l,o,s);return a&&_?b.createElement(ui.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",...E},navigationType:"POP"}},_):_}function yS(){let t=RS(),a=uS(t)?`${t.status} ${t.statusText}`:t instanceof Error?t.message:JSON.stringify(t),l=t instanceof Error?t.stack:null,o="rgba(200,200,200, 0.5)",s={padding:"0.5rem",backgroundColor:o},c={padding:"2px 4px",backgroundColor:o},d=null;return console.error("Error handled by React Router default ErrorBoundary:",t),d=b.createElement(b.Fragment,null,b.createElement("p",null,"💿 Hey developer 👋"),b.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",b.createElement("code",{style:c},"ErrorBoundary")," or"," ",b.createElement("code",{style:c},"errorElement")," prop on your route.")),b.createElement(b.Fragment,null,b.createElement("h2",null,"Unexpected Application Error!"),b.createElement("h3",{style:{fontStyle:"italic"}},a),l?b.createElement("pre",{style:s},l):null,d)}var bS=b.createElement(yS,null),xS=class extends b.Component{constructor(t){super(t),this.state={location:t.location,revalidation:t.revalidation,error:t.error}}static getDerivedStateFromError(t){return{error:t}}static getDerivedStateFromProps(t,a){return a.location!==t.location||a.revalidation!=="idle"&&t.revalidation==="idle"?{error:t.error,location:t.location,revalidation:t.revalidation}:{error:t.error!==void 0?t.error:a.error,location:a.location,revalidation:t.revalidation||a.revalidation}}componentDidCatch(t,a){this.props.unstable_onError?this.props.unstable_onError(t,a):console.error("React Router caught the following error during render",t)}render(){return this.state.error!==void 0?b.createElement(Un.Provider,{value:this.props.routeContext},b.createElement(zd.Provider,{value:this.state.error,children:this.props.component})):this.props.children}};function wS({routeContext:t,match:a,children:l}){let o=b.useContext(Gl);return o&&o.static&&o.staticContext&&(a.route.errorElement||a.route.ErrorBoundary)&&(o.staticContext._deepestRenderedBoundaryId=a.route.id),b.createElement(Un.Provider,{value:t},l)}function SS(t,a=[],l=null,o=null,s=null){if(t==null){if(!l)return null;if(l.errors)t=l.matches;else if(a.length===0&&!l.initialized&&l.matches.length>0)t=l.matches;else return null}let c=t,d=l?.errors;if(d!=null){let h=c.findIndex(y=>y.route.id&&d?.[y.route.id]!==void 0);tt(h>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(d).join(",")}`),c=c.slice(0,Math.min(c.length,h+1))}let m=!1,p=-1;if(l)for(let h=0;h=0?c=c.slice(0,p+1):c=[c[0]];break}}}return c.reduceRight((h,y,g)=>{let S,E=!1,O=null,A=null;l&&(S=d&&y.route.id?d[y.route.id]:void 0,O=y.route.errorElement||bS,m&&(p<0&&g===0?(Gy("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),E=!0,A=null):p===g&&(E=!0,A=y.route.hydrateFallbackElement||null)));let z=a.concat(c.slice(0,g+1)),_=()=>{let C;return S?C=O:E?C=A:y.route.Component?C=b.createElement(y.route.Component,null):y.route.element?C=y.route.element:C=h,b.createElement(wS,{match:y,routeContext:{outlet:h,matches:z,isDataRoute:l!=null},children:C})};return l&&(y.route.ErrorBoundary||y.route.errorElement||g===0)?b.createElement(xS,{location:l.location,revalidation:l.revalidation,component:O,error:S,children:_(),routeContext:{outlet:null,matches:z,isDataRoute:!0},unstable_onError:o}):_()},null)}function Nd(t){return`${t} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function ES(t){let a=b.useContext(Gl);return tt(a,Nd(t)),a}function _S(t){let a=b.useContext(du);return tt(a,Nd(t)),a}function AS(t){let a=b.useContext(Un);return tt(a,Nd(t)),a}function Md(t){let a=AS(t),l=a.matches[a.matches.length-1];return tt(l.route.id,`${t} can only be used on routes that contain a unique "id"`),l.route.id}function TS(){return Md("useRouteId")}function RS(){let t=b.useContext(zd),a=_S("useRouteError"),l=Md("useRouteError");return t!==void 0?t:a.errors?.[l]}function CS(){let{router:t}=ES("useNavigate"),a=Md("useNavigate"),l=b.useRef(!1);return Yy(()=>{l.current=!0}),b.useCallback(async(s,c={})=>{An(l.current,$y),l.current&&(typeof s=="number"?t.navigate(s):await t.navigate(s,{fromRouteId:a,...c}))},[t,a])}var iv={};function Gy(t,a,l){!a&&!iv[t]&&(iv[t]=!0,An(!1,l))}b.memo(OS);function OS({routes:t,future:a,state:l,unstable_onError:o}){return qy(t,void 0,l,o,a)}function Py({to:t,replace:a,state:l,relative:o}){tt(Pl()," may be used only in the context of a component.");let{static:s}=b.useContext(kn);An(!s," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:c}=b.useContext(Un),{pathname:d}=Ln(),m=pr(),p=Dd(t,Od(c),d,o==="path"),h=JSON.stringify(p);return b.useEffect(()=>{m(JSON.parse(h),{replace:a,state:l,relative:o})},[m,h,o,a,l]),null}function Xy(t){return gS(t.context)}function _t(t){tt(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function DS({basename:t="/",children:a=null,location:l,navigationType:o="POP",navigator:s,static:c=!1}){tt(!Pl(),"You cannot render a inside another . You should never have more than one in your app.");let d=t.replace(/^\/*/,"/"),m=b.useMemo(()=>({basename:d,navigator:s,static:c,future:{}}),[d,s,c]);typeof l=="string"&&(l=ql(l));let{pathname:p="/",search:h="",hash:y="",state:g=null,key:S="default"}=l,E=b.useMemo(()=>{let O=za(p,d);return O==null?null:{location:{pathname:O,search:h,hash:y,state:g,key:S},navigationType:o}},[d,p,h,y,g,S,o]);return An(E!=null,` is not able to match the URL "${p}${h}${y}" because it does not start with the basename, so the won't render anything.`),E==null?null:b.createElement(kn.Provider,{value:m},b.createElement(ui.Provider,{children:a,value:E}))}function zS({children:t,location:a}){return vS(fd(t),a)}function fd(t,a=[]){let l=[];return b.Children.forEach(t,(o,s)=>{if(!b.isValidElement(o))return;let c=[...a,s];if(o.type===b.Fragment){l.push.apply(l,fd(o.props.children,c));return}tt(o.type===_t,`[${typeof o.type=="string"?o.type:o.type.name}] is not a component. All component children of must be a or `),tt(!o.props.index||!o.props.children,"An index route cannot have child routes.");let d={id:o.props.id||c.join("-"),caseSensitive:o.props.caseSensitive,element:o.props.element,Component:o.props.Component,index:o.props.index,path:o.props.path,loader:o.props.loader,action:o.props.action,hydrateFallbackElement:o.props.hydrateFallbackElement,HydrateFallback:o.props.HydrateFallback,errorElement:o.props.errorElement,ErrorBoundary:o.props.ErrorBoundary,hasErrorBoundary:o.props.hasErrorBoundary===!0||o.props.ErrorBoundary!=null||o.props.errorElement!=null,shouldRevalidate:o.props.shouldRevalidate,handle:o.props.handle,lazy:o.props.lazy};o.props.children&&(d.children=fd(o.props.children,c)),l.push(d)}),l}var Ps="get",Xs="application/x-www-form-urlencoded";function mu(t){return t!=null&&typeof t.tagName=="string"}function NS(t){return mu(t)&&t.tagName.toLowerCase()==="button"}function MS(t){return mu(t)&&t.tagName.toLowerCase()==="form"}function jS(t){return mu(t)&&t.tagName.toLowerCase()==="input"}function kS(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function US(t,a){return t.button===0&&(!a||a==="_self")&&!kS(t)}function dd(t=""){return new URLSearchParams(typeof t=="string"||Array.isArray(t)||t instanceof URLSearchParams?t:Object.keys(t).reduce((a,l)=>{let o=t[l];return a.concat(Array.isArray(o)?o.map(s=>[l,s]):[[l,o]])},[]))}function LS(t,a){let l=dd(t);return a&&a.forEach((o,s)=>{l.has(s)||a.getAll(s).forEach(c=>{l.append(s,c)})}),l}var zs=null;function BS(){if(zs===null)try{new FormData(document.createElement("form"),0),zs=!1}catch{zs=!0}return zs}var HS=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function qf(t){return t!=null&&!HS.has(t)?(An(!1,`"${t}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Xs}"`),null):t}function VS(t,a){let l,o,s,c,d;if(MS(t)){let m=t.getAttribute("action");o=m?za(m,a):null,l=t.getAttribute("method")||Ps,s=qf(t.getAttribute("enctype"))||Xs,c=new FormData(t)}else if(NS(t)||jS(t)&&(t.type==="submit"||t.type==="image")){let m=t.form;if(m==null)throw new Error('Cannot submit a