From b97bdbb6adab0181475c159becb24cf9b4216e59 Mon Sep 17 00:00:00 2001 From: Junhyeong Park Date: Tue, 5 Mar 2024 12:19:05 +0900 Subject: [PATCH 1/4] build folder push --- my-app/.gitignore | 3 - my-app/build/asset-manifest.json | 15 ++ my-app/build/bannerlogo.ico | Bin 0 -> 268286 bytes my-app/build/img/bannerlogo.png | Bin 0 -> 100654 bytes my-app/build/img/choosefile.png | Bin 0 -> 4629 bytes my-app/build/img/complete.png | Bin 0 -> 9270 bytes my-app/build/img/mainlogo.png | Bin 0 -> 1290 bytes my-app/build/img/mainlogo.svg | 7 + my-app/build/img/uploadedfile.png | Bin 0 -> 5744 bytes my-app/build/img/uploadfile.png | Bin 0 -> 5004 bytes my-app/build/index.html | 1 + my-app/build/manifest.json | 15 ++ my-app/build/robots.txt | 3 + my-app/build/static/css/main.d5c25553.css | 4 + my-app/build/static/css/main.d5c25553.css.map | 1 + my-app/build/static/js/787.d4aba7ab.chunk.js | 2 + .../build/static/js/787.d4aba7ab.chunk.js.map | 1 + my-app/build/static/js/main.c90bec40.js | 3 + .../static/js/main.c90bec40.js.LICENSE.txt | 199 ++++++++++++++++++ my-app/build/static/js/main.c90bec40.js.map | 1 + 20 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 my-app/build/asset-manifest.json create mode 100644 my-app/build/bannerlogo.ico create mode 100644 my-app/build/img/bannerlogo.png create mode 100644 my-app/build/img/choosefile.png create mode 100644 my-app/build/img/complete.png create mode 100644 my-app/build/img/mainlogo.png create mode 100644 my-app/build/img/mainlogo.svg create mode 100644 my-app/build/img/uploadedfile.png create mode 100644 my-app/build/img/uploadfile.png create mode 100644 my-app/build/index.html create mode 100644 my-app/build/manifest.json create mode 100644 my-app/build/robots.txt create mode 100644 my-app/build/static/css/main.d5c25553.css create mode 100644 my-app/build/static/css/main.d5c25553.css.map create mode 100644 my-app/build/static/js/787.d4aba7ab.chunk.js create mode 100644 my-app/build/static/js/787.d4aba7ab.chunk.js.map create mode 100644 my-app/build/static/js/main.c90bec40.js create mode 100644 my-app/build/static/js/main.c90bec40.js.LICENSE.txt create mode 100644 my-app/build/static/js/main.c90bec40.js.map diff --git a/my-app/.gitignore b/my-app/.gitignore index 4d29575..8996736 100644 --- a/my-app/.gitignore +++ b/my-app/.gitignore @@ -8,9 +8,6 @@ # testing /coverage -# production -/build - # misc .DS_Store .env.local diff --git a/my-app/build/asset-manifest.json b/my-app/build/asset-manifest.json new file mode 100644 index 0000000..021f81f --- /dev/null +++ b/my-app/build/asset-manifest.json @@ -0,0 +1,15 @@ +{ + "files": { + "main.css": "/static/css/main.d5c25553.css", + "main.js": "/static/js/main.c90bec40.js", + "static/js/787.d4aba7ab.chunk.js": "/static/js/787.d4aba7ab.chunk.js", + "index.html": "/index.html", + "main.d5c25553.css.map": "/static/css/main.d5c25553.css.map", + "main.c90bec40.js.map": "/static/js/main.c90bec40.js.map", + "787.d4aba7ab.chunk.js.map": "/static/js/787.d4aba7ab.chunk.js.map" + }, + "entrypoints": [ + "static/css/main.d5c25553.css", + "static/js/main.c90bec40.js" + ] +} \ No newline at end of file diff --git a/my-app/build/bannerlogo.ico b/my-app/build/bannerlogo.ico new file mode 100644 index 0000000000000000000000000000000000000000..7f46273289e6ba76e54b6067f7f8130c8c2b7030 GIT binary patch literal 268286 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

WwUY&e**nm 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

}6e0fZff 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 UO1@w0v4sAst7@x!P_lUXUr6q9!~g&Q literal 0 HcmV?d00001 diff --git a/my-app/build/img/choosefile.png b/my-app/build/img/choosefile.png new file mode 100644 index 0000000000000000000000000000000000000000..a831fb71fbb1fa987e18167cdd9f8df9f0336870 GIT binary patch literal 4629 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 literal 0 HcmV?d00001 diff --git a/my-app/build/img/mainlogo.png b/my-app/build/img/mainlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..a73ab6c74470c58951a7e4f9fe829f5d730cc47c GIT binary patch literal 1290 zcmV+l1@-!gP)T%td;!ZBuzUgdl*(zBFEGbcpejSoDVKbU zi(O4#YqTJZdL(UjN%>XT(#(!}TCMKaJ&mFjKx^I0C_Yj|zhKzIzloyw(3sy1tpJKv zfDOI*8J8_@I#r~0jk&v}B@xk*(E8mT)fHsGqIN(lKup2SH8xp?0#+AO6Jzct^_6NX zB*T*WIV?LqAm?ys9%BbJ5qk8ExQ+bd0asUaEYYAkJ3V`& z`=f{+kBu=kd6A&t0TdjPdrN;)ZD}@kmU!A=6jBsEdD*Vue67X4@s;%3nm_SF@AZ|e z;1hb5qHkZ*FB2Z5Y5LEr-s|76&HM6mQ0DZ(+z+1>{0T3ZT~jkOWId$mmrAfzEa`&a z$p?b~B^;Hl$r1cu?%ra47uGveG=24#xgV6D$!K;$onZI;8P6w`rfy(fWKJBEC*{DJ zTXDKa9Uujp=aZ@-2)vcKHTzp_>)7H@u+4=^s0W*;QJ1O;lcmwa_&ix;2|xJhUsD2d`EB{>hT53%V-`d`5c(!P{NgSi`= zmf*s?me9)rIiAkJw?m1@8Lb6|^Q+mo3pFhYY>o``%%u(M+TkL!IRN1BBV2C4h$-iD z`1Qx87sLAPt`(A+E5Qjr%Q?!X2>DMw=M`MXC7DMhVPE2WEcrHPBcJT&HL2rj)*(Kh z2apPVPR_9qbXpZuk9-ujZ<{I@q1J>C#@pp*LOLjl4vhKZGIHsv{#jt10YB_bPyBIP z^^MPZULDho{|vs+g`@*={g5pj;d3+)t)I%)Z~YCa6>F37DDyH(Q3E7_hqC zT`^`0tX&l>TQd6;UJ!d}GSijEiFT+Jv!pzVNa^yp;KqsktTG(Hu;gs;oX#o=ocg|# zQS`xEmK3BP1mv7}?_{(IzT~xQVnvxEz;{5SKNZ) z0tIo9PO(;PI31$VoYoc~^Yzb7f@7m}1{c8va;W|k*0w3QnLvSy?=meq z<#K;Y=tYrdEcpN3D7ZqJL^`{WeCcJeK&kddZ=MzY)Lp!zkehPRi~n};B|4pJs){~t z`z2dN$#4V*k-ASM`_+Fb^Q6f4&p4gWBJ|Xd3Ohd25?cnhok}u>5)y=eTGZ5C*lCw~ zkUt&BdY>BGF%{Hk%Tuy`oRpELtBM7gOPLY4!QfX<&Z2bQNixv`H7hxrP=`0R`N^=X zV1J9r9{w~2r(UsNBLKaQMLeQTP_<)qr5EJ-IzN8H?fV8HCZg#fuXPG?aM)k#1uG@x zzD}C{okBJTY7&&}+Kb2je66d-pOG_xobb8L%z3&@5nScS(QCb<17r`_mq}I-7M$(} zev{$+s-l3{M1>y?{7R=J-f$yJmYo;WMH7{7oAUV5J@X=cjswE^K(`>F*RgcZys*GT z_=(%h3uUelmR6F1e&oJ&ji%I%*>~0Ms{TasFQPUZ9e)_vQvd(}07*qoM6N<$f{^HC A;{X5v literal 0 HcmV?d00001 diff --git a/my-app/build/img/mainlogo.svg b/my-app/build/img/mainlogo.svg new file mode 100644 index 0000000..424a03e --- /dev/null +++ b/my-app/build/img/mainlogo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/my-app/build/img/uploadedfile.png b/my-app/build/img/uploadedfile.png new file mode 100644 index 0000000000000000000000000000000000000000..df155a870abe93fd1e367a9707df8e78fbbeaf7b GIT binary patch literal 5744 zcmeHLX;{+R*2gLHR$9j_Er*WfK<1EkLQ|nZQ!ytROiQrAoDNZ$f`SrxkCvI{(X1T6 zEHyL5IZXwu)EpAEoG`=*%?wZ!8B}<&`{8|__v8EA`|W=CKmTW~z4rR;wf1kXy`FvF z+tX#sKX&~C003-pb9I6N016oSSH5wBT=T*>4ln!j+w=Br9uSE z9I3p+PHk4OlKO4s0{X#BwVeQuxdWnJhvoOZlp} z|MBpqw?)-?dkan{6)pZ|b@IsTnv8Q^&=KCNa|TV0y?sYu_u1t;Wx)+EMYk_0w)(l$ zZ2TD1|6?!6$R7q&LKL4l^0uh`$#&{DvD(u>yCt%1p?~bFtPo(qCS1WSOhG36;$v8; zbo@#b0-QIB0dVTQWaEV#duq6i!u%a}mV?^`dD!TC?D65^WHMbe7FTpP!~bF<&Dq zpQ`gq?D{4wq?Zld7z;0Sq%NA-@oOed#nqNDp<(ZpsFTRi_tG}$MCAj@c$Z$samHuS~@*{UagO(Xa0Y}^RSpx#cQpl`Sy)rNpC z+@As8XbsK&ffzX`e%Dclt3QPq3opKMOg7U-xzhYjIb*;;);kOlPZ_xzWLXE%CFtQz zh+R*1iYrY&Xs>#vA1caSC59?8Bne`0A!H9U9;s)flj@{q4%r{iLC3vcD-+9t6y^D@8R!$;F;j8J%EANu_qrCN(G2GM15nz(F+l; z8V04{{DUsW-IkAg$C|+oGt_&MGG6SRKdN&|=c@ftGg!(ano_~RPf>Tyz0_48s6q=+ z_B4X;%WAzbZ#4(+Bhh?8YdAS(H8Nu6&thzQ)SVA|=8po|?SmIkaIt8%D7TR!{Ue=x zLhkXIhxlXPBGCY2PqTwqTR^Pj-Yik7wxXmAL)JZ-lKG{1Eg(XarUgVB%^&S7H)PLm zbm)Oaz17Rp0^*&=2$?oRQFq#tGAuPQc|iiCs_lGI2B%3cPd?S$i!!YRM5@-A5mf!* z6ySa@%3=Ss%3KqKivGsmy(sFHhCxIevSE%bmxCT@0e9Apc=#x4{PW9O!=TCb!DYWR z*cjo_hEetM*mEzpWA?m>VySzN5xz5`?2i&u8OK>ub7f|*R_400Hq8V8hRQKU$3_%txk(v{8jmhtS2djn*e@YfF|D&jQp8$#Y2A99OX(&E zONq$NF`8c^2Qsf&R~~v~fqxGkv=5>Uuw8ov z>&vhJALdB4L9~GeaXue>2Za||^PPO&z%5zeGCT6&S;Mo32 za<+Z2JJbEc=r2oSFUn}lVn>^*f10(NO+o7zrbR%dU%Q!DX;?s0$`}e+k2&u-NnZDp zoPf!<*NtK#BRyENn=67xY$V=>@qen?jwNMCRh46!mh<9k1$fGGvjI2P^f42udLD0V zIe(N4GO$BM$g=+=#)K{Evn0z+SR-hGEb5K`R6O_Z zXEI4mL!mL$L>^fk|Fw*R6HwMt2KJA9nHqhbm2#;0+PQ0k5-{ZUxq_8iOXiJWMdPkY zvrIa5vYSjNL!{YcJd-{{$9}L0uqlL)Odr>1NCRbfM1(M7hKP;+crDx|X8cjRS{|v> zk}@y#@IsEx5P1$(Z)FRr_<0DH?UJvx{lp<`&gFX>hFS!JxUkRdCc0RB{$Ksd`XL8M z?JRk|Ek9c%cxsv#X|KQo?`_cT8BhGo6&GEG|9l=fS5zjY%d&czO*em}dm#^x`@_Nw zR>!+8>&DUbyzEu<$@!YOdm!p!m-6P}t5-WK=mBboy_Wx@e!)5XeSXZs}5a}S@%YH#>!m0&LeV6 zg^oPE{PvsVg7%V+dj2B;B~(E|i-C0Lel`dd9hA=zYygw$cN$C^<*||9mZlU)7vny! zI*nwXDb|JGoK~-xvJsQxIAvu{7qY7zn=o#Q@5R%vWjW76!qbnyKKE=^UZOF0zP};O zQ=2zAC|5_$c@-HmvUcYJ?*4|klc%h|$CRMDQC?d9onlr_Nc8CW$>55NY+9;!%8&6xy{y*Gqs`o`gN{rL^K46-5&|40zX}THu8S`F`#Ef| zek)=M&87BB!YU$ic04lGc+Uoc!E@bD^wP%t51;Ifo73BpilF>_pF1%+^D{MW4^v1J zZdm^BW3GK(@>=ihj+PL&c6wVs?eKe!BQ(h2+o}y)g*X=hU_}R*@jww`CZ?Gck zs<`7Zp0dd5!?b^}GO!DFJ5srE^_WeeP`@GkGczF=KuDdSTz)l8nPQ;Fe3P61_bj%K z>1YN7s1|vR-Ve>JG|JL>;~Ni5uZI7^M_X^dCG29 zbmdFF3d&2KSI4nIw%|G!8;E?z?nK-Knk4^D2>yC&h%Wx58Us;xhPRnO`1v8?)SeDH z^T3kT24$j;pJXB8fj1TO@T;3iqnTdS7_v#IvC4dcazDDb(P8i3JYtiiqcZ_FKxyDT zmU&OHAE;iK(AL%`1Up6T6gHmh{*d~{Yi_`CU6bG$fK6`wF!&jhh}oQCa3+T<`3^WSAVOeM$VbJFRoMU zl!&gP0geWC*#+#KJZb4h`=o|TXE%8+zR=+__|c{>4(tHc=~|O&Ql}GMJLE*TAH0r$ z{7fgO(|gf_X306f?@HL$b{Ij1^WM=PN-JAW4pL`G=$DQ`m(C~?e-FLge=08VCU5Np zA|6aC07<~DcbDb)KG1JgV{2qJm8%Odf^D?gcmlyM(Ev!NqE`IP7_0) zEJ&ZxdUWFdb#|?tKHU2w;gH_dE%tjzNy~nJ>EsCk`BO!OH87Rw}A!OJq31Ku{PRDyMGJrN`)Q=ZEpGz^x&U@H2SUYblbJBqiyq4VS4DWRwsHT zQk8Q}+gP@+6~oB=eb>o-EYT9BB^abzrc>N#Ik&Qd^v6pph{LBSf|$hPULWPDltRaJ zDsaZ6_-`Q-k+v~0L^oflpk{V&OT*pg#7K>08`<>?s)p0=^T|+kKHsprEw|B@>64tT zF_R1?Rm`-1o%FQ3GUU?@g0nkK=kRbTxFI|5uc+RGRn`redH4C};#_v57Y788-A)UK zqm#j^(N`AggoGLoos;bmfM{4GYhvcm9QGu?2}`*dn~%(qNK=XB(uy!&Rz&)nLjn3E zRJHB!`A@t(=SnH|3JumyO8=JLL5sk9WxOXx=SvaFv%1DjFLXsuZDa6sbHD}pbwp}r z5%1ivu;slFnlKnI!y?yyq?}o~t@!?Y^*o0KSuG!SykA>;^qsDD-wd2 ztldC1u5`b4aJML|=3UL+rW?sN(IH52*V+Tp%2F;_T%#117J^M*0k@}Ff^!hXx^aT# ziR3ugYds(LP`Dzrw5qBqSh|h6AmSZ3@-AkzVP~Yt(4|{zgfPMLu!Zpxp*dY|y2=Ex zao^uSg-FD^@or_>tNLEG|HL)-qn7Hc%}QNw!+=YYfQBKSRJT*9Qwv0g^vW zn?s&4WYNWn)b+;b`e3^|uTBXeX^20T%ik%HBMEsXl8_e!j^uy6@P zCIQJN%av*6xEE!)HTk7Rw(-2WCRvq>K}l4sARHZO1W1?~chMgSj_vK1wiy?=fjlr{ zCH;bu2O1?S1`XHPEK19H2U<^#IMLnfjeYey|JbV&i6NCK85VOg++?ANhUjAuDaKtf z&^wrj?!7B%@23<}3?I`5N-w-#iR8XTEQGH`u`0IgKJ2-|jfZ@j`6z5$Tu`QY@=e>s zI|C%kSjr;po3u^dwR*IC`c#CFH16B~7#eKOSzulc%j=V2f@eywWwLBDSr9kJZ{#-s zkbW9o#czH4=eMP=3ii}KAC4=XTH#-MofDf0eF?K`gt=Rmy-vj~OIVlyfe3BxkN(Ni zWjZ1mQtBxHav!OJ6~SVJg5t*AQ8Crmj|+_Kxc_>pl#UGWIZ*7_#2f7$I2(;a0bbx~rkAV?=~(p_yz`7_w&zSwcIJ$i7Y1 zj44I-J+h4@W-xfpc%Iku4?I78U(XNcb008iu zKWB0U03ht(5yA-tk&CFe-r$Mr?m25;0FcpU9T3x0lmiGte6N_D1&S$>zrg{Ai_t|R z04R;;W;z}M03n(4CPr5SAxk6NepffL8&^YIIR%0qa|FFoQ?eS8Kl*gz)B86?_j9Gf z-l=%#SJb;)^$_LyJhx;id2{PI!nU|UMGNyUlN?NJX=a}rW&En7_) zP$gHvM-enr*&hqAZ{Jj*6L+=0J4E+uN2V;V=UL9J$cx%DF84@{@JS#ng7+Ijj)at# z6sc|!i0cyl#pgCuiCQXg`T`Q+5YY(wXz)U;gqf}H4?Fhhf$V^b%aTZ_kMM#`cSIIq z*qy4dG>puWnSf0lX&Q@{s+!nxNv$*Cw2bns+Zy^fQ9mnPT9S>py1~uIc>bjtc10vM zjLD((=@y4z_?h12A%{>l|KJik#o(RcwRcW`$Nrqr(JyGqx}S|GI4MrN@9P$!zdZ70 z7IGGdSIR!^w3c|&Yx|x@?562EaI{U!q^Skc)(YPh(D3_6_%T&pNi16&9ASxjul@U3$o6y&t=7Y$*P82W zi!>2!B?sj!&}|6mby3N=QCo$#u6({}Lp>Zr2EsIPD{0+ph1_(qm@0HFm;)PXm@M%G z_dal`zhrPi$5xCi@gxeuW&w@i>j`>ayybwhQjsP>?mmTy%yxeYF}K8^1=$;&zr0N3 zX|VfPpcBQK<$oU1z&-fcert|);ztyOKN2S5Z2r;faeZrDWn@X^)#Fe@Y@u(F#kPjh z&DR3#xxz*RS7PD7dDq+KnhkFWa!|vh#Z))@?a4;sW)@6jw`?sD4k#xyP0n94-z1M+ z=^kRSB*@kjJ{`Lb^5@3lW~QPQMLpNLI?b>^f#Y1l8ZXy%^nFirO>o#zOsFl#MlA$$ z&^%uK4GV=Oq{JKS4}|ZoR$lE@OcmC{0=R^cEAM_o<+;LxM!0=BKp-6^5>n^WAwqZf z%6-6gXtzc5NxQ>W^MjH6y&0!3scwgASg8$M`|IZGAjg^GD8R=MgBD?=x{-nQ#Is|p zs?J<(XBCNP!@XxT`>Irk4j#<1TW_TYntx;-lq=QY;Jq3?K#M$^*Yd*R(b`AWU4yO% zeO}2=>5>}Bq@~1@0VSZU@abE^Te!~8k5uJKRvMNFu<%}U(Y{vut@K@%)|Q62_pTVU zR(5wci$=+?Y|VS--VOyaQViYS!+sxcfjy@L83ZkZP zF#YoJdsUZS93($_O~#tgodH|7Ul%3@-h3^8ARt;s zMH+Mn@`3lb5gyC{>=?)#-|pbO@me15Sv#?Pu6JPifZPSFnDtl{RkJig%d1FZ^s4SA zyPJO$Ij~||1g|n}rR#;r54jJ8;wXSXDJI|OPDgmT&1s;Ig2 zmfT)vTPuQ}J+SkKeGTD-e(;7tU%<#mcMCkR;Pcp(rD^1J6uj}@zgerFF8@wf;&J;= zJN36`g&uwf)7$*BLr+b;_x{CS+40A`RJ20dhC^tK4L%BE)%DD1y%Xm5l90ltggT=H z-QYKeiG#~6&8zHJEYD!6Kh7apu9T|II9p1ktk?)oM>O>KwiAVm!d8k%p_Z)m{YH-VU9yjURHt0)_(YKr|e% zBm<$cP~a#E$c=&krZ7P1|KAkc=>J@HZm!-All#HmujrC^-i<|r;@ZizQuEYzoD$O< zD8r^edL3OiHq%n`e%IlfJM9Ywv{Bp5#`s%t%o6{7+gl0#WZ=+qw{PDkRw)+Q=zw&i zJ^}Wl4nFFFNj2yOgZw8z^9otW80!O<@TEYnu)Oy(%h;3ny*Q7M1@|?bZB# zVp~5(%3i&;sHlRBaF2qldG3X`b@EAS|Fn*ai5beIT!K9`F|vz!Znp4`!o>_b#{^9> z5G0Q|gsd;C7_Lu!6E-=C)%WZ#&Q@L+J-%Istgo%GL3^mRAHjy!Zc|PK#Fe)l(|zWl z<3CSmjqe&dv{fc${fCUV=f0F_0<9N~P$cS0L1<$gk-Tsu3B)CEa56ZCbai*oP?K4$lV|pVp8I1kxPYZ(y zRnZZkORQyD^maB4BM2G6c>b=sdZWD%7k!N!U7>$XUeED&JFJ<)@7=xgXznjw?Tm*21t z2$LMKYf%vOc|~qfvozr@Dm8d9O$8=21nx4NhK*b94F8*;8bR_fh9wB7YcSJ(^q6`b zrhKNV3H&cu-sW>HVfk!0oX@DHhS_?T#Uc9p)(bRGRzbn z1PQlxe7s80{@XScR`Eo5?!_biU=Qw;dUmK?-rM7$7{U_Do(>KQ(y8xPzq&jE-FJPl z_#Epg$#R^`h=N?va$jbyU452pr4(rA)CB^Qk3cHDl2T_fpj_p|tV`LnLboBmvkcec zPQZN?veyJx%=5{4nXs|N1z-FhExYMpyXVaHmD*OYr{_D!zJlC`dfXp_PEuYM)%(?P zV8P7eP}dY2;aW!L;9Oz(j);8;HvOk0%J9u_&-o`ylsYYz`&k*?kOSN9D>y>m+JUr? z703YB)@|2x&i}r2-Z?{hl#lYc*h2O;U^pUj`p?1m(`XGVGvI z#iDu2N^}E$i!(rRjlkrHp-Fjpr;hgCT$+BJ8`DPD_)>vj1p`4#pkmGXHYtwzF#Fhe zej?z5G)c;n@#0H5?k+Nnu~a8)^n!A6z>Hh|fQH*G|Ez=J;1 z>|y{Q2(B?sRey2LgRbuA$;8KOyy~6hJ%u)ev4!V3-s%upNQDW_%=QOLqBuDtA~J+) zRKDf6rNQXitosATEsHBd>*A!a9+buxsRmZ@44WSXufFOtr+t0E_?Z{8nu6@o$$6=Z z6E5~SL(eOXer?SJ#gZFexVgET4;vfbLv~7S1ugw7y*-kIVfCKi);GL0vz+JXA|mUY z^7iI?%wfA@V5_9DuIc#FuBo9`4F|)E_}&-kUI1CzrLY z*=<^lTuxRtrO-k*NyfpJ_V!+vBn@tbP|TSjJoUf6(l-4tB+|(H4kw}S8x2H-O*^T@rvDT-52AV=xmIXdUk4Q#IpZn z+ul-T2@bdVCGmJp8Z(IQIY!GniMhH9enUBY^V=La79anqT79jt0AC@_Cj&*xH}Id@ zh`C%eIi+wlRtv2t!x)h$smHNJS91L)ZdE#4#}o9u8OWS8I1sinv1yyVwE7#aVX{cd zuDO>c24Z`^_^Jn{dQsXRDbE;p@dZ75yN9cE0JiafhB0_Wn>g{DoUE5n-$3$u@S4>l z$hf;#-G{ulgInEW^>MuXF^@Bx~i;TUg#7+N1gA_(Dht2+d;<#TOw#jWD`#$V(F(lNp}Os4K&j8H7Sa)iRx-6`Gy;H zx6;=|;eIn?wiO#?<|^pwx#s#v9=4g@9^S*)TtazqF|Mm`p3>^VE2;N=;$7uFb-}~M zijn93H$ps%fAR5EgTLBLSNEpxGLr5R&umn4G$B^z=i{C}eSrV-iM7@F&>z%_WHNjD zqK#uQ9I-O|-ZaA}Di5<0J$5A`qhq}!00t4pot@Zd8Ng}cZ61=e-hC>2KSPYy-p{rU zm9liOo$+V+m@xz}W7-6L1~LdIVaMsBe!??cpe*Tt1NGpE6y PXTW*WOD4r<9m4+$Q{1;t literal 0 HcmV?d00001 diff --git a/my-app/build/index.html b/my-app/build/index.html new file mode 100644 index 0000000..67b9f72 --- /dev/null +++ b/my-app/build/index.html @@ -0,0 +1 @@ +SUNNY BRAILLE

\ No newline at end of file diff --git a/my-app/build/manifest.json b/my-app/build/manifest.json new file mode 100644 index 0000000..1f2f141 --- /dev/null +++ b/my-app/build/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/my-app/build/robots.txt b/my-app/build/robots.txt new file mode 100644 index 0000000..e9e57dc --- /dev/null +++ b/my-app/build/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/my-app/build/static/css/main.d5c25553.css b/my-app/build/static/css/main.d5c25553.css new file mode 100644 index 0000000..3a8b6f4 --- /dev/null +++ b/my-app/build/static/css/main.d5c25553.css @@ -0,0 +1,4 @@ +/* +! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com +*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.link-underline{display:inline-block;position:relative}.link-underline:after{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity));bottom:.125rem;content:"";height:.125rem;left:50%;position:absolute;transition-duration:.3s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);width:0}.link-underline:hover:after{left:0;width:100%}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.bottom-0{bottom:0}.bottom-\[-100px\]{bottom:-100px}.bottom-\[33px\]{bottom:33px}.left-0{left:0}.left-\[11\.83px\]{left:11.83px}.left-\[126\.53px\]{left:126.53px}.left-\[13\.14px\]{left:13.14px}.left-\[150px\]{left:150px}.left-\[18\.72px\]{left:18.72px}.left-\[31\.21px\]{left:31.21px}.left-\[33\.18px\]{left:33.18px}.left-\[38\.11px\]{left:38.11px}.left-\[40\.08px\]{left:40.08px}.left-\[45px\]{left:45px}.left-\[50\.59px\]{left:50.59px}.left-\[51px\]{left:51px}.left-\[53\.22px\]{left:53.22px}.left-\[57\.49px\]{left:57.49px}.left-\[62px\]{left:62px}.left-\[630px\]{left:630px}.left-\[69\.97px\]{left:69.97px}.left-\[76\.87px\]{left:76.87px}.left-\[89\.35px\]{left:89.35px}.left-\[96\.25px\]{left:96.25px}.right-10{right:2.5rem}.right-\[-180px\]{right:-180px}.top-0{top:0}.top-\[13\.80px\]{top:13.8px}.top-\[150px\]{top:150px}.top-\[200px\]{top:200px}.top-\[22px\]{top:22px}.top-\[24px\]{top:24px}.top-\[290px\]{top:290px}.top-\[350px\]{top:350px}.top-\[6\.90px\]{top:6.9px}.top-\[80px\]{top:80px}.z-0{z-index:0}.z-10{z-index:10}.m-auto{margin:auto}.mx-auto{margin-left:auto;margin-right:auto}.my-\[180px\]{margin-bottom:180px;margin-top:180px}.my-\[20px\]{margin-bottom:20px;margin-top:20px}.my-\[30px\]{margin-bottom:30px;margin-top:30px}.my-\[40px\]{margin-bottom:40px;margin-top:40px}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.mr-4{margin-right:1rem}.mr-auto{margin-right:auto}.mt-4{margin-top:1rem}.flex{display:flex}.inline-flex{display:inline-flex}.hidden{display:none}.h-10{height:2.5rem}.h-6{height:1.5rem}.h-\[130px\]{height:130px}.h-\[19\.05px\]{height:19.05px}.h-\[300px\]{height:300px}.h-\[36px\]{height:36px}.h-\[38px\]{height:38px}.h-\[40px\]{height:40px}.h-\[450px\]{height:450px}.h-\[5\.26px\]{height:5.26px}.h-\[50px\]{height:50px}.h-\[52px\]{height:52px}.h-\[650px\]{height:650px}.h-\[72px\]{height:72px}.h-\[75px\]{height:75px}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[300px\]{max-height:300px}.w-1\/2{width:50%}.w-6{width:1.5rem}.w-\[101\.51px\]{width:101.51px}.w-\[170px\]{width:170px}.w-\[185px\]{width:185px}.w-\[300px\]{width:300px}.w-\[320px\]{width:320px}.w-\[38px\]{width:38px}.w-\[40px\]{width:40px}.w-\[5\.26px\]{width:5.26px}.w-\[58\.47px\]{width:58.47px}.w-\[650px\]{width:650px}.w-\[90px\]{width:90px}.w-\[926px\]{width:926px}.w-auto{width:auto}.w-full{width:100%}.max-w-\[300px\]{max-width:300px}.cursor-pointer{cursor:pointer}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-4{gap:1rem}.gap-\[6\.45px\]{gap:6.45px}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.border{border-width:1px}.border-neutral-800{--tw-border-opacity:1;border-color:rgb(38 38 38/var(--tw-border-opacity))}.bg-\[\#2B2B2B\]{--tw-bg-opacity:1;background-color:rgb(43 43 43/var(--tw-bg-opacity))}.bg-\[\#FF6A3F\]{--tw-bg-opacity:1;background-color:rgb(255 106 63/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-neutral-800{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity))}.bg-stone-200{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity))}.bg-stone-800{--tw-bg-opacity:1;background-color:rgb(41 37 36/var(--tw-bg-opacity))}.bg-transparent{background-color:initial}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-yellow-300{--tw-bg-opacity:1;background-color:rgb(253 224 71/var(--tw-bg-opacity))}.bg-opacity-75{--tw-bg-opacity:0.75}.object-fill{object-fit:fill}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-2\.5{padding-bottom:.625rem;padding-top:.625rem}.text-left{text-align:left}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-\[\'Pretendard\'\]{font-family:Pretendard}.font-\[\'Univers\'\]{font-family:Univers}.font-eng{font-family:Figtree,sans-serif}.font-kor{font-family:Pretendard,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-5xl{font-size:3rem;line-height:1}.text-6xl{font-size:3.75rem;line-height:1}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.leading-4{line-height:1rem}.leading-9{line-height:2.25rem}.leading-\[15\.12px\]{line-height:15.12px}.leading-\[18\.90px\]{line-height:18.9px}.leading-\[20px\]{line-height:20px}.leading-\[25px\]{line-height:25px}.leading-\[37px\]{line-height:37px}.leading-\[57px\]{line-height:57px}.leading-\[60px\]{line-height:60px}.leading-\[72px\]{line-height:72px}.leading-none{line-height:1}.tracking-wide{letter-spacing:.025em}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-neutral-800{--tw-text-opacity:1;color:rgb(38 38 38/var(--tw-text-opacity))}.text-stone-200{--tw-text-opacity:1;color:rgb(231 229 228/var(--tw-text-opacity))}.text-stone-800{--tw-text-opacity:1;color:rgb(41 37 36/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-300{--tw-text-opacity:1;color:rgb(253 224 71/var(--tw-text-opacity))}.text-opacity-50{--tw-text-opacity:0.5}.opacity-50{opacity:.5}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:bg-\[\#E6552F\]:hover{--tw-bg-opacity:1;background-color:rgb(230 85 47/var(--tw-bg-opacity))}.hover\:bg-neutral-600:hover{--tw-bg-opacity:1;background-color:rgb(82 82 82/var(--tw-bg-opacity))}.hover\:bg-stone-600:hover{--tw-bg-opacity:1;background-color:rgb(87 83 78/var(--tw-bg-opacity))}.hover\:bg-yellow-600:hover{--tw-bg-opacity:1;background-color:rgb(202 138 4/var(--tw-bg-opacity))}.hover\:font-bold:hover{font-weight:700}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),0 0 #0000;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-white:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.focus\:ring-offset-stone-200:focus{--tw-ring-offset-color:#e7e5e4} +/*# sourceMappingURL=main.d5c25553.css.map*/ \ No newline at end of file diff --git a/my-app/build/static/css/main.d5c25553.css.map b/my-app/build/static/css/main.d5c25553.css.map new file mode 100644 index 0000000..bbb230b --- /dev/null +++ b/my-app/build/static/css/main.d5c25553.css.map @@ -0,0 +1 @@ +{"version":3,"file":"static/css/main.d5c25553.css","mappings":"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","sources":["tailwind.css"],"sourcesContent":["@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer components {\n .link-underline {\n @apply relative;\n @apply inline-block;\n }\n .link-underline::after {\n content: '';\n @apply absolute;\n @apply w-0;\n @apply h-0.5;\n @apply bg-neutral-800;\n @apply bottom-0.5;\n @apply left-1/2;\n @apply transition-all;\n @apply duration-300;\n }\n .link-underline:hover::after {\n @apply w-full;\n @apply left-0;\n }\n }"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/my-app/build/static/js/787.d4aba7ab.chunk.js b/my-app/build/static/js/787.d4aba7ab.chunk.js new file mode 100644 index 0000000..a41e13c --- /dev/null +++ b/my-app/build/static/js/787.d4aba7ab.chunk.js @@ -0,0 +1,2 @@ +"use strict";(self.webpackChunkmy_app=self.webpackChunkmy_app||[]).push([[787],{787:(e,t,n)=>{n.r(t),n.d(t,{getCLS:()=>y,getFCP:()=>g,getFID:()=>C,getLCP:()=>P,getTTFB:()=>D});var i,r,a,o,u=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v2-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},c=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},f=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},s=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},m=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},v=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},d=function(){f((function(e){var t=e.timeStamp;v=t}),!0)},l=function(){return v<0&&(v=p(),d(),s((function(){setTimeout((function(){v=p(),d()}),0)}))),{get firstHiddenTime(){return v}}},g=function(e,t){var n,i=l(),r=u("FCP"),a=function(e){"first-contentful-paint"===e.name&&(f&&f.disconnect(),e.startTime-1&&e(t)},r=u("CLS",0),a=0,o=[],v=function(e){if(!e.hadRecentInput){var t=o[0],i=o[o.length-1];a&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(a+=e.value,o.push(e)):(a=e.value,o=[e]),a>r.value&&(r.value=a,r.entries=o,n())}},p=c("layout-shift",v);p&&(n=m(i,r,t),f((function(){p.takeRecords().map(v),n(!0)})),s((function(){a=0,T=-1,r=u("CLS",0),n=m(i,r,t)})))},E={passive:!0,capture:!0},w=new Date,L=function(e,t){i||(i=t,r=e,a=new Date,F(removeEventListener),S())},S=function(){if(r>=0&&r1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){L(e,t),r()},i=function(){r()},r=function(){removeEventListener("pointerup",n,E),removeEventListener("pointercancel",i,E)};addEventListener("pointerup",n,E),addEventListener("pointercancel",i,E)}(t,e):L(t,e)}},F=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,b,E)}))},C=function(e,t){var n,a=l(),v=u("FID"),p=function(e){e.startTimeperformance.now())return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("load",(function(){return setTimeout(t,0)}))}}}]); +//# sourceMappingURL=787.d4aba7ab.chunk.js.map \ No newline at end of file diff --git a/my-app/build/static/js/787.d4aba7ab.chunk.js.map b/my-app/build/static/js/787.d4aba7ab.chunk.js.map new file mode 100644 index 0000000..2b0bfb5 --- /dev/null +++ b/my-app/build/static/js/787.d4aba7ab.chunk.js.map @@ -0,0 +1 @@ +{"version":3,"file":"static/js/787.d4aba7ab.chunk.js","mappings":"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","sources":["../node_modules/web-vitals/dist/web-vitals.js"],"sourcesContent":["var e,t,n,i,r=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:\"v2-\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12)}},a=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if(\"first-input\"===e&&!(\"PerformanceEventTiming\"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},o=function(e,t){var n=function n(i){\"pagehide\"!==i.type&&\"hidden\"!==document.visibilityState||(e(i),t&&(removeEventListener(\"visibilitychange\",n,!0),removeEventListener(\"pagehide\",n,!0)))};addEventListener(\"visibilitychange\",n,!0),addEventListener(\"pagehide\",n,!0)},u=function(e){addEventListener(\"pageshow\",(function(t){t.persisted&&e(t)}),!0)},c=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},f=-1,s=function(){return\"hidden\"===document.visibilityState?0:1/0},m=function(){o((function(e){var t=e.timeStamp;f=t}),!0)},v=function(){return f<0&&(f=s(),m(),u((function(){setTimeout((function(){f=s(),m()}),0)}))),{get firstHiddenTime(){return f}}},d=function(e,t){var n,i=v(),o=r(\"FCP\"),f=function(e){\"first-contentful-paint\"===e.name&&(m&&m.disconnect(),e.startTime-1&&e(t)},f=r(\"CLS\",0),s=0,m=[],v=function(e){if(!e.hadRecentInput){var t=m[0],i=m[m.length-1];s&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(s+=e.value,m.push(e)):(s=e.value,m=[e]),s>f.value&&(f.value=s,f.entries=m,n())}},h=a(\"layout-shift\",v);h&&(n=c(i,f,t),o((function(){h.takeRecords().map(v),n(!0)})),u((function(){s=0,l=-1,f=r(\"CLS\",0),n=c(i,f,t)})))},T={passive:!0,capture:!0},y=new Date,g=function(i,r){e||(e=r,t=i,n=new Date,w(removeEventListener),E())},E=function(){if(t>=0&&t1e12?new Date:performance.now())-e.timeStamp;\"pointerdown\"==e.type?function(e,t){var n=function(){g(e,t),r()},i=function(){r()},r=function(){removeEventListener(\"pointerup\",n,T),removeEventListener(\"pointercancel\",i,T)};addEventListener(\"pointerup\",n,T),addEventListener(\"pointercancel\",i,T)}(t,e):g(t,e)}},w=function(e){[\"mousedown\",\"keydown\",\"touchstart\",\"pointerdown\"].forEach((function(t){return e(t,S,T)}))},L=function(n,f){var s,m=v(),d=r(\"FID\"),p=function(e){e.startTimeperformance.now())return;n.entries=[t],e(n)}catch(e){}},\"complete\"===document.readyState?setTimeout(t,0):addEventListener(\"load\",(function(){return setTimeout(t,0)}))};export{h as getCLS,d as getFCP,L as getFID,F as getLCP,P as getTTFB};\n"],"names":["e","t","n","i","r","name","value","delta","entries","id","concat","Date","now","Math","floor","random","a","PerformanceObserver","supportedEntryTypes","includes","self","getEntries","map","observe","type","buffered","o","document","visibilityState","removeEventListener","addEventListener","u","persisted","c","f","s","m","timeStamp","v","setTimeout","firstHiddenTime","d","disconnect","startTime","push","window","performance","getEntriesByName","requestAnimationFrame","p","l","h","hadRecentInput","length","takeRecords","T","passive","capture","y","g","w","E","entryType","target","cancelable","processingStart","forEach","S","L","b","F","once","P","getEntriesByType","timing","max","navigationStart","responseStart","readyState"],"sourceRoot":""} \ No newline at end of file diff --git a/my-app/build/static/js/main.c90bec40.js b/my-app/build/static/js/main.c90bec40.js new file mode 100644 index 0000000..f9349af --- /dev/null +++ b/my-app/build/static/js/main.c90bec40.js @@ -0,0 +1,3 @@ +/*! For license information please see main.c90bec40.js.LICENSE.txt */ +(()=>{var e={463:(e,t,n)=>{"use strict";var r=n(791),a=n(296);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n attribute.\n *\n * @param to - The destination URL\n */\n createHref(to: To): string;\n\n /**\n * Returns a URL for the given `to` value\n *\n * @param to - The destination URL\n */\n createURL(to: To): URL;\n\n /**\n * Encode a location the same way window.history would do (no-op for memory\n * history) so we ensure our PUSH/REPLACE navigations for data routers\n * behave the same as POP\n *\n * @param to Unencoded path\n */\n encodeLocation(to: To): Path;\n\n /**\n * Pushes a new location onto the history stack, increasing its length by one.\n * If there were any entries in the stack after the current one, they are\n * lost.\n *\n * @param to - The new URL\n * @param state - Data to associate with the new location\n */\n push(to: To, state?: any): void;\n\n /**\n * Replaces the current location in the history stack with a new one. The\n * location that was replaced will no longer be available.\n *\n * @param to - The new URL\n * @param state - Data to associate with the new location\n */\n replace(to: To, state?: any): void;\n\n /**\n * Navigates `n` entries backward/forward in the history stack relative to the\n * current index. For example, a \"back\" navigation would use go(-1).\n *\n * @param delta - The delta in the stack index\n */\n go(delta: number): void;\n\n /**\n * Sets up a listener that will be called whenever the current location\n * changes.\n *\n * @param listener - A function that will be called when the location changes\n * @returns unlisten - A function that may be used to stop listening\n */\n listen(listener: Listener): () => void;\n}\n\ntype HistoryState = {\n usr: any;\n key?: string;\n idx: number;\n};\n\nconst PopStateEventType = \"popstate\";\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Memory History\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A user-supplied object that describes a location. Used when providing\n * entries to `createMemoryHistory` via its `initialEntries` option.\n */\nexport type InitialEntry = string | Partial;\n\nexport type MemoryHistoryOptions = {\n initialEntries?: InitialEntry[];\n initialIndex?: number;\n v5Compat?: boolean;\n};\n\n/**\n * A memory history stores locations in memory. This is useful in stateful\n * environments where there is no web browser, such as node tests or React\n * Native.\n */\nexport interface MemoryHistory extends History {\n /**\n * The current index in the history stack.\n */\n readonly index: number;\n}\n\n/**\n * Memory history stores the current location in memory. It is designed for use\n * in stateful non-browser environments like tests and React Native.\n */\nexport function createMemoryHistory(\n options: MemoryHistoryOptions = {}\n): MemoryHistory {\n let { initialEntries = [\"/\"], initialIndex, v5Compat = false } = options;\n let entries: Location[]; // Declare so we can access from createMemoryLocation\n entries = initialEntries.map((entry, index) =>\n createMemoryLocation(\n entry,\n typeof entry === \"string\" ? null : entry.state,\n index === 0 ? \"default\" : undefined\n )\n );\n let index = clampIndex(\n initialIndex == null ? entries.length - 1 : initialIndex\n );\n let action = Action.Pop;\n let listener: Listener | null = null;\n\n function clampIndex(n: number): number {\n return Math.min(Math.max(n, 0), entries.length - 1);\n }\n function getCurrentLocation(): Location {\n return entries[index];\n }\n function createMemoryLocation(\n to: To,\n state: any = null,\n key?: string\n ): Location {\n let location = createLocation(\n entries ? getCurrentLocation().pathname : \"/\",\n to,\n state,\n key\n );\n warning(\n location.pathname.charAt(0) === \"/\",\n `relative pathnames are not supported in memory history: ${JSON.stringify(\n to\n )}`\n );\n return location;\n }\n\n function createHref(to: To) {\n return typeof to === \"string\" ? to : createPath(to);\n }\n\n let history: MemoryHistory = {\n get index() {\n return index;\n },\n get action() {\n return action;\n },\n get location() {\n return getCurrentLocation();\n },\n createHref,\n createURL(to) {\n return new URL(createHref(to), \"http://localhost\");\n },\n encodeLocation(to: To) {\n let path = typeof to === \"string\" ? parsePath(to) : to;\n return {\n pathname: path.pathname || \"\",\n search: path.search || \"\",\n hash: path.hash || \"\",\n };\n },\n push(to, state) {\n action = Action.Push;\n let nextLocation = createMemoryLocation(to, state);\n index += 1;\n entries.splice(index, entries.length, nextLocation);\n if (v5Compat && listener) {\n listener({ action, location: nextLocation, delta: 1 });\n }\n },\n replace(to, state) {\n action = Action.Replace;\n let nextLocation = createMemoryLocation(to, state);\n entries[index] = nextLocation;\n if (v5Compat && listener) {\n listener({ action, location: nextLocation, delta: 0 });\n }\n },\n go(delta) {\n action = Action.Pop;\n let nextIndex = clampIndex(index + delta);\n let nextLocation = entries[nextIndex];\n index = nextIndex;\n if (listener) {\n listener({ action, location: nextLocation, delta });\n }\n },\n listen(fn: Listener) {\n listener = fn;\n return () => {\n listener = null;\n };\n },\n };\n\n return history;\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Browser History\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A browser history stores the current location in regular URLs in a web\n * browser environment. This is the standard for most web apps and provides the\n * cleanest URLs the browser's address bar.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#browserhistory\n */\nexport interface BrowserHistory extends UrlHistory {}\n\nexport type BrowserHistoryOptions = UrlHistoryOptions;\n\n/**\n * Browser history stores the location in regular URLs. This is the standard for\n * most web apps, but it requires some configuration on the server to ensure you\n * serve the same app at multiple URLs.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createbrowserhistory\n */\nexport function createBrowserHistory(\n options: BrowserHistoryOptions = {}\n): BrowserHistory {\n function createBrowserLocation(\n window: Window,\n globalHistory: Window[\"history\"]\n ) {\n let { pathname, search, hash } = window.location;\n return createLocation(\n \"\",\n { pathname, search, hash },\n // state defaults to `null` because `window.history.state` does\n (globalHistory.state && globalHistory.state.usr) || null,\n (globalHistory.state && globalHistory.state.key) || \"default\"\n );\n }\n\n function createBrowserHref(window: Window, to: To) {\n return typeof to === \"string\" ? to : createPath(to);\n }\n\n return getUrlBasedHistory(\n createBrowserLocation,\n createBrowserHref,\n null,\n options\n );\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Hash History\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A hash history stores the current location in the fragment identifier portion\n * of the URL in a web browser environment.\n *\n * This is ideal for apps that do not control the server for some reason\n * (because the fragment identifier is never sent to the server), including some\n * shared hosting environments that do not provide fine-grained controls over\n * which pages are served at which URLs.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#hashhistory\n */\nexport interface HashHistory extends UrlHistory {}\n\nexport type HashHistoryOptions = UrlHistoryOptions;\n\n/**\n * Hash history stores the location in window.location.hash. This makes it ideal\n * for situations where you don't want to send the location to the server for\n * some reason, either because you do cannot configure it or the URL space is\n * reserved for something else.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createhashhistory\n */\nexport function createHashHistory(\n options: HashHistoryOptions = {}\n): HashHistory {\n function createHashLocation(\n window: Window,\n globalHistory: Window[\"history\"]\n ) {\n let {\n pathname = \"/\",\n search = \"\",\n hash = \"\",\n } = parsePath(window.location.hash.substr(1));\n\n // Hash URL should always have a leading / just like window.location.pathname\n // does, so if an app ends up at a route like /#something then we add a\n // leading slash so all of our path-matching behaves the same as if it would\n // in a browser router. This is particularly important when there exists a\n // root splat route () since that matches internally against\n // \"/*\" and we'd expect /#something to 404 in a hash router app.\n if (!pathname.startsWith(\"/\") && !pathname.startsWith(\".\")) {\n pathname = \"/\" + pathname;\n }\n\n return createLocation(\n \"\",\n { pathname, search, hash },\n // state defaults to `null` because `window.history.state` does\n (globalHistory.state && globalHistory.state.usr) || null,\n (globalHistory.state && globalHistory.state.key) || \"default\"\n );\n }\n\n function createHashHref(window: Window, to: To) {\n let base = window.document.querySelector(\"base\");\n let href = \"\";\n\n if (base && base.getAttribute(\"href\")) {\n let url = window.location.href;\n let hashIndex = url.indexOf(\"#\");\n href = hashIndex === -1 ? url : url.slice(0, hashIndex);\n }\n\n return href + \"#\" + (typeof to === \"string\" ? to : createPath(to));\n }\n\n function validateHashLocation(location: Location, to: To) {\n warning(\n location.pathname.charAt(0) === \"/\",\n `relative pathnames are not supported in hash history.push(${JSON.stringify(\n to\n )})`\n );\n }\n\n return getUrlBasedHistory(\n createHashLocation,\n createHashHref,\n validateHashLocation,\n options\n );\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region UTILS\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * @private\n */\nexport function invariant(value: boolean, message?: string): asserts value;\nexport function invariant(\n value: T | null | undefined,\n message?: string\n): asserts value is T;\nexport function invariant(value: any, message?: string) {\n if (value === false || value === null || typeof value === \"undefined\") {\n throw new Error(message);\n }\n}\n\nexport function warning(cond: any, message: string) {\n if (!cond) {\n // eslint-disable-next-line no-console\n if (typeof console !== \"undefined\") console.warn(message);\n\n try {\n // Welcome to debugging history!\n //\n // This error is thrown as a convenience, so you can more easily\n // find the source for a warning that appears in the console by\n // enabling \"pause on exceptions\" in your JavaScript debugger.\n throw new Error(message);\n // eslint-disable-next-line no-empty\n } catch (e) {}\n }\n}\n\nfunction createKey() {\n return Math.random().toString(36).substr(2, 8);\n}\n\n/**\n * For browser-based histories, we combine the state and key into an object\n */\nfunction getHistoryState(location: Location, index: number): HistoryState {\n return {\n usr: location.state,\n key: location.key,\n idx: index,\n };\n}\n\n/**\n * Creates a Location object with a unique key from the given Path\n */\nexport function createLocation(\n current: string | Location,\n to: To,\n state: any = null,\n key?: string\n): Readonly {\n let location: Readonly = {\n pathname: typeof current === \"string\" ? current : current.pathname,\n search: \"\",\n hash: \"\",\n ...(typeof to === \"string\" ? parsePath(to) : to),\n state,\n // TODO: This could be cleaned up. push/replace should probably just take\n // full Locations now and avoid the need to run through this flow at all\n // But that's a pretty big refactor to the current test suite so going to\n // keep as is for the time being and just let any incoming keys take precedence\n key: (to && (to as Location).key) || key || createKey(),\n };\n return location;\n}\n\n/**\n * Creates a string URL path from the given pathname, search, and hash components.\n */\nexport function createPath({\n pathname = \"/\",\n search = \"\",\n hash = \"\",\n}: Partial) {\n if (search && search !== \"?\")\n pathname += search.charAt(0) === \"?\" ? search : \"?\" + search;\n if (hash && hash !== \"#\")\n pathname += hash.charAt(0) === \"#\" ? hash : \"#\" + hash;\n return pathname;\n}\n\n/**\n * Parses a string URL path into its separate pathname, search, and hash components.\n */\nexport function parsePath(path: string): Partial {\n let parsedPath: Partial = {};\n\n if (path) {\n let hashIndex = path.indexOf(\"#\");\n if (hashIndex >= 0) {\n parsedPath.hash = path.substr(hashIndex);\n path = path.substr(0, hashIndex);\n }\n\n let searchIndex = path.indexOf(\"?\");\n if (searchIndex >= 0) {\n parsedPath.search = path.substr(searchIndex);\n path = path.substr(0, searchIndex);\n }\n\n if (path) {\n parsedPath.pathname = path;\n }\n }\n\n return parsedPath;\n}\n\nexport interface UrlHistory extends History {}\n\nexport type UrlHistoryOptions = {\n window?: Window;\n v5Compat?: boolean;\n};\n\nfunction getUrlBasedHistory(\n getLocation: (window: Window, globalHistory: Window[\"history\"]) => Location,\n createHref: (window: Window, to: To) => string,\n validateLocation: ((location: Location, to: To) => void) | null,\n options: UrlHistoryOptions = {}\n): UrlHistory {\n let { window = document.defaultView!, v5Compat = false } = options;\n let globalHistory = window.history;\n let action = Action.Pop;\n let listener: Listener | null = null;\n\n let index = getIndex()!;\n // Index should only be null when we initialize. If not, it's because the\n // user called history.pushState or history.replaceState directly, in which\n // case we should log a warning as it will result in bugs.\n if (index == null) {\n index = 0;\n globalHistory.replaceState({ ...globalHistory.state, idx: index }, \"\");\n }\n\n function getIndex(): number {\n let state = globalHistory.state || { idx: null };\n return state.idx;\n }\n\n function handlePop() {\n action = Action.Pop;\n let nextIndex = getIndex();\n let delta = nextIndex == null ? null : nextIndex - index;\n index = nextIndex;\n if (listener) {\n listener({ action, location: history.location, delta });\n }\n }\n\n function push(to: To, state?: any) {\n action = Action.Push;\n let location = createLocation(history.location, to, state);\n if (validateLocation) validateLocation(location, to);\n\n index = getIndex() + 1;\n let historyState = getHistoryState(location, index);\n let url = history.createHref(location);\n\n // try...catch because iOS limits us to 100 pushState calls :/\n try {\n globalHistory.pushState(historyState, \"\", url);\n } catch (error) {\n // If the exception is because `state` can't be serialized, let that throw\n // outwards just like a replace call would so the dev knows the cause\n // https://html.spec.whatwg.org/multipage/nav-history-apis.html#shared-history-push/replace-state-steps\n // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal\n if (error instanceof DOMException && error.name === \"DataCloneError\") {\n throw error;\n }\n // They are going to lose state here, but there is no real\n // way to warn them about it since the page will refresh...\n window.location.assign(url);\n }\n\n if (v5Compat && listener) {\n listener({ action, location: history.location, delta: 1 });\n }\n }\n\n function replace(to: To, state?: any) {\n action = Action.Replace;\n let location = createLocation(history.location, to, state);\n if (validateLocation) validateLocation(location, to);\n\n index = getIndex();\n let historyState = getHistoryState(location, index);\n let url = history.createHref(location);\n globalHistory.replaceState(historyState, \"\", url);\n\n if (v5Compat && listener) {\n listener({ action, location: history.location, delta: 0 });\n }\n }\n\n function createURL(to: To): URL {\n // window.location.origin is \"null\" (the literal string value) in Firefox\n // under certain conditions, notably when serving from a local HTML file\n // See https://bugzilla.mozilla.org/show_bug.cgi?id=878297\n let base =\n window.location.origin !== \"null\"\n ? window.location.origin\n : window.location.href;\n\n let href = typeof to === \"string\" ? to : createPath(to);\n invariant(\n base,\n `No window.location.(origin|href) available to create URL for href: ${href}`\n );\n return new URL(href, base);\n }\n\n let history: History = {\n get action() {\n return action;\n },\n get location() {\n return getLocation(window, globalHistory);\n },\n listen(fn: Listener) {\n if (listener) {\n throw new Error(\"A history only accepts one active listener\");\n }\n window.addEventListener(PopStateEventType, handlePop);\n listener = fn;\n\n return () => {\n window.removeEventListener(PopStateEventType, handlePop);\n listener = null;\n };\n },\n createHref(to) {\n return createHref(window, to);\n },\n createURL,\n encodeLocation(to) {\n // Encode a Location the same way window.location would\n let url = createURL(to);\n return {\n pathname: url.pathname,\n search: url.search,\n hash: url.hash,\n };\n },\n push,\n replace,\n go(n) {\n return globalHistory.go(n);\n },\n };\n\n return history;\n}\n\n//#endregion\n","import type { Location, Path, To } from \"./history\";\nimport { invariant, parsePath, warning } from \"./history\";\n\n/**\n * Map of routeId -> data returned from a loader/action/error\n */\nexport interface RouteData {\n [routeId: string]: any;\n}\n\nexport enum ResultType {\n data = \"data\",\n deferred = \"deferred\",\n redirect = \"redirect\",\n error = \"error\",\n}\n\n/**\n * Successful result from a loader or action\n */\nexport interface SuccessResult {\n type: ResultType.data;\n data: any;\n statusCode?: number;\n headers?: Headers;\n}\n\n/**\n * Successful defer() result from a loader or action\n */\nexport interface DeferredResult {\n type: ResultType.deferred;\n deferredData: DeferredData;\n statusCode?: number;\n headers?: Headers;\n}\n\n/**\n * Redirect result from a loader or action\n */\nexport interface RedirectResult {\n type: ResultType.redirect;\n status: number;\n location: string;\n revalidate: boolean;\n reloadDocument?: boolean;\n}\n\n/**\n * Unsuccessful result from a loader or action\n */\nexport interface ErrorResult {\n type: ResultType.error;\n error: any;\n headers?: Headers;\n}\n\n/**\n * Result from a loader or action - potentially successful or unsuccessful\n */\nexport type DataResult =\n | SuccessResult\n | DeferredResult\n | RedirectResult\n | ErrorResult;\n\ntype LowerCaseFormMethod = \"get\" | \"post\" | \"put\" | \"patch\" | \"delete\";\ntype UpperCaseFormMethod = Uppercase;\n\n/**\n * Users can specify either lowercase or uppercase form methods on `
`,\n * useSubmit(), ``, etc.\n */\nexport type HTMLFormMethod = LowerCaseFormMethod | UpperCaseFormMethod;\n\n/**\n * Active navigation/fetcher form methods are exposed in lowercase on the\n * RouterState\n */\nexport type FormMethod = LowerCaseFormMethod;\nexport type MutationFormMethod = Exclude;\n\n/**\n * In v7, active navigation/fetcher form methods are exposed in uppercase on the\n * RouterState. This is to align with the normalization done via fetch().\n */\nexport type V7_FormMethod = UpperCaseFormMethod;\nexport type V7_MutationFormMethod = Exclude;\n\nexport type FormEncType =\n | \"application/x-www-form-urlencoded\"\n | \"multipart/form-data\"\n | \"application/json\"\n | \"text/plain\";\n\n// Thanks https://github.com/sindresorhus/type-fest!\ntype JsonObject = { [Key in string]: JsonValue } & {\n [Key in string]?: JsonValue | undefined;\n};\ntype JsonArray = JsonValue[] | readonly JsonValue[];\ntype JsonPrimitive = string | number | boolean | null;\ntype JsonValue = JsonPrimitive | JsonObject | JsonArray;\n\n/**\n * @private\n * Internal interface to pass around for action submissions, not intended for\n * external consumption\n */\nexport type Submission =\n | {\n formMethod: FormMethod | V7_FormMethod;\n formAction: string;\n formEncType: FormEncType;\n formData: FormData;\n json: undefined;\n text: undefined;\n }\n | {\n formMethod: FormMethod | V7_FormMethod;\n formAction: string;\n formEncType: FormEncType;\n formData: undefined;\n json: JsonValue;\n text: undefined;\n }\n | {\n formMethod: FormMethod | V7_FormMethod;\n formAction: string;\n formEncType: FormEncType;\n formData: undefined;\n json: undefined;\n text: string;\n };\n\n/**\n * @private\n * Arguments passed to route loader/action functions. Same for now but we keep\n * this as a private implementation detail in case they diverge in the future.\n */\ninterface DataFunctionArgs {\n request: Request;\n params: Params;\n context?: Context;\n}\n\n// TODO: (v7) Change the defaults from any to unknown in and remove Remix wrappers:\n// ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs\n// Also, make them a type alias instead of an interface\n\n/**\n * Arguments passed to loader functions\n */\nexport interface LoaderFunctionArgs\n extends DataFunctionArgs {}\n\n/**\n * Arguments passed to action functions\n */\nexport interface ActionFunctionArgs\n extends DataFunctionArgs {}\n\n/**\n * Loaders and actions can return anything except `undefined` (`null` is a\n * valid return value if there is no data to return). Responses are preferred\n * and will ease any future migration to Remix\n */\ntype DataFunctionValue = Response | NonNullable | null;\n\n/**\n * Route loader function signature\n */\nexport interface LoaderFunction {\n (args: LoaderFunctionArgs):\n | Promise\n | DataFunctionValue;\n}\n\n/**\n * Route action function signature\n */\nexport interface ActionFunction {\n (args: ActionFunctionArgs):\n | Promise\n | DataFunctionValue;\n}\n\n/**\n * Arguments passed to shouldRevalidate function\n */\nexport interface ShouldRevalidateFunctionArgs {\n currentUrl: URL;\n currentParams: AgnosticDataRouteMatch[\"params\"];\n nextUrl: URL;\n nextParams: AgnosticDataRouteMatch[\"params\"];\n formMethod?: Submission[\"formMethod\"];\n formAction?: Submission[\"formAction\"];\n formEncType?: Submission[\"formEncType\"];\n text?: Submission[\"text\"];\n formData?: Submission[\"formData\"];\n json?: Submission[\"json\"];\n actionResult?: any;\n defaultShouldRevalidate: boolean;\n}\n\n/**\n * Route shouldRevalidate function signature. This runs after any submission\n * (navigation or fetcher), so we flatten the navigation/fetcher submission\n * onto the arguments. It shouldn't matter whether it came from a navigation\n * or a fetcher, what really matters is the URLs and the formData since loaders\n * have to re-run based on the data models that were potentially mutated.\n */\nexport interface ShouldRevalidateFunction {\n (args: ShouldRevalidateFunctionArgs): boolean;\n}\n\n/**\n * Function provided by the framework-aware layers to set `hasErrorBoundary`\n * from the framework-aware `errorElement` prop\n *\n * @deprecated Use `mapRouteProperties` instead\n */\nexport interface DetectErrorBoundaryFunction {\n (route: AgnosticRouteObject): boolean;\n}\n\n/**\n * Function provided by the framework-aware layers to set any framework-specific\n * properties from framework-agnostic properties\n */\nexport interface MapRoutePropertiesFunction {\n (route: AgnosticRouteObject): {\n hasErrorBoundary: boolean;\n } & Record;\n}\n\n/**\n * Keys we cannot change from within a lazy() function. We spread all other keys\n * onto the route. Either they're meaningful to the router, or they'll get\n * ignored.\n */\nexport type ImmutableRouteKey =\n | \"lazy\"\n | \"caseSensitive\"\n | \"path\"\n | \"id\"\n | \"index\"\n | \"children\";\n\nexport const immutableRouteKeys = new Set([\n \"lazy\",\n \"caseSensitive\",\n \"path\",\n \"id\",\n \"index\",\n \"children\",\n]);\n\ntype RequireOne = Exclude<\n {\n [K in keyof T]: K extends Key ? Omit & Required> : never;\n }[keyof T],\n undefined\n>;\n\n/**\n * lazy() function to load a route definition, which can add non-matching\n * related properties to a route\n */\nexport interface LazyRouteFunction {\n (): Promise>>;\n}\n\n/**\n * Base RouteObject with common props shared by all types of routes\n */\ntype AgnosticBaseRouteObject = {\n caseSensitive?: boolean;\n path?: string;\n id?: string;\n loader?: LoaderFunction;\n action?: ActionFunction;\n hasErrorBoundary?: boolean;\n shouldRevalidate?: ShouldRevalidateFunction;\n handle?: any;\n lazy?: LazyRouteFunction;\n};\n\n/**\n * Index routes must not have children\n */\nexport type AgnosticIndexRouteObject = AgnosticBaseRouteObject & {\n children?: undefined;\n index: true;\n};\n\n/**\n * Non-index routes may have children, but cannot have index\n */\nexport type AgnosticNonIndexRouteObject = AgnosticBaseRouteObject & {\n children?: AgnosticRouteObject[];\n index?: false;\n};\n\n/**\n * A route object represents a logical route, with (optionally) its child\n * routes organized in a tree-like structure.\n */\nexport type AgnosticRouteObject =\n | AgnosticIndexRouteObject\n | AgnosticNonIndexRouteObject;\n\nexport type AgnosticDataIndexRouteObject = AgnosticIndexRouteObject & {\n id: string;\n};\n\nexport type AgnosticDataNonIndexRouteObject = AgnosticNonIndexRouteObject & {\n children?: AgnosticDataRouteObject[];\n id: string;\n};\n\n/**\n * A data route object, which is just a RouteObject with a required unique ID\n */\nexport type AgnosticDataRouteObject =\n | AgnosticDataIndexRouteObject\n | AgnosticDataNonIndexRouteObject;\n\nexport type RouteManifest = Record;\n\n// Recursive helper for finding path parameters in the absence of wildcards\ntype _PathParam =\n // split path into individual path segments\n Path extends `${infer L}/${infer R}`\n ? _PathParam | _PathParam\n : // find params after `:`\n Path extends `:${infer Param}`\n ? Param extends `${infer Optional}?`\n ? Optional\n : Param\n : // otherwise, there aren't any params present\n never;\n\n/**\n * Examples:\n * \"/a/b/*\" -> \"*\"\n * \":a\" -> \"a\"\n * \"/a/:b\" -> \"b\"\n * \"/a/blahblahblah:b\" -> \"b\"\n * \"/:a/:b\" -> \"a\" | \"b\"\n * \"/:a/b/:c/*\" -> \"a\" | \"c\" | \"*\"\n */\ntype PathParam =\n // check if path is just a wildcard\n Path extends \"*\" | \"/*\"\n ? \"*\"\n : // look for wildcard at the end of the path\n Path extends `${infer Rest}/*`\n ? \"*\" | _PathParam\n : // look for params in the absence of wildcards\n _PathParam;\n\n// Attempt to parse the given string segment. If it fails, then just return the\n// plain string type as a default fallback. Otherwise, return the union of the\n// parsed string literals that were referenced as dynamic segments in the route.\nexport type ParamParseKey =\n // if you could not find path params, fallback to `string`\n [PathParam] extends [never] ? string : PathParam;\n\n/**\n * The parameters that were parsed from the URL path.\n */\nexport type Params = {\n readonly [key in Key]: string | undefined;\n};\n\n/**\n * A RouteMatch contains info about how a route matched a URL.\n */\nexport interface AgnosticRouteMatch<\n ParamKey extends string = string,\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n> {\n /**\n * The names and values of dynamic parameters in the URL.\n */\n params: Params;\n /**\n * The portion of the URL pathname that was matched.\n */\n pathname: string;\n /**\n * The portion of the URL pathname that was matched before child routes.\n */\n pathnameBase: string;\n /**\n * The route object that was used to match.\n */\n route: RouteObjectType;\n}\n\nexport interface AgnosticDataRouteMatch\n extends AgnosticRouteMatch {}\n\nfunction isIndexRoute(\n route: AgnosticRouteObject\n): route is AgnosticIndexRouteObject {\n return route.index === true;\n}\n\n// Walk the route tree generating unique IDs where necessary, so we are working\n// solely with AgnosticDataRouteObject's within the Router\nexport function convertRoutesToDataRoutes(\n routes: AgnosticRouteObject[],\n mapRouteProperties: MapRoutePropertiesFunction,\n parentPath: number[] = [],\n manifest: RouteManifest = {}\n): AgnosticDataRouteObject[] {\n return routes.map((route, index) => {\n let treePath = [...parentPath, index];\n let id = typeof route.id === \"string\" ? route.id : treePath.join(\"-\");\n invariant(\n route.index !== true || !route.children,\n `Cannot specify children on an index route`\n );\n invariant(\n !manifest[id],\n `Found a route id collision on id \"${id}\". Route ` +\n \"id's must be globally unique within Data Router usages\"\n );\n\n if (isIndexRoute(route)) {\n let indexRoute: AgnosticDataIndexRouteObject = {\n ...route,\n ...mapRouteProperties(route),\n id,\n };\n manifest[id] = indexRoute;\n return indexRoute;\n } else {\n let pathOrLayoutRoute: AgnosticDataNonIndexRouteObject = {\n ...route,\n ...mapRouteProperties(route),\n id,\n children: undefined,\n };\n manifest[id] = pathOrLayoutRoute;\n\n if (route.children) {\n pathOrLayoutRoute.children = convertRoutesToDataRoutes(\n route.children,\n mapRouteProperties,\n treePath,\n manifest\n );\n }\n\n return pathOrLayoutRoute;\n }\n });\n}\n\n/**\n * Matches the given routes to a location and returns the match data.\n *\n * @see https://reactrouter.com/utils/match-routes\n */\nexport function matchRoutes<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n>(\n routes: RouteObjectType[],\n locationArg: Partial | string,\n basename = \"/\"\n): AgnosticRouteMatch[] | null {\n let location =\n typeof locationArg === \"string\" ? parsePath(locationArg) : locationArg;\n\n let pathname = stripBasename(location.pathname || \"/\", basename);\n\n if (pathname == null) {\n return null;\n }\n\n let branches = flattenRoutes(routes);\n rankRouteBranches(branches);\n\n let matches = null;\n for (let i = 0; matches == null && i < branches.length; ++i) {\n matches = matchRouteBranch(\n branches[i],\n // Incoming pathnames are generally encoded from either window.location\n // or from router.navigate, but we want to match against the unencoded\n // paths in the route definitions. Memory router locations won't be\n // encoded here but there also shouldn't be anything to decode so this\n // should be a safe operation. This avoids needing matchRoutes to be\n // history-aware.\n safelyDecodeURI(pathname)\n );\n }\n\n return matches;\n}\n\nexport interface UIMatch {\n id: string;\n pathname: string;\n params: AgnosticRouteMatch[\"params\"];\n data: Data;\n handle: Handle;\n}\n\nexport function convertRouteMatchToUiMatch(\n match: AgnosticDataRouteMatch,\n loaderData: RouteData\n): UIMatch {\n let { route, pathname, params } = match;\n return {\n id: route.id,\n pathname,\n params,\n data: loaderData[route.id],\n handle: route.handle,\n };\n}\n\ninterface RouteMeta<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n> {\n relativePath: string;\n caseSensitive: boolean;\n childrenIndex: number;\n route: RouteObjectType;\n}\n\ninterface RouteBranch<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n> {\n path: string;\n score: number;\n routesMeta: RouteMeta[];\n}\n\nfunction flattenRoutes<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n>(\n routes: RouteObjectType[],\n branches: RouteBranch[] = [],\n parentsMeta: RouteMeta[] = [],\n parentPath = \"\"\n): RouteBranch[] {\n let flattenRoute = (\n route: RouteObjectType,\n index: number,\n relativePath?: string\n ) => {\n let meta: RouteMeta = {\n relativePath:\n relativePath === undefined ? route.path || \"\" : relativePath,\n caseSensitive: route.caseSensitive === true,\n childrenIndex: index,\n route,\n };\n\n if (meta.relativePath.startsWith(\"/\")) {\n invariant(\n meta.relativePath.startsWith(parentPath),\n `Absolute route path \"${meta.relativePath}\" nested under path ` +\n `\"${parentPath}\" is not valid. An absolute child route path ` +\n `must start with the combined path of all its parent routes.`\n );\n\n meta.relativePath = meta.relativePath.slice(parentPath.length);\n }\n\n let path = joinPaths([parentPath, meta.relativePath]);\n let routesMeta = parentsMeta.concat(meta);\n\n // Add the children before adding this route to the array, so we traverse the\n // route tree depth-first and child routes appear before their parents in\n // the \"flattened\" version.\n if (route.children && route.children.length > 0) {\n invariant(\n // Our types know better, but runtime JS may not!\n // @ts-expect-error\n route.index !== true,\n `Index routes must not have child routes. Please remove ` +\n `all child routes from route path \"${path}\".`\n );\n\n flattenRoutes(route.children, branches, routesMeta, path);\n }\n\n // Routes without a path shouldn't ever match by themselves unless they are\n // index routes, so don't add them to the list of possible branches.\n if (route.path == null && !route.index) {\n return;\n }\n\n branches.push({\n path,\n score: computeScore(path, route.index),\n routesMeta,\n });\n };\n routes.forEach((route, index) => {\n // coarse-grain check for optional params\n if (route.path === \"\" || !route.path?.includes(\"?\")) {\n flattenRoute(route, index);\n } else {\n for (let exploded of explodeOptionalSegments(route.path)) {\n flattenRoute(route, index, exploded);\n }\n }\n });\n\n return branches;\n}\n\n/**\n * Computes all combinations of optional path segments for a given path,\n * excluding combinations that are ambiguous and of lower priority.\n *\n * For example, `/one/:two?/three/:four?/:five?` explodes to:\n * - `/one/three`\n * - `/one/:two/three`\n * - `/one/three/:four`\n * - `/one/three/:five`\n * - `/one/:two/three/:four`\n * - `/one/:two/three/:five`\n * - `/one/three/:four/:five`\n * - `/one/:two/three/:four/:five`\n */\nfunction explodeOptionalSegments(path: string): string[] {\n let segments = path.split(\"/\");\n if (segments.length === 0) return [];\n\n let [first, ...rest] = segments;\n\n // Optional path segments are denoted by a trailing `?`\n let isOptional = first.endsWith(\"?\");\n // Compute the corresponding required segment: `foo?` -> `foo`\n let required = first.replace(/\\?$/, \"\");\n\n if (rest.length === 0) {\n // Intepret empty string as omitting an optional segment\n // `[\"one\", \"\", \"three\"]` corresponds to omitting `:two` from `/one/:two?/three` -> `/one/three`\n return isOptional ? [required, \"\"] : [required];\n }\n\n let restExploded = explodeOptionalSegments(rest.join(\"/\"));\n\n let result: string[] = [];\n\n // All child paths with the prefix. Do this for all children before the\n // optional version for all children, so we get consistent ordering where the\n // parent optional aspect is preferred as required. Otherwise, we can get\n // child sections interspersed where deeper optional segments are higher than\n // parent optional segments, where for example, /:two would explode _earlier_\n // then /:one. By always including the parent as required _for all children_\n // first, we avoid this issue\n result.push(\n ...restExploded.map((subpath) =>\n subpath === \"\" ? required : [required, subpath].join(\"/\")\n )\n );\n\n // Then, if this is an optional value, add all child versions without\n if (isOptional) {\n result.push(...restExploded);\n }\n\n // for absolute paths, ensure `/` instead of empty segment\n return result.map((exploded) =>\n path.startsWith(\"/\") && exploded === \"\" ? \"/\" : exploded\n );\n}\n\nfunction rankRouteBranches(branches: RouteBranch[]): void {\n branches.sort((a, b) =>\n a.score !== b.score\n ? b.score - a.score // Higher score first\n : compareIndexes(\n a.routesMeta.map((meta) => meta.childrenIndex),\n b.routesMeta.map((meta) => meta.childrenIndex)\n )\n );\n}\n\nconst paramRe = /^:\\w+$/;\nconst dynamicSegmentValue = 3;\nconst indexRouteValue = 2;\nconst emptySegmentValue = 1;\nconst staticSegmentValue = 10;\nconst splatPenalty = -2;\nconst isSplat = (s: string) => s === \"*\";\n\nfunction computeScore(path: string, index: boolean | undefined): number {\n let segments = path.split(\"/\");\n let initialScore = segments.length;\n if (segments.some(isSplat)) {\n initialScore += splatPenalty;\n }\n\n if (index) {\n initialScore += indexRouteValue;\n }\n\n return segments\n .filter((s) => !isSplat(s))\n .reduce(\n (score, segment) =>\n score +\n (paramRe.test(segment)\n ? dynamicSegmentValue\n : segment === \"\"\n ? emptySegmentValue\n : staticSegmentValue),\n initialScore\n );\n}\n\nfunction compareIndexes(a: number[], b: number[]): number {\n let siblings =\n a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);\n\n return siblings\n ? // If two routes are siblings, we should try to match the earlier sibling\n // first. This allows people to have fine-grained control over the matching\n // behavior by simply putting routes with identical paths in the order they\n // want them tried.\n a[a.length - 1] - b[b.length - 1]\n : // Otherwise, it doesn't really make sense to rank non-siblings by index,\n // so they sort equally.\n 0;\n}\n\nfunction matchRouteBranch<\n ParamKey extends string = string,\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n>(\n branch: RouteBranch,\n pathname: string\n): AgnosticRouteMatch[] | null {\n let { routesMeta } = branch;\n\n let matchedParams = {};\n let matchedPathname = \"/\";\n let matches: AgnosticRouteMatch[] = [];\n for (let i = 0; i < routesMeta.length; ++i) {\n let meta = routesMeta[i];\n let end = i === routesMeta.length - 1;\n let remainingPathname =\n matchedPathname === \"/\"\n ? pathname\n : pathname.slice(matchedPathname.length) || \"/\";\n let match = matchPath(\n { path: meta.relativePath, caseSensitive: meta.caseSensitive, end },\n remainingPathname\n );\n\n if (!match) return null;\n\n Object.assign(matchedParams, match.params);\n\n let route = meta.route;\n\n matches.push({\n // TODO: Can this as be avoided?\n params: matchedParams as Params,\n pathname: joinPaths([matchedPathname, match.pathname]),\n pathnameBase: normalizePathname(\n joinPaths([matchedPathname, match.pathnameBase])\n ),\n route,\n });\n\n if (match.pathnameBase !== \"/\") {\n matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);\n }\n }\n\n return matches;\n}\n\n/**\n * Returns a path with params interpolated.\n *\n * @see https://reactrouter.com/utils/generate-path\n */\nexport function generatePath(\n originalPath: Path,\n params: {\n [key in PathParam]: string | null;\n } = {} as any\n): string {\n let path: string = originalPath;\n if (path.endsWith(\"*\") && path !== \"*\" && !path.endsWith(\"/*\")) {\n warning(\n false,\n `Route path \"${path}\" will be treated as if it were ` +\n `\"${path.replace(/\\*$/, \"/*\")}\" because the \\`*\\` character must ` +\n `always follow a \\`/\\` in the pattern. To get rid of this warning, ` +\n `please change the route path to \"${path.replace(/\\*$/, \"/*\")}\".`\n );\n path = path.replace(/\\*$/, \"/*\") as Path;\n }\n\n // ensure `/` is added at the beginning if the path is absolute\n const prefix = path.startsWith(\"/\") ? \"/\" : \"\";\n\n const stringify = (p: any) =>\n p == null ? \"\" : typeof p === \"string\" ? p : String(p);\n\n const segments = path\n .split(/\\/+/)\n .map((segment, index, array) => {\n const isLastSegment = index === array.length - 1;\n\n // only apply the splat if it's the last segment\n if (isLastSegment && segment === \"*\") {\n const star = \"*\" as PathParam;\n // Apply the splat\n return stringify(params[star]);\n }\n\n const keyMatch = segment.match(/^:(\\w+)(\\??)$/);\n if (keyMatch) {\n const [, key, optional] = keyMatch;\n let param = params[key as PathParam];\n invariant(optional === \"?\" || param != null, `Missing \":${key}\" param`);\n return stringify(param);\n }\n\n // Remove any optional markers from optional static segments\n return segment.replace(/\\?$/g, \"\");\n })\n // Remove empty segments\n .filter((segment) => !!segment);\n\n return prefix + segments.join(\"/\");\n}\n\n/**\n * A PathPattern is used to match on some portion of a URL pathname.\n */\nexport interface PathPattern {\n /**\n * A string to match against a URL pathname. May contain `:id`-style segments\n * to indicate placeholders for dynamic parameters. May also end with `/*` to\n * indicate matching the rest of the URL pathname.\n */\n path: Path;\n /**\n * Should be `true` if the static portions of the `path` should be matched in\n * the same case.\n */\n caseSensitive?: boolean;\n /**\n * Should be `true` if this pattern should match the entire URL pathname.\n */\n end?: boolean;\n}\n\n/**\n * A PathMatch contains info about how a PathPattern matched on a URL pathname.\n */\nexport interface PathMatch {\n /**\n * The names and values of dynamic parameters in the URL.\n */\n params: Params;\n /**\n * The portion of the URL pathname that was matched.\n */\n pathname: string;\n /**\n * The portion of the URL pathname that was matched before child routes.\n */\n pathnameBase: string;\n /**\n * The pattern that was used to match.\n */\n pattern: PathPattern;\n}\n\ntype Mutable = {\n -readonly [P in keyof T]: T[P];\n};\n\n/**\n * Performs pattern matching on a URL pathname and returns information about\n * the match.\n *\n * @see https://reactrouter.com/utils/match-path\n */\nexport function matchPath<\n ParamKey extends ParamParseKey,\n Path extends string\n>(\n pattern: PathPattern | Path,\n pathname: string\n): PathMatch | null {\n if (typeof pattern === \"string\") {\n pattern = { path: pattern, caseSensitive: false, end: true };\n }\n\n let [matcher, compiledParams] = compilePath(\n pattern.path,\n pattern.caseSensitive,\n pattern.end\n );\n\n let match = pathname.match(matcher);\n if (!match) return null;\n\n let matchedPathname = match[0];\n let pathnameBase = matchedPathname.replace(/(.)\\/+$/, \"$1\");\n let captureGroups = match.slice(1);\n let params: Params = compiledParams.reduce>(\n (memo, { paramName, isOptional }, index) => {\n // We need to compute the pathnameBase here using the raw splat value\n // instead of using params[\"*\"] later because it will be decoded then\n if (paramName === \"*\") {\n let splatValue = captureGroups[index] || \"\";\n pathnameBase = matchedPathname\n .slice(0, matchedPathname.length - splatValue.length)\n .replace(/(.)\\/+$/, \"$1\");\n }\n\n const value = captureGroups[index];\n if (isOptional && !value) {\n memo[paramName] = undefined;\n } else {\n memo[paramName] = safelyDecodeURIComponent(value || \"\", paramName);\n }\n return memo;\n },\n {}\n );\n\n return {\n params,\n pathname: matchedPathname,\n pathnameBase,\n pattern,\n };\n}\n\ntype CompiledPathParam = { paramName: string; isOptional?: boolean };\n\nfunction compilePath(\n path: string,\n caseSensitive = false,\n end = true\n): [RegExp, CompiledPathParam[]] {\n warning(\n path === \"*\" || !path.endsWith(\"*\") || path.endsWith(\"/*\"),\n `Route path \"${path}\" will be treated as if it were ` +\n `\"${path.replace(/\\*$/, \"/*\")}\" because the \\`*\\` character must ` +\n `always follow a \\`/\\` in the pattern. To get rid of this warning, ` +\n `please change the route path to \"${path.replace(/\\*$/, \"/*\")}\".`\n );\n\n let params: CompiledPathParam[] = [];\n let regexpSource =\n \"^\" +\n path\n .replace(/\\/*\\*?$/, \"\") // Ignore trailing / and /*, we'll handle it below\n .replace(/^\\/*/, \"/\") // Make sure it has a leading /\n .replace(/[\\\\.*+^${}|()[\\]]/g, \"\\\\$&\") // Escape special regex chars\n .replace(/\\/:(\\w+)(\\?)?/g, (_: string, paramName: string, isOptional) => {\n params.push({ paramName, isOptional: isOptional != null });\n return isOptional ? \"/?([^\\\\/]+)?\" : \"/([^\\\\/]+)\";\n });\n\n if (path.endsWith(\"*\")) {\n params.push({ paramName: \"*\" });\n regexpSource +=\n path === \"*\" || path === \"/*\"\n ? \"(.*)$\" // Already matched the initial /, just match the rest\n : \"(?:\\\\/(.+)|\\\\/*)$\"; // Don't include the / in params[\"*\"]\n } else if (end) {\n // When matching to the end, ignore trailing slashes\n regexpSource += \"\\\\/*$\";\n } else if (path !== \"\" && path !== \"/\") {\n // If our path is non-empty and contains anything beyond an initial slash,\n // then we have _some_ form of path in our regex, so we should expect to\n // match only if we find the end of this path segment. Look for an optional\n // non-captured trailing slash (to match a portion of the URL) or the end\n // of the path (if we've matched to the end). We used to do this with a\n // word boundary but that gives false positives on routes like\n // /user-preferences since `-` counts as a word boundary.\n regexpSource += \"(?:(?=\\\\/|$))\";\n } else {\n // Nothing to match for \"\" or \"/\"\n }\n\n let matcher = new RegExp(regexpSource, caseSensitive ? undefined : \"i\");\n\n return [matcher, params];\n}\n\nfunction safelyDecodeURI(value: string) {\n try {\n return decodeURI(value);\n } catch (error) {\n warning(\n false,\n `The URL path \"${value}\" could not be decoded because it is is a ` +\n `malformed URL segment. This is probably due to a bad percent ` +\n `encoding (${error}).`\n );\n\n return value;\n }\n}\n\nfunction safelyDecodeURIComponent(value: string, paramName: string) {\n try {\n return decodeURIComponent(value);\n } catch (error) {\n warning(\n false,\n `The value for the URL param \"${paramName}\" will not be decoded because` +\n ` the string \"${value}\" is a malformed URL segment. This is probably` +\n ` due to a bad percent encoding (${error}).`\n );\n\n return value;\n }\n}\n\n/**\n * @private\n */\nexport function stripBasename(\n pathname: string,\n basename: string\n): string | null {\n if (basename === \"/\") return pathname;\n\n if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {\n return null;\n }\n\n // We want to leave trailing slash behavior in the user's control, so if they\n // specify a basename with a trailing slash, we should support it\n let startIndex = basename.endsWith(\"/\")\n ? basename.length - 1\n : basename.length;\n let nextChar = pathname.charAt(startIndex);\n if (nextChar && nextChar !== \"/\") {\n // pathname does not start with basename/\n return null;\n }\n\n return pathname.slice(startIndex) || \"/\";\n}\n\n/**\n * Returns a resolved path object relative to the given pathname.\n *\n * @see https://reactrouter.com/utils/resolve-path\n */\nexport function resolvePath(to: To, fromPathname = \"/\"): Path {\n let {\n pathname: toPathname,\n search = \"\",\n hash = \"\",\n } = typeof to === \"string\" ? parsePath(to) : to;\n\n let pathname = toPathname\n ? toPathname.startsWith(\"/\")\n ? toPathname\n : resolvePathname(toPathname, fromPathname)\n : fromPathname;\n\n return {\n pathname,\n search: normalizeSearch(search),\n hash: normalizeHash(hash),\n };\n}\n\nfunction resolvePathname(relativePath: string, fromPathname: string): string {\n let segments = fromPathname.replace(/\\/+$/, \"\").split(\"/\");\n let relativeSegments = relativePath.split(\"/\");\n\n relativeSegments.forEach((segment) => {\n if (segment === \"..\") {\n // Keep the root \"\" segment so the pathname starts at /\n if (segments.length > 1) segments.pop();\n } else if (segment !== \".\") {\n segments.push(segment);\n }\n });\n\n return segments.length > 1 ? segments.join(\"/\") : \"/\";\n}\n\nfunction getInvalidPathError(\n char: string,\n field: string,\n dest: string,\n path: Partial\n) {\n return (\n `Cannot include a '${char}' character in a manually specified ` +\n `\\`to.${field}\\` field [${JSON.stringify(\n path\n )}]. Please separate it out to the ` +\n `\\`to.${dest}\\` field. Alternatively you may provide the full path as ` +\n `a string in and the router will parse it for you.`\n );\n}\n\n/**\n * @private\n *\n * When processing relative navigation we want to ignore ancestor routes that\n * do not contribute to the path, such that index/pathless layout routes don't\n * interfere.\n *\n * For example, when moving a route element into an index route and/or a\n * pathless layout route, relative link behavior contained within should stay\n * the same. Both of the following examples should link back to the root:\n *\n * \n * \n * \n *\n * \n * \n * }> // <-- Does not contribute\n * // <-- Does not contribute\n * \n * \n */\nexport function getPathContributingMatches<\n T extends AgnosticRouteMatch = AgnosticRouteMatch\n>(matches: T[]) {\n return matches.filter(\n (match, index) =>\n index === 0 || (match.route.path && match.route.path.length > 0)\n );\n}\n\n/**\n * @private\n */\nexport function resolveTo(\n toArg: To,\n routePathnames: string[],\n locationPathname: string,\n isPathRelative = false\n): Path {\n let to: Partial;\n if (typeof toArg === \"string\") {\n to = parsePath(toArg);\n } else {\n to = { ...toArg };\n\n invariant(\n !to.pathname || !to.pathname.includes(\"?\"),\n getInvalidPathError(\"?\", \"pathname\", \"search\", to)\n );\n invariant(\n !to.pathname || !to.pathname.includes(\"#\"),\n getInvalidPathError(\"#\", \"pathname\", \"hash\", to)\n );\n invariant(\n !to.search || !to.search.includes(\"#\"),\n getInvalidPathError(\"#\", \"search\", \"hash\", to)\n );\n }\n\n let isEmptyPath = toArg === \"\" || to.pathname === \"\";\n let toPathname = isEmptyPath ? \"/\" : to.pathname;\n\n let from: string;\n\n // Routing is relative to the current pathname if explicitly requested.\n //\n // If a pathname is explicitly provided in `to`, it should be relative to the\n // route context. This is explained in `Note on `` values` in our\n // migration guide from v5 as a means of disambiguation between `to` values\n // that begin with `/` and those that do not. However, this is problematic for\n // `to` values that do not provide a pathname. `to` can simply be a search or\n // hash string, in which case we should assume that the navigation is relative\n // to the current location's pathname and *not* the route pathname.\n if (isPathRelative || toPathname == null) {\n from = locationPathname;\n } else {\n let routePathnameIndex = routePathnames.length - 1;\n\n if (toPathname.startsWith(\"..\")) {\n let toSegments = toPathname.split(\"/\");\n\n // Each leading .. segment means \"go up one route\" instead of \"go up one\n // URL segment\". This is a key difference from how works and a\n // major reason we call this a \"to\" value instead of a \"href\".\n while (toSegments[0] === \"..\") {\n toSegments.shift();\n routePathnameIndex -= 1;\n }\n\n to.pathname = toSegments.join(\"/\");\n }\n\n // If there are more \"..\" segments than parent routes, resolve relative to\n // the root / URL.\n from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : \"/\";\n }\n\n let path = resolvePath(to, from);\n\n // Ensure the pathname has a trailing slash if the original \"to\" had one\n let hasExplicitTrailingSlash =\n toPathname && toPathname !== \"/\" && toPathname.endsWith(\"/\");\n // Or if this was a link to the current path which has a trailing slash\n let hasCurrentTrailingSlash =\n (isEmptyPath || toPathname === \".\") && locationPathname.endsWith(\"/\");\n if (\n !path.pathname.endsWith(\"/\") &&\n (hasExplicitTrailingSlash || hasCurrentTrailingSlash)\n ) {\n path.pathname += \"/\";\n }\n\n return path;\n}\n\n/**\n * @private\n */\nexport function getToPathname(to: To): string | undefined {\n // Empty strings should be treated the same as / paths\n return to === \"\" || (to as Path).pathname === \"\"\n ? \"/\"\n : typeof to === \"string\"\n ? parsePath(to).pathname\n : to.pathname;\n}\n\n/**\n * @private\n */\nexport const joinPaths = (paths: string[]): string =>\n paths.join(\"/\").replace(/\\/\\/+/g, \"/\");\n\n/**\n * @private\n */\nexport const normalizePathname = (pathname: string): string =>\n pathname.replace(/\\/+$/, \"\").replace(/^\\/*/, \"/\");\n\n/**\n * @private\n */\nexport const normalizeSearch = (search: string): string =>\n !search || search === \"?\"\n ? \"\"\n : search.startsWith(\"?\")\n ? search\n : \"?\" + search;\n\n/**\n * @private\n */\nexport const normalizeHash = (hash: string): string =>\n !hash || hash === \"#\" ? \"\" : hash.startsWith(\"#\") ? hash : \"#\" + hash;\n\nexport type JsonFunction = (\n data: Data,\n init?: number | ResponseInit\n) => Response;\n\n/**\n * This is a shortcut for creating `application/json` responses. Converts `data`\n * to JSON and sets the `Content-Type` header.\n */\nexport const json: JsonFunction = (data, init = {}) => {\n let responseInit = typeof init === \"number\" ? { status: init } : init;\n\n let headers = new Headers(responseInit.headers);\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json; charset=utf-8\");\n }\n\n return new Response(JSON.stringify(data), {\n ...responseInit,\n headers,\n });\n};\n\nexport interface TrackedPromise extends Promise {\n _tracked?: boolean;\n _data?: any;\n _error?: any;\n}\n\nexport class AbortedDeferredError extends Error {}\n\nexport class DeferredData {\n private pendingKeysSet: Set = new Set();\n private controller: AbortController;\n private abortPromise: Promise;\n private unlistenAbortSignal: () => void;\n private subscribers: Set<(aborted: boolean, settledKey?: string) => void> =\n new Set();\n data: Record;\n init?: ResponseInit;\n deferredKeys: string[] = [];\n\n constructor(data: Record, responseInit?: ResponseInit) {\n invariant(\n data && typeof data === \"object\" && !Array.isArray(data),\n \"defer() only accepts plain objects\"\n );\n\n // Set up an AbortController + Promise we can race against to exit early\n // cancellation\n let reject: (e: AbortedDeferredError) => void;\n this.abortPromise = new Promise((_, r) => (reject = r));\n this.controller = new AbortController();\n let onAbort = () =>\n reject(new AbortedDeferredError(\"Deferred data aborted\"));\n this.unlistenAbortSignal = () =>\n this.controller.signal.removeEventListener(\"abort\", onAbort);\n this.controller.signal.addEventListener(\"abort\", onAbort);\n\n this.data = Object.entries(data).reduce(\n (acc, [key, value]) =>\n Object.assign(acc, {\n [key]: this.trackPromise(key, value),\n }),\n {}\n );\n\n if (this.done) {\n // All incoming values were resolved\n this.unlistenAbortSignal();\n }\n\n this.init = responseInit;\n }\n\n private trackPromise(\n key: string,\n value: Promise | unknown\n ): TrackedPromise | unknown {\n if (!(value instanceof Promise)) {\n return value;\n }\n\n this.deferredKeys.push(key);\n this.pendingKeysSet.add(key);\n\n // We store a little wrapper promise that will be extended with\n // _data/_error props upon resolve/reject\n let promise: TrackedPromise = Promise.race([value, this.abortPromise]).then(\n (data) => this.onSettle(promise, key, undefined, data as unknown),\n (error) => this.onSettle(promise, key, error as unknown)\n );\n\n // Register rejection listeners to avoid uncaught promise rejections on\n // errors or aborted deferred values\n promise.catch(() => {});\n\n Object.defineProperty(promise, \"_tracked\", { get: () => true });\n return promise;\n }\n\n private onSettle(\n promise: TrackedPromise,\n key: string,\n error: unknown,\n data?: unknown\n ): unknown {\n if (\n this.controller.signal.aborted &&\n error instanceof AbortedDeferredError\n ) {\n this.unlistenAbortSignal();\n Object.defineProperty(promise, \"_error\", { get: () => error });\n return Promise.reject(error);\n }\n\n this.pendingKeysSet.delete(key);\n\n if (this.done) {\n // Nothing left to abort!\n this.unlistenAbortSignal();\n }\n\n // If the promise was resolved/rejected with undefined, we'll throw an error as you\n // should always resolve with a value or null\n if (error === undefined && data === undefined) {\n let undefinedError = new Error(\n `Deferred data for key \"${key}\" resolved/rejected with \\`undefined\\`, ` +\n `you must resolve/reject with a value or \\`null\\`.`\n );\n Object.defineProperty(promise, \"_error\", { get: () => undefinedError });\n this.emit(false, key);\n return Promise.reject(undefinedError);\n }\n\n if (data === undefined) {\n Object.defineProperty(promise, \"_error\", { get: () => error });\n this.emit(false, key);\n return Promise.reject(error);\n }\n\n Object.defineProperty(promise, \"_data\", { get: () => data });\n this.emit(false, key);\n return data;\n }\n\n private emit(aborted: boolean, settledKey?: string) {\n this.subscribers.forEach((subscriber) => subscriber(aborted, settledKey));\n }\n\n subscribe(fn: (aborted: boolean, settledKey?: string) => void) {\n this.subscribers.add(fn);\n return () => this.subscribers.delete(fn);\n }\n\n cancel() {\n this.controller.abort();\n this.pendingKeysSet.forEach((v, k) => this.pendingKeysSet.delete(k));\n this.emit(true);\n }\n\n async resolveData(signal: AbortSignal) {\n let aborted = false;\n if (!this.done) {\n let onAbort = () => this.cancel();\n signal.addEventListener(\"abort\", onAbort);\n aborted = await new Promise((resolve) => {\n this.subscribe((aborted) => {\n signal.removeEventListener(\"abort\", onAbort);\n if (aborted || this.done) {\n resolve(aborted);\n }\n });\n });\n }\n return aborted;\n }\n\n get done() {\n return this.pendingKeysSet.size === 0;\n }\n\n get unwrappedData() {\n invariant(\n this.data !== null && this.done,\n \"Can only unwrap data on initialized and settled deferreds\"\n );\n\n return Object.entries(this.data).reduce(\n (acc, [key, value]) =>\n Object.assign(acc, {\n [key]: unwrapTrackedPromise(value),\n }),\n {}\n );\n }\n\n get pendingKeys() {\n return Array.from(this.pendingKeysSet);\n }\n}\n\nfunction isTrackedPromise(value: any): value is TrackedPromise {\n return (\n value instanceof Promise && (value as TrackedPromise)._tracked === true\n );\n}\n\nfunction unwrapTrackedPromise(value: any) {\n if (!isTrackedPromise(value)) {\n return value;\n }\n\n if (value._error) {\n throw value._error;\n }\n return value._data;\n}\n\nexport type DeferFunction = (\n data: Record,\n init?: number | ResponseInit\n) => DeferredData;\n\nexport const defer: DeferFunction = (data, init = {}) => {\n let responseInit = typeof init === \"number\" ? { status: init } : init;\n\n return new DeferredData(data, responseInit);\n};\n\nexport type RedirectFunction = (\n url: string,\n init?: number | ResponseInit\n) => Response;\n\n/**\n * A redirect response. Sets the status code and the `Location` header.\n * Defaults to \"302 Found\".\n */\nexport const redirect: RedirectFunction = (url, init = 302) => {\n let responseInit = init;\n if (typeof responseInit === \"number\") {\n responseInit = { status: responseInit };\n } else if (typeof responseInit.status === \"undefined\") {\n responseInit.status = 302;\n }\n\n let headers = new Headers(responseInit.headers);\n headers.set(\"Location\", url);\n\n return new Response(null, {\n ...responseInit,\n headers,\n });\n};\n\n/**\n * A redirect response that will force a document reload to the new location.\n * Sets the status code and the `Location` header.\n * Defaults to \"302 Found\".\n */\nexport const redirectDocument: RedirectFunction = (url, init) => {\n let response = redirect(url, init);\n response.headers.set(\"X-Remix-Reload-Document\", \"true\");\n return response;\n};\n\nexport type ErrorResponse = {\n status: number;\n statusText: string;\n data: any;\n};\n\n/**\n * @private\n * Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies\n *\n * We don't export the class for public use since it's an implementation\n * detail, but we export the interface above so folks can build their own\n * abstractions around instances via isRouteErrorResponse()\n */\nexport class ErrorResponseImpl implements ErrorResponse {\n status: number;\n statusText: string;\n data: any;\n private error?: Error;\n private internal: boolean;\n\n constructor(\n status: number,\n statusText: string | undefined,\n data: any,\n internal = false\n ) {\n this.status = status;\n this.statusText = statusText || \"\";\n this.internal = internal;\n if (data instanceof Error) {\n this.data = data.toString();\n this.error = data;\n } else {\n this.data = data;\n }\n }\n}\n\n/**\n * Check if the given error is an ErrorResponse generated from a 4xx/5xx\n * Response thrown from an action/loader\n */\nexport function isRouteErrorResponse(error: any): error is ErrorResponse {\n return (\n error != null &&\n typeof error.status === \"number\" &&\n typeof error.statusText === \"string\" &&\n typeof error.internal === \"boolean\" &&\n \"data\" in error\n );\n}\n","import type { History, Location, Path, To } from \"./history\";\nimport {\n Action as HistoryAction,\n createLocation,\n createPath,\n invariant,\n parsePath,\n warning,\n} from \"./history\";\nimport type {\n ActionFunction,\n AgnosticDataRouteMatch,\n AgnosticDataRouteObject,\n AgnosticRouteObject,\n DataResult,\n DeferredData,\n DeferredResult,\n DetectErrorBoundaryFunction,\n ErrorResult,\n FormEncType,\n FormMethod,\n HTMLFormMethod,\n ImmutableRouteKey,\n LoaderFunction,\n MapRoutePropertiesFunction,\n MutationFormMethod,\n RedirectResult,\n RouteData,\n RouteManifest,\n ShouldRevalidateFunctionArgs,\n Submission,\n SuccessResult,\n UIMatch,\n V7_FormMethod,\n V7_MutationFormMethod,\n} from \"./utils\";\nimport {\n ErrorResponseImpl,\n ResultType,\n convertRouteMatchToUiMatch,\n convertRoutesToDataRoutes,\n getPathContributingMatches,\n immutableRouteKeys,\n isRouteErrorResponse,\n joinPaths,\n matchRoutes,\n resolveTo,\n stripBasename,\n} from \"./utils\";\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Types and Constants\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A Router instance manages all navigation and data loading/mutations\n */\nexport interface Router {\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the basename for the router\n */\n get basename(): RouterInit[\"basename\"];\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the current state of the router\n */\n get state(): RouterState;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the routes for this router instance\n */\n get routes(): AgnosticDataRouteObject[];\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the window associated with the router\n */\n get window(): RouterInit[\"window\"];\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Initialize the router, including adding history listeners and kicking off\n * initial data fetches. Returns a function to cleanup listeners and abort\n * any in-progress loads\n */\n initialize(): Router;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Subscribe to router.state updates\n *\n * @param fn function to call with the new state\n */\n subscribe(fn: RouterSubscriber): () => void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Enable scroll restoration behavior in the router\n *\n * @param savedScrollPositions Object that will manage positions, in case\n * it's being restored from sessionStorage\n * @param getScrollPosition Function to get the active Y scroll position\n * @param getKey Function to get the key to use for restoration\n */\n enableScrollRestoration(\n savedScrollPositions: Record,\n getScrollPosition: GetScrollPositionFunction,\n getKey?: GetScrollRestorationKeyFunction\n ): () => void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Navigate forward/backward in the history stack\n * @param to Delta to move in the history stack\n */\n navigate(to: number): Promise;\n\n /**\n * Navigate to the given path\n * @param to Path to navigate to\n * @param opts Navigation options (method, submission, etc.)\n */\n navigate(to: To | null, opts?: RouterNavigateOptions): Promise;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Trigger a fetcher load/submission\n *\n * @param key Fetcher key\n * @param routeId Route that owns the fetcher\n * @param href href to fetch\n * @param opts Fetcher options, (method, submission, etc.)\n */\n fetch(\n key: string,\n routeId: string,\n href: string | null,\n opts?: RouterFetchOptions\n ): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Trigger a revalidation of all current route loaders and fetcher loads\n */\n revalidate(): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Utility function to create an href for the given location\n * @param location\n */\n createHref(location: Location | URL): string;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Utility function to URL encode a destination path according to the internal\n * history implementation\n * @param to\n */\n encodeLocation(to: To): Path;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Get/create a fetcher for the given key\n * @param key\n */\n getFetcher(key: string): Fetcher;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Delete the fetcher for a given key\n * @param key\n */\n deleteFetcher(key: string): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Cleanup listeners and abort any in-progress loads\n */\n dispose(): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Get a navigation blocker\n * @param key The identifier for the blocker\n * @param fn The blocker function implementation\n */\n getBlocker(key: string, fn: BlockerFunction): Blocker;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Delete a navigation blocker\n * @param key The identifier for the blocker\n */\n deleteBlocker(key: string): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * HMR needs to pass in-flight route updates to React Router\n * TODO: Replace this with granular route update APIs (addRoute, updateRoute, deleteRoute)\n */\n _internalSetRoutes(routes: AgnosticRouteObject[]): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Internal fetch AbortControllers accessed by unit tests\n */\n _internalFetchControllers: Map;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Internal pending DeferredData instances accessed by unit tests\n */\n _internalActiveDeferreds: Map;\n}\n\n/**\n * State maintained internally by the router. During a navigation, all states\n * reflect the the \"old\" location unless otherwise noted.\n */\nexport interface RouterState {\n /**\n * The action of the most recent navigation\n */\n historyAction: HistoryAction;\n\n /**\n * The current location reflected by the router\n */\n location: Location;\n\n /**\n * The current set of route matches\n */\n matches: AgnosticDataRouteMatch[];\n\n /**\n * Tracks whether we've completed our initial data load\n */\n initialized: boolean;\n\n /**\n * Current scroll position we should start at for a new view\n * - number -> scroll position to restore to\n * - false -> do not restore scroll at all (used during submissions)\n * - null -> don't have a saved position, scroll to hash or top of page\n */\n restoreScrollPosition: number | false | null;\n\n /**\n * Indicate whether this navigation should skip resetting the scroll position\n * if we are unable to restore the scroll position\n */\n preventScrollReset: boolean;\n\n /**\n * Tracks the state of the current navigation\n */\n navigation: Navigation;\n\n /**\n * Tracks any in-progress revalidations\n */\n revalidation: RevalidationState;\n\n /**\n * Data from the loaders for the current matches\n */\n loaderData: RouteData;\n\n /**\n * Data from the action for the current matches\n */\n actionData: RouteData | null;\n\n /**\n * Errors caught from loaders for the current matches\n */\n errors: RouteData | null;\n\n /**\n * Map of current fetchers\n */\n fetchers: Map;\n\n /**\n * Map of current blockers\n */\n blockers: Map;\n}\n\n/**\n * Data that can be passed into hydrate a Router from SSR\n */\nexport type HydrationState = Partial<\n Pick\n>;\n\n/**\n * Future flags to toggle new feature behavior\n */\nexport interface FutureConfig {\n v7_fetcherPersist: boolean;\n v7_normalizeFormMethod: boolean;\n v7_prependBasename: boolean;\n}\n\n/**\n * Initialization options for createRouter\n */\nexport interface RouterInit {\n routes: AgnosticRouteObject[];\n history: History;\n basename?: string;\n /**\n * @deprecated Use `mapRouteProperties` instead\n */\n detectErrorBoundary?: DetectErrorBoundaryFunction;\n mapRouteProperties?: MapRoutePropertiesFunction;\n future?: Partial;\n hydrationData?: HydrationState;\n window?: Window;\n}\n\n/**\n * State returned from a server-side query() call\n */\nexport interface StaticHandlerContext {\n basename: Router[\"basename\"];\n location: RouterState[\"location\"];\n matches: RouterState[\"matches\"];\n loaderData: RouterState[\"loaderData\"];\n actionData: RouterState[\"actionData\"];\n errors: RouterState[\"errors\"];\n statusCode: number;\n loaderHeaders: Record;\n actionHeaders: Record;\n activeDeferreds: Record | null;\n _deepestRenderedBoundaryId?: string | null;\n}\n\n/**\n * A StaticHandler instance manages a singular SSR navigation/fetch event\n */\nexport interface StaticHandler {\n dataRoutes: AgnosticDataRouteObject[];\n query(\n request: Request,\n opts?: { requestContext?: unknown }\n ): Promise;\n queryRoute(\n request: Request,\n opts?: { routeId?: string; requestContext?: unknown }\n ): Promise;\n}\n\ntype ViewTransitionOpts = {\n currentLocation: Location;\n nextLocation: Location;\n};\n\n/**\n * Subscriber function signature for changes to router state\n */\nexport interface RouterSubscriber {\n (\n state: RouterState,\n opts: {\n deletedFetchers: string[];\n unstable_viewTransitionOpts?: ViewTransitionOpts;\n }\n ): void;\n}\n\n/**\n * Function signature for determining the key to be used in scroll restoration\n * for a given location\n */\nexport interface GetScrollRestorationKeyFunction {\n (location: Location, matches: UIMatch[]): string | null;\n}\n\n/**\n * Function signature for determining the current scroll position\n */\nexport interface GetScrollPositionFunction {\n (): number;\n}\n\nexport type RelativeRoutingType = \"route\" | \"path\";\n\n// Allowed for any navigation or fetch\ntype BaseNavigateOrFetchOptions = {\n preventScrollReset?: boolean;\n relative?: RelativeRoutingType;\n};\n\n// Only allowed for navigations\ntype BaseNavigateOptions = BaseNavigateOrFetchOptions & {\n replace?: boolean;\n state?: any;\n fromRouteId?: string;\n unstable_viewTransition?: boolean;\n};\n\n// Only allowed for submission navigations\ntype BaseSubmissionOptions = {\n formMethod?: HTMLFormMethod;\n formEncType?: FormEncType;\n} & (\n | { formData: FormData; body?: undefined }\n | { formData?: undefined; body: any }\n);\n\n/**\n * Options for a navigate() call for a normal (non-submission) navigation\n */\ntype LinkNavigateOptions = BaseNavigateOptions;\n\n/**\n * Options for a navigate() call for a submission navigation\n */\ntype SubmissionNavigateOptions = BaseNavigateOptions & BaseSubmissionOptions;\n\n/**\n * Options to pass to navigate() for a navigation\n */\nexport type RouterNavigateOptions =\n | LinkNavigateOptions\n | SubmissionNavigateOptions;\n\n/**\n * Options for a fetch() load\n */\ntype LoadFetchOptions = BaseNavigateOrFetchOptions;\n\n/**\n * Options for a fetch() submission\n */\ntype SubmitFetchOptions = BaseNavigateOrFetchOptions & BaseSubmissionOptions;\n\n/**\n * Options to pass to fetch()\n */\nexport type RouterFetchOptions = LoadFetchOptions | SubmitFetchOptions;\n\n/**\n * Potential states for state.navigation\n */\nexport type NavigationStates = {\n Idle: {\n state: \"idle\";\n location: undefined;\n formMethod: undefined;\n formAction: undefined;\n formEncType: undefined;\n formData: undefined;\n json: undefined;\n text: undefined;\n };\n Loading: {\n state: \"loading\";\n location: Location;\n formMethod: Submission[\"formMethod\"] | undefined;\n formAction: Submission[\"formAction\"] | undefined;\n formEncType: Submission[\"formEncType\"] | undefined;\n formData: Submission[\"formData\"] | undefined;\n json: Submission[\"json\"] | undefined;\n text: Submission[\"text\"] | undefined;\n };\n Submitting: {\n state: \"submitting\";\n location: Location;\n formMethod: Submission[\"formMethod\"];\n formAction: Submission[\"formAction\"];\n formEncType: Submission[\"formEncType\"];\n formData: Submission[\"formData\"];\n json: Submission[\"json\"];\n text: Submission[\"text\"];\n };\n};\n\nexport type Navigation = NavigationStates[keyof NavigationStates];\n\nexport type RevalidationState = \"idle\" | \"loading\";\n\n/**\n * Potential states for fetchers\n */\ntype FetcherStates = {\n Idle: {\n state: \"idle\";\n formMethod: undefined;\n formAction: undefined;\n formEncType: undefined;\n text: undefined;\n formData: undefined;\n json: undefined;\n data: TData | undefined;\n };\n Loading: {\n state: \"loading\";\n formMethod: Submission[\"formMethod\"] | undefined;\n formAction: Submission[\"formAction\"] | undefined;\n formEncType: Submission[\"formEncType\"] | undefined;\n text: Submission[\"text\"] | undefined;\n formData: Submission[\"formData\"] | undefined;\n json: Submission[\"json\"] | undefined;\n data: TData | undefined;\n };\n Submitting: {\n state: \"submitting\";\n formMethod: Submission[\"formMethod\"];\n formAction: Submission[\"formAction\"];\n formEncType: Submission[\"formEncType\"];\n text: Submission[\"text\"];\n formData: Submission[\"formData\"];\n json: Submission[\"json\"];\n data: TData | undefined;\n };\n};\n\nexport type Fetcher =\n FetcherStates[keyof FetcherStates];\n\ninterface BlockerBlocked {\n state: \"blocked\";\n reset(): void;\n proceed(): void;\n location: Location;\n}\n\ninterface BlockerUnblocked {\n state: \"unblocked\";\n reset: undefined;\n proceed: undefined;\n location: undefined;\n}\n\ninterface BlockerProceeding {\n state: \"proceeding\";\n reset: undefined;\n proceed: undefined;\n location: Location;\n}\n\nexport type Blocker = BlockerUnblocked | BlockerBlocked | BlockerProceeding;\n\nexport type BlockerFunction = (args: {\n currentLocation: Location;\n nextLocation: Location;\n historyAction: HistoryAction;\n}) => boolean;\n\ninterface ShortCircuitable {\n /**\n * startNavigation does not need to complete the navigation because we\n * redirected or got interrupted\n */\n shortCircuited?: boolean;\n}\n\ninterface HandleActionResult extends ShortCircuitable {\n /**\n * Error thrown from the current action, keyed by the route containing the\n * error boundary to render the error. To be committed to the state after\n * loaders have completed\n */\n pendingActionError?: RouteData;\n /**\n * Data returned from the current action, keyed by the route owning the action.\n * To be committed to the state after loaders have completed\n */\n pendingActionData?: RouteData;\n}\n\ninterface HandleLoadersResult extends ShortCircuitable {\n /**\n * loaderData returned from the current set of loaders\n */\n loaderData?: RouterState[\"loaderData\"];\n /**\n * errors thrown from the current set of loaders\n */\n errors?: RouterState[\"errors\"];\n}\n\n/**\n * Cached info for active fetcher.load() instances so they can participate\n * in revalidation\n */\ninterface FetchLoadMatch {\n routeId: string;\n path: string;\n}\n\n/**\n * Identified fetcher.load() calls that need to be revalidated\n */\ninterface RevalidatingFetcher extends FetchLoadMatch {\n key: string;\n match: AgnosticDataRouteMatch | null;\n matches: AgnosticDataRouteMatch[] | null;\n controller: AbortController | null;\n}\n\n/**\n * Wrapper object to allow us to throw any response out from callLoaderOrAction\n * for queryRouter while preserving whether or not it was thrown or returned\n * from the loader/action\n */\ninterface QueryRouteResponse {\n type: ResultType.data | ResultType.error;\n response: Response;\n}\n\nconst validMutationMethodsArr: MutationFormMethod[] = [\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n];\nconst validMutationMethods = new Set(\n validMutationMethodsArr\n);\n\nconst validRequestMethodsArr: FormMethod[] = [\n \"get\",\n ...validMutationMethodsArr,\n];\nconst validRequestMethods = new Set(validRequestMethodsArr);\n\nconst redirectStatusCodes = new Set([301, 302, 303, 307, 308]);\nconst redirectPreserveMethodStatusCodes = new Set([307, 308]);\n\nexport const IDLE_NAVIGATION: NavigationStates[\"Idle\"] = {\n state: \"idle\",\n location: undefined,\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n};\n\nexport const IDLE_FETCHER: FetcherStates[\"Idle\"] = {\n state: \"idle\",\n data: undefined,\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n};\n\nexport const IDLE_BLOCKER: BlockerUnblocked = {\n state: \"unblocked\",\n proceed: undefined,\n reset: undefined,\n location: undefined,\n};\n\nconst ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i;\n\nconst defaultMapRouteProperties: MapRoutePropertiesFunction = (route) => ({\n hasErrorBoundary: Boolean(route.hasErrorBoundary),\n});\n\nconst TRANSITIONS_STORAGE_KEY = \"remix-router-transitions\";\n\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region createRouter\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * Create a router and listen to history POP navigations\n */\nexport function createRouter(init: RouterInit): Router {\n const routerWindow = init.window\n ? init.window\n : typeof window !== \"undefined\"\n ? window\n : undefined;\n const isBrowser =\n typeof routerWindow !== \"undefined\" &&\n typeof routerWindow.document !== \"undefined\" &&\n typeof routerWindow.document.createElement !== \"undefined\";\n const isServer = !isBrowser;\n\n invariant(\n init.routes.length > 0,\n \"You must provide a non-empty routes array to createRouter\"\n );\n\n let mapRouteProperties: MapRoutePropertiesFunction;\n if (init.mapRouteProperties) {\n mapRouteProperties = init.mapRouteProperties;\n } else if (init.detectErrorBoundary) {\n // If they are still using the deprecated version, wrap it with the new API\n let detectErrorBoundary = init.detectErrorBoundary;\n mapRouteProperties = (route) => ({\n hasErrorBoundary: detectErrorBoundary(route),\n });\n } else {\n mapRouteProperties = defaultMapRouteProperties;\n }\n\n // Routes keyed by ID\n let manifest: RouteManifest = {};\n // Routes in tree format for matching\n let dataRoutes = convertRoutesToDataRoutes(\n init.routes,\n mapRouteProperties,\n undefined,\n manifest\n );\n let inFlightDataRoutes: AgnosticDataRouteObject[] | undefined;\n let basename = init.basename || \"/\";\n // Config driven behavior flags\n let future: FutureConfig = {\n v7_fetcherPersist: false,\n v7_normalizeFormMethod: false,\n v7_prependBasename: false,\n ...init.future,\n };\n // Cleanup function for history\n let unlistenHistory: (() => void) | null = null;\n // Externally-provided functions to call on all state changes\n let subscribers = new Set();\n // Externally-provided object to hold scroll restoration locations during routing\n let savedScrollPositions: Record | null = null;\n // Externally-provided function to get scroll restoration keys\n let getScrollRestorationKey: GetScrollRestorationKeyFunction | null = null;\n // Externally-provided function to get current scroll position\n let getScrollPosition: GetScrollPositionFunction | null = null;\n // One-time flag to control the initial hydration scroll restoration. Because\n // we don't get the saved positions from until _after_\n // the initial render, we need to manually trigger a separate updateState to\n // send along the restoreScrollPosition\n // Set to true if we have `hydrationData` since we assume we were SSR'd and that\n // SSR did the initial scroll restoration.\n let initialScrollRestored = init.hydrationData != null;\n\n let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);\n let initialErrors: RouteData | null = null;\n\n if (initialMatches == null) {\n // If we do not match a user-provided-route, fall back to the root\n // to allow the error boundary to take over\n let error = getInternalRouterError(404, {\n pathname: init.history.location.pathname,\n });\n let { matches, route } = getShortCircuitMatches(dataRoutes);\n initialMatches = matches;\n initialErrors = { [route.id]: error };\n }\n\n let initialized =\n // All initialMatches need to be loaded before we're ready. If we have lazy\n // functions around still then we'll need to run them in initialize()\n !initialMatches.some((m) => m.route.lazy) &&\n // And we have to either have no loaders or have been provided hydrationData\n (!initialMatches.some((m) => m.route.loader) || init.hydrationData != null);\n\n let router: Router;\n let state: RouterState = {\n historyAction: init.history.action,\n location: init.history.location,\n matches: initialMatches,\n initialized,\n navigation: IDLE_NAVIGATION,\n // Don't restore on initial updateState() if we were SSR'd\n restoreScrollPosition: init.hydrationData != null ? false : null,\n preventScrollReset: false,\n revalidation: \"idle\",\n loaderData: (init.hydrationData && init.hydrationData.loaderData) || {},\n actionData: (init.hydrationData && init.hydrationData.actionData) || null,\n errors: (init.hydrationData && init.hydrationData.errors) || initialErrors,\n fetchers: new Map(),\n blockers: new Map(),\n };\n\n // -- Stateful internal variables to manage navigations --\n // Current navigation in progress (to be committed in completeNavigation)\n let pendingAction: HistoryAction = HistoryAction.Pop;\n\n // Should the current navigation prevent the scroll reset if scroll cannot\n // be restored?\n let pendingPreventScrollReset = false;\n\n // AbortController for the active navigation\n let pendingNavigationController: AbortController | null;\n\n // Should the current navigation enable document.startViewTransition?\n let pendingViewTransitionEnabled = false;\n\n // Store applied view transitions so we can apply them on POP\n let appliedViewTransitions: Map> = new Map<\n string,\n Set\n >();\n\n // Cleanup function for persisting applied transitions to sessionStorage\n let removePageHideEventListener: (() => void) | null = null;\n\n // We use this to avoid touching history in completeNavigation if a\n // revalidation is entirely uninterrupted\n let isUninterruptedRevalidation = false;\n\n // Use this internal flag to force revalidation of all loaders:\n // - submissions (completed or interrupted)\n // - useRevalidator()\n // - X-Remix-Revalidate (from redirect)\n let isRevalidationRequired = false;\n\n // Use this internal array to capture routes that require revalidation due\n // to a cancelled deferred on action submission\n let cancelledDeferredRoutes: string[] = [];\n\n // Use this internal array to capture fetcher loads that were cancelled by an\n // action navigation and require revalidation\n let cancelledFetcherLoads: string[] = [];\n\n // AbortControllers for any in-flight fetchers\n let fetchControllers = new Map();\n\n // Track loads based on the order in which they started\n let incrementingLoadId = 0;\n\n // Track the outstanding pending navigation data load to be compared against\n // the globally incrementing load when a fetcher load lands after a completed\n // navigation\n let pendingNavigationLoadId = -1;\n\n // Fetchers that triggered data reloads as a result of their actions\n let fetchReloadIds = new Map();\n\n // Fetchers that triggered redirect navigations\n let fetchRedirectIds = new Set();\n\n // Most recent href/match for fetcher.load calls for fetchers\n let fetchLoadMatches = new Map();\n\n // Ref-count mounted fetchers so we know when it's ok to clean them up\n let activeFetchers = new Map();\n\n // Fetchers that have requested a delete when using v7_fetcherPersist,\n // they'll be officially removed after they return to idle\n let deletedFetchers = new Set();\n\n // Store DeferredData instances for active route matches. When a\n // route loader returns defer() we stick one in here. Then, when a nested\n // promise resolves we update loaderData. If a new navigation starts we\n // cancel active deferreds for eliminated routes.\n let activeDeferreds = new Map();\n\n // Store blocker functions in a separate Map outside of router state since\n // we don't need to update UI state if they change\n let blockerFunctions = new Map();\n\n // Flag to ignore the next history update, so we can revert the URL change on\n // a POP navigation that was blocked by the user without touching router state\n let ignoreNextHistoryUpdate = false;\n\n // Initialize the router, all side effects should be kicked off from here.\n // Implemented as a Fluent API for ease of:\n // let router = createRouter(init).initialize();\n function initialize() {\n // If history informs us of a POP navigation, start the navigation but do not update\n // state. We'll update our own state once the navigation completes\n unlistenHistory = init.history.listen(\n ({ action: historyAction, location, delta }) => {\n // Ignore this event if it was just us resetting the URL from a\n // blocked POP navigation\n if (ignoreNextHistoryUpdate) {\n ignoreNextHistoryUpdate = false;\n return;\n }\n\n warning(\n blockerFunctions.size === 0 || delta != null,\n \"You are trying to use a blocker on a POP navigation to a location \" +\n \"that was not created by @remix-run/router. This will fail silently in \" +\n \"production. This can happen if you are navigating outside the router \" +\n \"via `window.history.pushState`/`window.location.hash` instead of using \" +\n \"router navigation APIs. This can also happen if you are using \" +\n \"createHashRouter and the user manually changes the URL.\"\n );\n\n let blockerKey = shouldBlockNavigation({\n currentLocation: state.location,\n nextLocation: location,\n historyAction,\n });\n\n if (blockerKey && delta != null) {\n // Restore the URL to match the current UI, but don't update router state\n ignoreNextHistoryUpdate = true;\n init.history.go(delta * -1);\n\n // Put the blocker into a blocked state\n updateBlocker(blockerKey, {\n state: \"blocked\",\n location,\n proceed() {\n updateBlocker(blockerKey!, {\n state: \"proceeding\",\n proceed: undefined,\n reset: undefined,\n location,\n });\n // Re-do the same POP navigation we just blocked\n init.history.go(delta);\n },\n reset() {\n let blockers = new Map(state.blockers);\n blockers.set(blockerKey!, IDLE_BLOCKER);\n updateState({ blockers });\n },\n });\n return;\n }\n\n return startNavigation(historyAction, location);\n }\n );\n\n if (isBrowser) {\n // FIXME: This feels gross. How can we cleanup the lines between\n // scrollRestoration/appliedTransitions persistance?\n restoreAppliedTransitions(routerWindow, appliedViewTransitions);\n let _saveAppliedTransitions = () =>\n persistAppliedTransitions(routerWindow, appliedViewTransitions);\n routerWindow.addEventListener(\"pagehide\", _saveAppliedTransitions);\n removePageHideEventListener = () =>\n routerWindow.removeEventListener(\"pagehide\", _saveAppliedTransitions);\n }\n\n // Kick off initial data load if needed. Use Pop to avoid modifying history\n // Note we don't do any handling of lazy here. For SPA's it'll get handled\n // in the normal navigation flow. For SSR it's expected that lazy modules are\n // resolved prior to router creation since we can't go into a fallbackElement\n // UI for SSR'd apps\n if (!state.initialized) {\n startNavigation(HistoryAction.Pop, state.location);\n }\n\n return router;\n }\n\n // Clean up a router and it's side effects\n function dispose() {\n if (unlistenHistory) {\n unlistenHistory();\n }\n if (removePageHideEventListener) {\n removePageHideEventListener();\n }\n subscribers.clear();\n pendingNavigationController && pendingNavigationController.abort();\n state.fetchers.forEach((_, key) => deleteFetcher(key));\n state.blockers.forEach((_, key) => deleteBlocker(key));\n }\n\n // Subscribe to state updates for the router\n function subscribe(fn: RouterSubscriber) {\n subscribers.add(fn);\n return () => subscribers.delete(fn);\n }\n\n // Update our state and notify the calling context of the change\n function updateState(\n newState: Partial,\n viewTransitionOpts?: ViewTransitionOpts\n ): void {\n state = {\n ...state,\n ...newState,\n };\n\n // Prep fetcher cleanup so we can tell the UI which fetcher data entries\n // can be removed\n let completedFetchers: string[] = [];\n let deletedFetchersKeys: string[] = [];\n\n if (future.v7_fetcherPersist) {\n state.fetchers.forEach((fetcher, key) => {\n if (fetcher.state === \"idle\") {\n if (deletedFetchers.has(key)) {\n // Unmounted from the UI and can be totally removed\n deletedFetchersKeys.push(key);\n } else {\n // Returned to idle but still mounted in the UI, so semi-remains for\n // revalidations and such\n completedFetchers.push(key);\n }\n }\n });\n }\n\n subscribers.forEach((subscriber) =>\n subscriber(state, {\n deletedFetchers: deletedFetchersKeys,\n unstable_viewTransitionOpts: viewTransitionOpts,\n })\n );\n\n // Remove idle fetchers from state since we only care about in-flight fetchers.\n if (future.v7_fetcherPersist) {\n completedFetchers.forEach((key) => state.fetchers.delete(key));\n deletedFetchersKeys.forEach((key) => deleteFetcher(key));\n }\n }\n\n // Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION\n // and setting state.[historyAction/location/matches] to the new route.\n // - Location is a required param\n // - Navigation will always be set to IDLE_NAVIGATION\n // - Can pass any other state in newState\n function completeNavigation(\n location: Location,\n newState: Partial>\n ): void {\n // Deduce if we're in a loading/actionReload state:\n // - We have committed actionData in the store\n // - The current navigation was a mutation submission\n // - We're past the submitting state and into the loading state\n // - The location being loaded is not the result of a redirect\n let isActionReload =\n state.actionData != null &&\n state.navigation.formMethod != null &&\n isMutationMethod(state.navigation.formMethod) &&\n state.navigation.state === \"loading\" &&\n location.state?._isRedirect !== true;\n\n let actionData: RouteData | null;\n if (newState.actionData) {\n if (Object.keys(newState.actionData).length > 0) {\n actionData = newState.actionData;\n } else {\n // Empty actionData -> clear prior actionData due to an action error\n actionData = null;\n }\n } else if (isActionReload) {\n // Keep the current data if we're wrapping up the action reload\n actionData = state.actionData;\n } else {\n // Clear actionData on any other completed navigations\n actionData = null;\n }\n\n // Always preserve any existing loaderData from re-used routes\n let loaderData = newState.loaderData\n ? mergeLoaderData(\n state.loaderData,\n newState.loaderData,\n newState.matches || [],\n newState.errors\n )\n : state.loaderData;\n\n // On a successful navigation we can assume we got through all blockers\n // so we can start fresh\n let blockers = state.blockers;\n if (blockers.size > 0) {\n blockers = new Map(blockers);\n blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));\n }\n\n // Always respect the user flag. Otherwise don't reset on mutation\n // submission navigations unless they redirect\n let preventScrollReset =\n pendingPreventScrollReset === true ||\n (state.navigation.formMethod != null &&\n isMutationMethod(state.navigation.formMethod) &&\n location.state?._isRedirect !== true);\n\n if (inFlightDataRoutes) {\n dataRoutes = inFlightDataRoutes;\n inFlightDataRoutes = undefined;\n }\n\n if (isUninterruptedRevalidation) {\n // If this was an uninterrupted revalidation then do not touch history\n } else if (pendingAction === HistoryAction.Pop) {\n // Do nothing for POP - URL has already been updated\n } else if (pendingAction === HistoryAction.Push) {\n init.history.push(location, location.state);\n } else if (pendingAction === HistoryAction.Replace) {\n init.history.replace(location, location.state);\n }\n\n let viewTransitionOpts: ViewTransitionOpts | undefined;\n\n // On POP, enable transitions if they were enabled on the original navigation\n if (pendingAction === HistoryAction.Pop) {\n // Forward takes precedence so they behave like the original navigation\n let priorPaths = appliedViewTransitions.get(state.location.pathname);\n if (priorPaths && priorPaths.has(location.pathname)) {\n viewTransitionOpts = {\n currentLocation: state.location,\n nextLocation: location,\n };\n } else if (appliedViewTransitions.has(location.pathname)) {\n // If we don't have a previous forward nav, assume we're popping back to\n // the new location and enable if that location previously enabled\n viewTransitionOpts = {\n currentLocation: location,\n nextLocation: state.location,\n };\n }\n } else if (pendingViewTransitionEnabled) {\n // Store the applied transition on PUSH/REPLACE\n let toPaths = appliedViewTransitions.get(state.location.pathname);\n if (toPaths) {\n toPaths.add(location.pathname);\n } else {\n toPaths = new Set([location.pathname]);\n appliedViewTransitions.set(state.location.pathname, toPaths);\n }\n viewTransitionOpts = {\n currentLocation: state.location,\n nextLocation: location,\n };\n }\n\n updateState(\n {\n ...newState, // matches, errors, fetchers go through as-is\n actionData,\n loaderData,\n historyAction: pendingAction,\n location,\n initialized: true,\n navigation: IDLE_NAVIGATION,\n revalidation: \"idle\",\n restoreScrollPosition: getSavedScrollPosition(\n location,\n newState.matches || state.matches\n ),\n preventScrollReset,\n blockers,\n },\n viewTransitionOpts\n );\n\n // Reset stateful navigation vars\n pendingAction = HistoryAction.Pop;\n pendingPreventScrollReset = false;\n pendingViewTransitionEnabled = false;\n isUninterruptedRevalidation = false;\n isRevalidationRequired = false;\n cancelledDeferredRoutes = [];\n cancelledFetcherLoads = [];\n }\n\n // Trigger a navigation event, which can either be a numerical POP or a PUSH\n // replace with an optional submission\n async function navigate(\n to: number | To | null,\n opts?: RouterNavigateOptions\n ): Promise {\n if (typeof to === \"number\") {\n init.history.go(to);\n return;\n }\n\n let normalizedPath = normalizeTo(\n state.location,\n state.matches,\n basename,\n future.v7_prependBasename,\n to,\n opts?.fromRouteId,\n opts?.relative\n );\n let { path, submission, error } = normalizeNavigateOptions(\n future.v7_normalizeFormMethod,\n false,\n normalizedPath,\n opts\n );\n\n let currentLocation = state.location;\n let nextLocation = createLocation(state.location, path, opts && opts.state);\n\n // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded\n // URL from window.location, so we need to encode it here so the behavior\n // remains the same as POP and non-data-router usages. new URL() does all\n // the same encoding we'd get from a history.pushState/window.location read\n // without having to touch history\n nextLocation = {\n ...nextLocation,\n ...init.history.encodeLocation(nextLocation),\n };\n\n let userReplace = opts && opts.replace != null ? opts.replace : undefined;\n\n let historyAction = HistoryAction.Push;\n\n if (userReplace === true) {\n historyAction = HistoryAction.Replace;\n } else if (userReplace === false) {\n // no-op\n } else if (\n submission != null &&\n isMutationMethod(submission.formMethod) &&\n submission.formAction === state.location.pathname + state.location.search\n ) {\n // By default on submissions to the current location we REPLACE so that\n // users don't have to double-click the back button to get to the prior\n // location. If the user redirects to a different location from the\n // action/loader this will be ignored and the redirect will be a PUSH\n historyAction = HistoryAction.Replace;\n }\n\n let preventScrollReset =\n opts && \"preventScrollReset\" in opts\n ? opts.preventScrollReset === true\n : undefined;\n\n let blockerKey = shouldBlockNavigation({\n currentLocation,\n nextLocation,\n historyAction,\n });\n\n if (blockerKey) {\n // Put the blocker into a blocked state\n updateBlocker(blockerKey, {\n state: \"blocked\",\n location: nextLocation,\n proceed() {\n updateBlocker(blockerKey!, {\n state: \"proceeding\",\n proceed: undefined,\n reset: undefined,\n location: nextLocation,\n });\n // Send the same navigation through\n navigate(to, opts);\n },\n reset() {\n let blockers = new Map(state.blockers);\n blockers.set(blockerKey!, IDLE_BLOCKER);\n updateState({ blockers });\n },\n });\n return;\n }\n\n return await startNavigation(historyAction, nextLocation, {\n submission,\n // Send through the formData serialization error if we have one so we can\n // render at the right error boundary after we match routes\n pendingError: error,\n preventScrollReset,\n replace: opts && opts.replace,\n enableViewTransition: opts && opts.unstable_viewTransition,\n });\n }\n\n // Revalidate all current loaders. If a navigation is in progress or if this\n // is interrupted by a navigation, allow this to \"succeed\" by calling all\n // loaders during the next loader round\n function revalidate() {\n interruptActiveLoads();\n updateState({ revalidation: \"loading\" });\n\n // If we're currently submitting an action, we don't need to start a new\n // navigation, we'll just let the follow up loader execution call all loaders\n if (state.navigation.state === \"submitting\") {\n return;\n }\n\n // If we're currently in an idle state, start a new navigation for the current\n // action/location and mark it as uninterrupted, which will skip the history\n // update in completeNavigation\n if (state.navigation.state === \"idle\") {\n startNavigation(state.historyAction, state.location, {\n startUninterruptedRevalidation: true,\n });\n return;\n }\n\n // Otherwise, if we're currently in a loading state, just start a new\n // navigation to the navigation.location but do not trigger an uninterrupted\n // revalidation so that history correctly updates once the navigation completes\n startNavigation(\n pendingAction || state.historyAction,\n state.navigation.location,\n { overrideNavigation: state.navigation }\n );\n }\n\n // Start a navigation to the given action/location. Can optionally provide a\n // overrideNavigation which will override the normalLoad in the case of a redirect\n // navigation\n async function startNavigation(\n historyAction: HistoryAction,\n location: Location,\n opts?: {\n submission?: Submission;\n fetcherSubmission?: Submission;\n overrideNavigation?: Navigation;\n pendingError?: ErrorResponseImpl;\n startUninterruptedRevalidation?: boolean;\n preventScrollReset?: boolean;\n replace?: boolean;\n enableViewTransition?: boolean;\n }\n ): Promise {\n // Abort any in-progress navigations and start a new one. Unset any ongoing\n // uninterrupted revalidations unless told otherwise, since we want this\n // new navigation to update history normally\n pendingNavigationController && pendingNavigationController.abort();\n pendingNavigationController = null;\n pendingAction = historyAction;\n isUninterruptedRevalidation =\n (opts && opts.startUninterruptedRevalidation) === true;\n\n // Save the current scroll position every time we start a new navigation,\n // and track whether we should reset scroll on completion\n saveScrollPosition(state.location, state.matches);\n pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;\n\n pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;\n\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let loadingNavigation = opts && opts.overrideNavigation;\n let matches = matchRoutes(routesToUse, location, basename);\n\n // Short circuit with a 404 on the root error boundary if we match nothing\n if (!matches) {\n let error = getInternalRouterError(404, { pathname: location.pathname });\n let { matches: notFoundMatches, route } =\n getShortCircuitMatches(routesToUse);\n // Cancel all pending deferred on 404s since we don't keep any routes\n cancelActiveDeferreds();\n completeNavigation(location, {\n matches: notFoundMatches,\n loaderData: {},\n errors: {\n [route.id]: error,\n },\n });\n return;\n }\n\n // Short circuit if it's only a hash change and not a revalidation or\n // mutation submission.\n //\n // Ignore on initial page loads because since the initial load will always\n // be \"same hash\". For example, on /page#hash and submit a \n // which will default to a navigation to /page\n if (\n state.initialized &&\n !isRevalidationRequired &&\n isHashChangeOnly(state.location, location) &&\n !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))\n ) {\n completeNavigation(location, { matches });\n return;\n }\n\n // Create a controller/Request for this navigation\n pendingNavigationController = new AbortController();\n let request = createClientSideRequest(\n init.history,\n location,\n pendingNavigationController.signal,\n opts && opts.submission\n );\n let pendingActionData: RouteData | undefined;\n let pendingError: RouteData | undefined;\n\n if (opts && opts.pendingError) {\n // If we have a pendingError, it means the user attempted a GET submission\n // with binary FormData so assign here and skip to handleLoaders. That\n // way we handle calling loaders above the boundary etc. It's not really\n // different from an actionError in that sense.\n pendingError = {\n [findNearestBoundary(matches).route.id]: opts.pendingError,\n };\n } else if (\n opts &&\n opts.submission &&\n isMutationMethod(opts.submission.formMethod)\n ) {\n // Call action if we received an action submission\n let actionOutput = await handleAction(\n request,\n location,\n opts.submission,\n matches,\n { replace: opts.replace }\n );\n\n if (actionOutput.shortCircuited) {\n return;\n }\n\n pendingActionData = actionOutput.pendingActionData;\n pendingError = actionOutput.pendingActionError;\n loadingNavigation = getLoadingNavigation(location, opts.submission);\n\n // Create a GET request for the loaders\n request = new Request(request.url, { signal: request.signal });\n }\n\n // Call loaders\n let { shortCircuited, loaderData, errors } = await handleLoaders(\n request,\n location,\n matches,\n loadingNavigation,\n opts && opts.submission,\n opts && opts.fetcherSubmission,\n opts && opts.replace,\n pendingActionData,\n pendingError\n );\n\n if (shortCircuited) {\n return;\n }\n\n // Clean up now that the action/loaders have completed. Don't clean up if\n // we short circuited because pendingNavigationController will have already\n // been assigned to a new controller for the next navigation\n pendingNavigationController = null;\n\n completeNavigation(location, {\n matches,\n ...(pendingActionData ? { actionData: pendingActionData } : {}),\n loaderData,\n errors,\n });\n }\n\n // Call the action matched by the leaf route for this navigation and handle\n // redirects/errors\n async function handleAction(\n request: Request,\n location: Location,\n submission: Submission,\n matches: AgnosticDataRouteMatch[],\n opts: { replace?: boolean } = {}\n ): Promise {\n interruptActiveLoads();\n\n // Put us in a submitting state\n let navigation = getSubmittingNavigation(location, submission);\n updateState({ navigation });\n\n // Call our action and get the result\n let result: DataResult;\n let actionMatch = getTargetMatch(matches, location);\n\n if (!actionMatch.route.action && !actionMatch.route.lazy) {\n result = {\n type: ResultType.error,\n error: getInternalRouterError(405, {\n method: request.method,\n pathname: location.pathname,\n routeId: actionMatch.route.id,\n }),\n };\n } else {\n result = await callLoaderOrAction(\n \"action\",\n request,\n actionMatch,\n matches,\n manifest,\n mapRouteProperties,\n basename\n );\n\n if (request.signal.aborted) {\n return { shortCircuited: true };\n }\n }\n\n if (isRedirectResult(result)) {\n let replace: boolean;\n if (opts && opts.replace != null) {\n replace = opts.replace;\n } else {\n // If the user didn't explicity indicate replace behavior, replace if\n // we redirected to the exact same location we're currently at to avoid\n // double back-buttons\n replace =\n result.location === state.location.pathname + state.location.search;\n }\n await startRedirectNavigation(state, result, { submission, replace });\n return { shortCircuited: true };\n }\n\n if (isErrorResult(result)) {\n // Store off the pending error - we use it to determine which loaders\n // to call and will commit it when we complete the navigation\n let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);\n\n // By default, all submissions are REPLACE navigations, but if the\n // action threw an error that'll be rendered in an errorElement, we fall\n // back to PUSH so that the user can use the back button to get back to\n // the pre-submission form location to try again\n if ((opts && opts.replace) !== true) {\n pendingAction = HistoryAction.Push;\n }\n\n return {\n // Send back an empty object we can use to clear out any prior actionData\n pendingActionData: {},\n pendingActionError: { [boundaryMatch.route.id]: result.error },\n };\n }\n\n if (isDeferredResult(result)) {\n throw getInternalRouterError(400, { type: \"defer-action\" });\n }\n\n return {\n pendingActionData: { [actionMatch.route.id]: result.data },\n };\n }\n\n // Call all applicable loaders for the given matches, handling redirects,\n // errors, etc.\n async function handleLoaders(\n request: Request,\n location: Location,\n matches: AgnosticDataRouteMatch[],\n overrideNavigation?: Navigation,\n submission?: Submission,\n fetcherSubmission?: Submission,\n replace?: boolean,\n pendingActionData?: RouteData,\n pendingError?: RouteData\n ): Promise {\n // Figure out the right navigation we want to use for data loading\n let loadingNavigation =\n overrideNavigation || getLoadingNavigation(location, submission);\n\n // If this was a redirect from an action we don't have a \"submission\" but\n // we have it on the loading navigation so use that if available\n let activeSubmission =\n submission ||\n fetcherSubmission ||\n getSubmissionFromNavigation(loadingNavigation);\n\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(\n init.history,\n state,\n matches,\n activeSubmission,\n location,\n isRevalidationRequired,\n cancelledDeferredRoutes,\n cancelledFetcherLoads,\n fetchLoadMatches,\n fetchRedirectIds,\n routesToUse,\n basename,\n pendingActionData,\n pendingError\n );\n\n // Cancel pending deferreds for no-longer-matched routes or routes we're\n // about to reload. Note that if this is an action reload we would have\n // already cancelled all pending deferreds so this would be a no-op\n cancelActiveDeferreds(\n (routeId) =>\n !(matches && matches.some((m) => m.route.id === routeId)) ||\n (matchesToLoad && matchesToLoad.some((m) => m.route.id === routeId))\n );\n\n pendingNavigationLoadId = ++incrementingLoadId;\n\n // Short circuit if we have no loaders to run\n if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {\n let updatedFetchers = markFetchRedirectsDone();\n completeNavigation(location, {\n matches,\n loaderData: {},\n // Commit pending error if we're short circuiting\n errors: pendingError || null,\n ...(pendingActionData ? { actionData: pendingActionData } : {}),\n ...(updatedFetchers ? { fetchers: new Map(state.fetchers) } : {}),\n });\n return { shortCircuited: true };\n }\n\n // If this is an uninterrupted revalidation, we remain in our current idle\n // state. If not, we need to switch to our loading state and load data,\n // preserving any new action data or existing action data (in the case of\n // a revalidation interrupting an actionReload)\n if (!isUninterruptedRevalidation) {\n revalidatingFetchers.forEach((rf) => {\n let fetcher = state.fetchers.get(rf.key);\n let revalidatingFetcher = getLoadingFetcher(\n undefined,\n fetcher ? fetcher.data : undefined\n );\n state.fetchers.set(rf.key, revalidatingFetcher);\n });\n let actionData = pendingActionData || state.actionData;\n updateState({\n navigation: loadingNavigation,\n ...(actionData\n ? Object.keys(actionData).length === 0\n ? { actionData: null }\n : { actionData }\n : {}),\n ...(revalidatingFetchers.length > 0\n ? { fetchers: new Map(state.fetchers) }\n : {}),\n });\n }\n\n revalidatingFetchers.forEach((rf) => {\n if (fetchControllers.has(rf.key)) {\n abortFetcher(rf.key);\n }\n if (rf.controller) {\n // Fetchers use an independent AbortController so that aborting a fetcher\n // (via deleteFetcher) does not abort the triggering navigation that\n // triggered the revalidation\n fetchControllers.set(rf.key, rf.controller);\n }\n });\n\n // Proxy navigation abort through to revalidation fetchers\n let abortPendingFetchRevalidations = () =>\n revalidatingFetchers.forEach((f) => abortFetcher(f.key));\n if (pendingNavigationController) {\n pendingNavigationController.signal.addEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n }\n\n let { results, loaderResults, fetcherResults } =\n await callLoadersAndMaybeResolveData(\n state.matches,\n matches,\n matchesToLoad,\n revalidatingFetchers,\n request\n );\n\n if (request.signal.aborted) {\n return { shortCircuited: true };\n }\n\n // Clean up _after_ loaders have completed. Don't clean up if we short\n // circuited because fetchControllers would have been aborted and\n // reassigned to new controllers for the next navigation\n if (pendingNavigationController) {\n pendingNavigationController.signal.removeEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n }\n revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));\n\n // If any loaders returned a redirect Response, start a new REPLACE navigation\n let redirect = findRedirect(results);\n if (redirect) {\n if (redirect.idx >= matchesToLoad.length) {\n // If this redirect came from a fetcher make sure we mark it in\n // fetchRedirectIds so it doesn't get revalidated on the next set of\n // loader executions\n let fetcherKey =\n revalidatingFetchers[redirect.idx - matchesToLoad.length].key;\n fetchRedirectIds.add(fetcherKey);\n }\n await startRedirectNavigation(state, redirect.result, { replace });\n return { shortCircuited: true };\n }\n\n // Process and commit output from loaders\n let { loaderData, errors } = processLoaderData(\n state,\n matches,\n matchesToLoad,\n loaderResults,\n pendingError,\n revalidatingFetchers,\n fetcherResults,\n activeDeferreds\n );\n\n // Wire up subscribers to update loaderData as promises settle\n activeDeferreds.forEach((deferredData, routeId) => {\n deferredData.subscribe((aborted) => {\n // Note: No need to updateState here since the TrackedPromise on\n // loaderData is stable across resolve/reject\n // Remove this instance if we were aborted or if promises have settled\n if (aborted || deferredData.done) {\n activeDeferreds.delete(routeId);\n }\n });\n });\n\n let updatedFetchers = markFetchRedirectsDone();\n let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);\n let shouldUpdateFetchers =\n updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;\n\n return {\n loaderData,\n errors,\n ...(shouldUpdateFetchers ? { fetchers: new Map(state.fetchers) } : {}),\n };\n }\n\n function getFetcher(key: string): Fetcher {\n if (future.v7_fetcherPersist) {\n activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);\n // If this fetcher was previously marked for deletion, unmark it since we\n // have a new instance\n if (deletedFetchers.has(key)) {\n deletedFetchers.delete(key);\n }\n }\n return state.fetchers.get(key) || IDLE_FETCHER;\n }\n\n // Trigger a fetcher load/submit for the given fetcher key\n function fetch(\n key: string,\n routeId: string,\n href: string | null,\n opts?: RouterFetchOptions\n ) {\n if (isServer) {\n throw new Error(\n \"router.fetch() was called during the server render, but it shouldn't be. \" +\n \"You are likely calling a useFetcher() method in the body of your component. \" +\n \"Try moving it to a useEffect or a callback.\"\n );\n }\n\n if (fetchControllers.has(key)) abortFetcher(key);\n\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let normalizedPath = normalizeTo(\n state.location,\n state.matches,\n basename,\n future.v7_prependBasename,\n href,\n routeId,\n opts?.relative\n );\n let matches = matchRoutes(routesToUse, normalizedPath, basename);\n\n if (!matches) {\n setFetcherError(\n key,\n routeId,\n getInternalRouterError(404, { pathname: normalizedPath })\n );\n return;\n }\n\n let { path, submission, error } = normalizeNavigateOptions(\n future.v7_normalizeFormMethod,\n true,\n normalizedPath,\n opts\n );\n\n if (error) {\n setFetcherError(key, routeId, error);\n return;\n }\n\n let match = getTargetMatch(matches, path);\n\n pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;\n\n if (submission && isMutationMethod(submission.formMethod)) {\n handleFetcherAction(key, routeId, path, match, matches, submission);\n return;\n }\n\n // Store off the match so we can call it's shouldRevalidate on subsequent\n // revalidations\n fetchLoadMatches.set(key, { routeId, path });\n handleFetcherLoader(key, routeId, path, match, matches, submission);\n }\n\n // Call the action for the matched fetcher.submit(), and then handle redirects,\n // errors, and revalidation\n async function handleFetcherAction(\n key: string,\n routeId: string,\n path: string,\n match: AgnosticDataRouteMatch,\n requestMatches: AgnosticDataRouteMatch[],\n submission: Submission\n ) {\n interruptActiveLoads();\n fetchLoadMatches.delete(key);\n\n if (!match.route.action && !match.route.lazy) {\n let error = getInternalRouterError(405, {\n method: submission.formMethod,\n pathname: path,\n routeId: routeId,\n });\n setFetcherError(key, routeId, error);\n return;\n }\n\n // Put this fetcher into it's submitting state\n let existingFetcher = state.fetchers.get(key);\n let fetcher = getSubmittingFetcher(submission, existingFetcher);\n state.fetchers.set(key, fetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n\n // Call the action for the fetcher\n let abortController = new AbortController();\n let fetchRequest = createClientSideRequest(\n init.history,\n path,\n abortController.signal,\n submission\n );\n fetchControllers.set(key, abortController);\n\n let originatingLoadId = incrementingLoadId;\n let actionResult = await callLoaderOrAction(\n \"action\",\n fetchRequest,\n match,\n requestMatches,\n manifest,\n mapRouteProperties,\n basename\n );\n\n if (fetchRequest.signal.aborted) {\n // We can delete this so long as we weren't aborted by our own fetcher\n // re-submit which would have put _new_ controller is in fetchControllers\n if (fetchControllers.get(key) === abortController) {\n fetchControllers.delete(key);\n }\n return;\n }\n\n if (deletedFetchers.has(key)) {\n state.fetchers.set(key, getDoneFetcher(undefined));\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n }\n\n if (isRedirectResult(actionResult)) {\n fetchControllers.delete(key);\n if (pendingNavigationLoadId > originatingLoadId) {\n // A new navigation was kicked off after our action started, so that\n // should take precedence over this redirect navigation. We already\n // set isRevalidationRequired so all loaders for the new route should\n // fire unless opted out via shouldRevalidate\n let doneFetcher = getDoneFetcher(undefined);\n state.fetchers.set(key, doneFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n } else {\n fetchRedirectIds.add(key);\n let loadingFetcher = getLoadingFetcher(submission);\n state.fetchers.set(key, loadingFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n\n return startRedirectNavigation(state, actionResult, {\n fetcherSubmission: submission,\n });\n }\n }\n\n // Process any non-redirect errors thrown\n if (isErrorResult(actionResult)) {\n setFetcherError(key, routeId, actionResult.error);\n return;\n }\n\n if (isDeferredResult(actionResult)) {\n throw getInternalRouterError(400, { type: \"defer-action\" });\n }\n\n // Start the data load for current matches, or the next location if we're\n // in the middle of a navigation\n let nextLocation = state.navigation.location || state.location;\n let revalidationRequest = createClientSideRequest(\n init.history,\n nextLocation,\n abortController.signal\n );\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let matches =\n state.navigation.state !== \"idle\"\n ? matchRoutes(routesToUse, state.navigation.location, basename)\n : state.matches;\n\n invariant(matches, \"Didn't find any matches after fetcher action\");\n\n let loadId = ++incrementingLoadId;\n fetchReloadIds.set(key, loadId);\n\n let loadFetcher = getLoadingFetcher(submission, actionResult.data);\n state.fetchers.set(key, loadFetcher);\n\n let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(\n init.history,\n state,\n matches,\n submission,\n nextLocation,\n isRevalidationRequired,\n cancelledDeferredRoutes,\n cancelledFetcherLoads,\n fetchLoadMatches,\n fetchRedirectIds,\n routesToUse,\n basename,\n { [match.route.id]: actionResult.data },\n undefined // No need to send through errors since we short circuit above\n );\n\n // Put all revalidating fetchers into the loading state, except for the\n // current fetcher which we want to keep in it's current loading state which\n // contains it's action submission info + action data\n revalidatingFetchers\n .filter((rf) => rf.key !== key)\n .forEach((rf) => {\n let staleKey = rf.key;\n let existingFetcher = state.fetchers.get(staleKey);\n let revalidatingFetcher = getLoadingFetcher(\n undefined,\n existingFetcher ? existingFetcher.data : undefined\n );\n state.fetchers.set(staleKey, revalidatingFetcher);\n if (fetchControllers.has(staleKey)) {\n abortFetcher(staleKey);\n }\n if (rf.controller) {\n fetchControllers.set(staleKey, rf.controller);\n }\n });\n\n updateState({ fetchers: new Map(state.fetchers) });\n\n let abortPendingFetchRevalidations = () =>\n revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));\n\n abortController.signal.addEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n\n let { results, loaderResults, fetcherResults } =\n await callLoadersAndMaybeResolveData(\n state.matches,\n matches,\n matchesToLoad,\n revalidatingFetchers,\n revalidationRequest\n );\n\n if (abortController.signal.aborted) {\n return;\n }\n\n abortController.signal.removeEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n\n fetchReloadIds.delete(key);\n fetchControllers.delete(key);\n revalidatingFetchers.forEach((r) => fetchControllers.delete(r.key));\n\n let redirect = findRedirect(results);\n if (redirect) {\n if (redirect.idx >= matchesToLoad.length) {\n // If this redirect came from a fetcher make sure we mark it in\n // fetchRedirectIds so it doesn't get revalidated on the next set of\n // loader executions\n let fetcherKey =\n revalidatingFetchers[redirect.idx - matchesToLoad.length].key;\n fetchRedirectIds.add(fetcherKey);\n }\n return startRedirectNavigation(state, redirect.result);\n }\n\n // Process and commit output from loaders\n let { loaderData, errors } = processLoaderData(\n state,\n state.matches,\n matchesToLoad,\n loaderResults,\n undefined,\n revalidatingFetchers,\n fetcherResults,\n activeDeferreds\n );\n\n // Since we let revalidations complete even if the submitting fetcher was\n // deleted, only put it back to idle if it hasn't been deleted\n if (state.fetchers.has(key)) {\n let doneFetcher = getDoneFetcher(actionResult.data);\n state.fetchers.set(key, doneFetcher);\n }\n\n abortStaleFetchLoads(loadId);\n\n // If we are currently in a navigation loading state and this fetcher is\n // more recent than the navigation, we want the newer data so abort the\n // navigation and complete it with the fetcher data\n if (\n state.navigation.state === \"loading\" &&\n loadId > pendingNavigationLoadId\n ) {\n invariant(pendingAction, \"Expected pending action\");\n pendingNavigationController && pendingNavigationController.abort();\n\n completeNavigation(state.navigation.location, {\n matches,\n loaderData,\n errors,\n fetchers: new Map(state.fetchers),\n });\n } else {\n // otherwise just update with the fetcher data, preserving any existing\n // loaderData for loaders that did not need to reload. We have to\n // manually merge here since we aren't going through completeNavigation\n updateState({\n errors,\n loaderData: mergeLoaderData(\n state.loaderData,\n loaderData,\n matches,\n errors\n ),\n fetchers: new Map(state.fetchers),\n });\n isRevalidationRequired = false;\n }\n }\n\n // Call the matched loader for fetcher.load(), handling redirects, errors, etc.\n async function handleFetcherLoader(\n key: string,\n routeId: string,\n path: string,\n match: AgnosticDataRouteMatch,\n matches: AgnosticDataRouteMatch[],\n submission?: Submission\n ) {\n let existingFetcher = state.fetchers.get(key);\n // Put this fetcher into it's loading state\n let loadingFetcher = getLoadingFetcher(\n submission,\n existingFetcher ? existingFetcher.data : undefined\n );\n state.fetchers.set(key, loadingFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n\n // Call the loader for this fetcher route match\n let abortController = new AbortController();\n let fetchRequest = createClientSideRequest(\n init.history,\n path,\n abortController.signal\n );\n fetchControllers.set(key, abortController);\n\n let originatingLoadId = incrementingLoadId;\n let result: DataResult = await callLoaderOrAction(\n \"loader\",\n fetchRequest,\n match,\n matches,\n manifest,\n mapRouteProperties,\n basename\n );\n\n // Deferred isn't supported for fetcher loads, await everything and treat it\n // as a normal load. resolveDeferredData will return undefined if this\n // fetcher gets aborted, so we just leave result untouched and short circuit\n // below if that happens\n if (isDeferredResult(result)) {\n result =\n (await resolveDeferredData(result, fetchRequest.signal, true)) ||\n result;\n }\n\n // We can delete this so long as we weren't aborted by our our own fetcher\n // re-load which would have put _new_ controller is in fetchControllers\n if (fetchControllers.get(key) === abortController) {\n fetchControllers.delete(key);\n }\n\n if (fetchRequest.signal.aborted) {\n return;\n }\n\n if (deletedFetchers.has(key)) {\n state.fetchers.set(key, getDoneFetcher(undefined));\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n }\n\n // If the loader threw a redirect Response, start a new REPLACE navigation\n if (isRedirectResult(result)) {\n if (pendingNavigationLoadId > originatingLoadId) {\n // A new navigation was kicked off after our loader started, so that\n // should take precedence over this redirect navigation\n let doneFetcher = getDoneFetcher(undefined);\n state.fetchers.set(key, doneFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n } else {\n fetchRedirectIds.add(key);\n await startRedirectNavigation(state, result);\n return;\n }\n }\n\n // Process any non-redirect errors thrown\n if (isErrorResult(result)) {\n setFetcherError(key, routeId, result.error);\n return;\n }\n\n invariant(!isDeferredResult(result), \"Unhandled fetcher deferred data\");\n\n // Put the fetcher back into an idle state\n let doneFetcher = getDoneFetcher(result.data);\n state.fetchers.set(key, doneFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n }\n\n /**\n * Utility function to handle redirects returned from an action or loader.\n * Normally, a redirect \"replaces\" the navigation that triggered it. So, for\n * example:\n *\n * - user is on /a\n * - user clicks a link to /b\n * - loader for /b redirects to /c\n *\n * In a non-JS app the browser would track the in-flight navigation to /b and\n * then replace it with /c when it encountered the redirect response. In\n * the end it would only ever update the URL bar with /c.\n *\n * In client-side routing using pushState/replaceState, we aim to emulate\n * this behavior and we also do not update history until the end of the\n * navigation (including processed redirects). This means that we never\n * actually touch history until we've processed redirects, so we just use\n * the history action from the original navigation (PUSH or REPLACE).\n */\n async function startRedirectNavigation(\n state: RouterState,\n redirect: RedirectResult,\n {\n submission,\n fetcherSubmission,\n replace,\n }: {\n submission?: Submission;\n fetcherSubmission?: Submission;\n replace?: boolean;\n } = {}\n ) {\n if (redirect.revalidate) {\n isRevalidationRequired = true;\n }\n\n let redirectLocation = createLocation(state.location, redirect.location, {\n _isRedirect: true,\n });\n invariant(\n redirectLocation,\n \"Expected a location on the redirect navigation\"\n );\n\n if (isBrowser) {\n let isDocumentReload = false;\n\n if (redirect.reloadDocument) {\n // Hard reload if the response contained X-Remix-Reload-Document\n isDocumentReload = true;\n } else if (ABSOLUTE_URL_REGEX.test(redirect.location)) {\n const url = init.history.createURL(redirect.location);\n isDocumentReload =\n // Hard reload if it's an absolute URL to a new origin\n url.origin !== routerWindow.location.origin ||\n // Hard reload if it's an absolute URL that does not match our basename\n stripBasename(url.pathname, basename) == null;\n }\n\n if (isDocumentReload) {\n if (replace) {\n routerWindow.location.replace(redirect.location);\n } else {\n routerWindow.location.assign(redirect.location);\n }\n return;\n }\n }\n\n // There's no need to abort on redirects, since we don't detect the\n // redirect until the action/loaders have settled\n pendingNavigationController = null;\n\n let redirectHistoryAction =\n replace === true ? HistoryAction.Replace : HistoryAction.Push;\n\n // Use the incoming submission if provided, fallback on the active one in\n // state.navigation\n let { formMethod, formAction, formEncType } = state.navigation;\n if (\n !submission &&\n !fetcherSubmission &&\n formMethod &&\n formAction &&\n formEncType\n ) {\n submission = getSubmissionFromNavigation(state.navigation);\n }\n\n // If this was a 307/308 submission we want to preserve the HTTP method and\n // re-submit the GET/POST/PUT/PATCH/DELETE as a submission navigation to the\n // redirected location\n let activeSubmission = submission || fetcherSubmission;\n if (\n redirectPreserveMethodStatusCodes.has(redirect.status) &&\n activeSubmission &&\n isMutationMethod(activeSubmission.formMethod)\n ) {\n await startNavigation(redirectHistoryAction, redirectLocation, {\n submission: {\n ...activeSubmission,\n formAction: redirect.location,\n },\n // Preserve this flag across redirects\n preventScrollReset: pendingPreventScrollReset,\n });\n } else {\n // If we have a navigation submission, we will preserve it through the\n // redirect navigation\n let overrideNavigation = getLoadingNavigation(\n redirectLocation,\n submission\n );\n await startNavigation(redirectHistoryAction, redirectLocation, {\n overrideNavigation,\n // Send fetcher submissions through for shouldRevalidate\n fetcherSubmission,\n // Preserve this flag across redirects\n preventScrollReset: pendingPreventScrollReset,\n });\n }\n }\n\n async function callLoadersAndMaybeResolveData(\n currentMatches: AgnosticDataRouteMatch[],\n matches: AgnosticDataRouteMatch[],\n matchesToLoad: AgnosticDataRouteMatch[],\n fetchersToLoad: RevalidatingFetcher[],\n request: Request\n ) {\n // Call all navigation loaders and revalidating fetcher loaders in parallel,\n // then slice off the results into separate arrays so we can handle them\n // accordingly\n let results = await Promise.all([\n ...matchesToLoad.map((match) =>\n callLoaderOrAction(\n \"loader\",\n request,\n match,\n matches,\n manifest,\n mapRouteProperties,\n basename\n )\n ),\n ...fetchersToLoad.map((f) => {\n if (f.matches && f.match && f.controller) {\n return callLoaderOrAction(\n \"loader\",\n createClientSideRequest(init.history, f.path, f.controller.signal),\n f.match,\n f.matches,\n manifest,\n mapRouteProperties,\n basename\n );\n } else {\n let error: ErrorResult = {\n type: ResultType.error,\n error: getInternalRouterError(404, { pathname: f.path }),\n };\n return error;\n }\n }),\n ]);\n let loaderResults = results.slice(0, matchesToLoad.length);\n let fetcherResults = results.slice(matchesToLoad.length);\n\n await Promise.all([\n resolveDeferredResults(\n currentMatches,\n matchesToLoad,\n loaderResults,\n loaderResults.map(() => request.signal),\n false,\n state.loaderData\n ),\n resolveDeferredResults(\n currentMatches,\n fetchersToLoad.map((f) => f.match),\n fetcherResults,\n fetchersToLoad.map((f) => (f.controller ? f.controller.signal : null)),\n true\n ),\n ]);\n\n return { results, loaderResults, fetcherResults };\n }\n\n function interruptActiveLoads() {\n // Every interruption triggers a revalidation\n isRevalidationRequired = true;\n\n // Cancel pending route-level deferreds and mark cancelled routes for\n // revalidation\n cancelledDeferredRoutes.push(...cancelActiveDeferreds());\n\n // Abort in-flight fetcher loads\n fetchLoadMatches.forEach((_, key) => {\n if (fetchControllers.has(key)) {\n cancelledFetcherLoads.push(key);\n abortFetcher(key);\n }\n });\n }\n\n function setFetcherError(key: string, routeId: string, error: any) {\n let boundaryMatch = findNearestBoundary(state.matches, routeId);\n deleteFetcher(key);\n updateState({\n errors: {\n [boundaryMatch.route.id]: error,\n },\n fetchers: new Map(state.fetchers),\n });\n }\n\n function deleteFetcher(key: string): void {\n let fetcher = state.fetchers.get(key);\n // Don't abort the controller if this is a deletion of a fetcher.submit()\n // in it's loading phase since - we don't want to abort the corresponding\n // revalidation and want them to complete and land\n if (\n fetchControllers.has(key) &&\n !(fetcher && fetcher.state === \"loading\" && fetchReloadIds.has(key))\n ) {\n abortFetcher(key);\n }\n fetchLoadMatches.delete(key);\n fetchReloadIds.delete(key);\n fetchRedirectIds.delete(key);\n deletedFetchers.delete(key);\n state.fetchers.delete(key);\n }\n\n function deleteFetcherAndUpdateState(key: string): void {\n if (future.v7_fetcherPersist) {\n let count = (activeFetchers.get(key) || 0) - 1;\n if (count <= 0) {\n activeFetchers.delete(key);\n deletedFetchers.add(key);\n } else {\n activeFetchers.set(key, count);\n }\n } else {\n deleteFetcher(key);\n }\n updateState({ fetchers: new Map(state.fetchers) });\n }\n\n function abortFetcher(key: string) {\n let controller = fetchControllers.get(key);\n invariant(controller, `Expected fetch controller: ${key}`);\n controller.abort();\n fetchControllers.delete(key);\n }\n\n function markFetchersDone(keys: string[]) {\n for (let key of keys) {\n let fetcher = getFetcher(key);\n let doneFetcher = getDoneFetcher(fetcher.data);\n state.fetchers.set(key, doneFetcher);\n }\n }\n\n function markFetchRedirectsDone(): boolean {\n let doneKeys = [];\n let updatedFetchers = false;\n for (let key of fetchRedirectIds) {\n let fetcher = state.fetchers.get(key);\n invariant(fetcher, `Expected fetcher: ${key}`);\n if (fetcher.state === \"loading\") {\n fetchRedirectIds.delete(key);\n doneKeys.push(key);\n updatedFetchers = true;\n }\n }\n markFetchersDone(doneKeys);\n return updatedFetchers;\n }\n\n function abortStaleFetchLoads(landedId: number): boolean {\n let yeetedKeys = [];\n for (let [key, id] of fetchReloadIds) {\n if (id < landedId) {\n let fetcher = state.fetchers.get(key);\n invariant(fetcher, `Expected fetcher: ${key}`);\n if (fetcher.state === \"loading\") {\n abortFetcher(key);\n fetchReloadIds.delete(key);\n yeetedKeys.push(key);\n }\n }\n }\n markFetchersDone(yeetedKeys);\n return yeetedKeys.length > 0;\n }\n\n function getBlocker(key: string, fn: BlockerFunction) {\n let blocker: Blocker = state.blockers.get(key) || IDLE_BLOCKER;\n\n if (blockerFunctions.get(key) !== fn) {\n blockerFunctions.set(key, fn);\n }\n\n return blocker;\n }\n\n function deleteBlocker(key: string) {\n state.blockers.delete(key);\n blockerFunctions.delete(key);\n }\n\n // Utility function to update blockers, ensuring valid state transitions\n function updateBlocker(key: string, newBlocker: Blocker) {\n let blocker = state.blockers.get(key) || IDLE_BLOCKER;\n\n // Poor mans state machine :)\n // https://mermaid.live/edit#pako:eNqVkc9OwzAMxl8l8nnjAYrEtDIOHEBIgwvKJTReGy3_lDpIqO27k6awMG0XcrLlnz87nwdonESogKXXBuE79rq75XZO3-yHds0RJVuv70YrPlUrCEe2HfrORS3rubqZfuhtpg5C9wk5tZ4VKcRUq88q9Z8RS0-48cE1iHJkL0ugbHuFLus9L6spZy8nX9MP2CNdomVaposqu3fGayT8T8-jJQwhepo_UtpgBQaDEUom04dZhAN1aJBDlUKJBxE1ceB2Smj0Mln-IBW5AFU2dwUiktt_2Qaq2dBfaKdEup85UV7Yd-dKjlnkabl2Pvr0DTkTreM\n invariant(\n (blocker.state === \"unblocked\" && newBlocker.state === \"blocked\") ||\n (blocker.state === \"blocked\" && newBlocker.state === \"blocked\") ||\n (blocker.state === \"blocked\" && newBlocker.state === \"proceeding\") ||\n (blocker.state === \"blocked\" && newBlocker.state === \"unblocked\") ||\n (blocker.state === \"proceeding\" && newBlocker.state === \"unblocked\"),\n `Invalid blocker state transition: ${blocker.state} -> ${newBlocker.state}`\n );\n\n let blockers = new Map(state.blockers);\n blockers.set(key, newBlocker);\n updateState({ blockers });\n }\n\n function shouldBlockNavigation({\n currentLocation,\n nextLocation,\n historyAction,\n }: {\n currentLocation: Location;\n nextLocation: Location;\n historyAction: HistoryAction;\n }): string | undefined {\n if (blockerFunctions.size === 0) {\n return;\n }\n\n // We ony support a single active blocker at the moment since we don't have\n // any compelling use cases for multi-blocker yet\n if (blockerFunctions.size > 1) {\n warning(false, \"A router only supports one blocker at a time\");\n }\n\n let entries = Array.from(blockerFunctions.entries());\n let [blockerKey, blockerFunction] = entries[entries.length - 1];\n let blocker = state.blockers.get(blockerKey);\n\n if (blocker && blocker.state === \"proceeding\") {\n // If the blocker is currently proceeding, we don't need to re-check\n // it and can let this navigation continue\n return;\n }\n\n // At this point, we know we're unblocked/blocked so we need to check the\n // user-provided blocker function\n if (blockerFunction({ currentLocation, nextLocation, historyAction })) {\n return blockerKey;\n }\n }\n\n function cancelActiveDeferreds(\n predicate?: (routeId: string) => boolean\n ): string[] {\n let cancelledRouteIds: string[] = [];\n activeDeferreds.forEach((dfd, routeId) => {\n if (!predicate || predicate(routeId)) {\n // Cancel the deferred - but do not remove from activeDeferreds here -\n // we rely on the subscribers to do that so our tests can assert proper\n // cleanup via _internalActiveDeferreds\n dfd.cancel();\n cancelledRouteIds.push(routeId);\n activeDeferreds.delete(routeId);\n }\n });\n return cancelledRouteIds;\n }\n\n // Opt in to capturing and reporting scroll positions during navigations,\n // used by the component\n function enableScrollRestoration(\n positions: Record,\n getPosition: GetScrollPositionFunction,\n getKey?: GetScrollRestorationKeyFunction\n ) {\n savedScrollPositions = positions;\n getScrollPosition = getPosition;\n getScrollRestorationKey = getKey || null;\n\n // Perform initial hydration scroll restoration, since we miss the boat on\n // the initial updateState() because we've not yet rendered \n // and therefore have no savedScrollPositions available\n if (!initialScrollRestored && state.navigation === IDLE_NAVIGATION) {\n initialScrollRestored = true;\n let y = getSavedScrollPosition(state.location, state.matches);\n if (y != null) {\n updateState({ restoreScrollPosition: y });\n }\n }\n\n return () => {\n savedScrollPositions = null;\n getScrollPosition = null;\n getScrollRestorationKey = null;\n };\n }\n\n function getScrollKey(location: Location, matches: AgnosticDataRouteMatch[]) {\n if (getScrollRestorationKey) {\n let key = getScrollRestorationKey(\n location,\n matches.map((m) => convertRouteMatchToUiMatch(m, state.loaderData))\n );\n return key || location.key;\n }\n return location.key;\n }\n\n function saveScrollPosition(\n location: Location,\n matches: AgnosticDataRouteMatch[]\n ): void {\n if (savedScrollPositions && getScrollPosition) {\n let key = getScrollKey(location, matches);\n savedScrollPositions[key] = getScrollPosition();\n }\n }\n\n function getSavedScrollPosition(\n location: Location,\n matches: AgnosticDataRouteMatch[]\n ): number | null {\n if (savedScrollPositions) {\n let key = getScrollKey(location, matches);\n let y = savedScrollPositions[key];\n if (typeof y === \"number\") {\n return y;\n }\n }\n return null;\n }\n\n function _internalSetRoutes(newRoutes: AgnosticDataRouteObject[]) {\n manifest = {};\n inFlightDataRoutes = convertRoutesToDataRoutes(\n newRoutes,\n mapRouteProperties,\n undefined,\n manifest\n );\n }\n\n router = {\n get basename() {\n return basename;\n },\n get state() {\n return state;\n },\n get routes() {\n return dataRoutes;\n },\n get window() {\n return routerWindow;\n },\n initialize,\n subscribe,\n enableScrollRestoration,\n navigate,\n fetch,\n revalidate,\n // Passthrough to history-aware createHref used by useHref so we get proper\n // hash-aware URLs in DOM paths\n createHref: (to: To) => init.history.createHref(to),\n encodeLocation: (to: To) => init.history.encodeLocation(to),\n getFetcher,\n deleteFetcher: deleteFetcherAndUpdateState,\n dispose,\n getBlocker,\n deleteBlocker,\n _internalFetchControllers: fetchControllers,\n _internalActiveDeferreds: activeDeferreds,\n // TODO: Remove setRoutes, it's temporary to avoid dealing with\n // updating the tree while validating the update algorithm.\n _internalSetRoutes,\n };\n\n return router;\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region createStaticHandler\n////////////////////////////////////////////////////////////////////////////////\n\nexport const UNSAFE_DEFERRED_SYMBOL = Symbol(\"deferred\");\n\nexport interface CreateStaticHandlerOptions {\n basename?: string;\n /**\n * @deprecated Use `mapRouteProperties` instead\n */\n detectErrorBoundary?: DetectErrorBoundaryFunction;\n mapRouteProperties?: MapRoutePropertiesFunction;\n}\n\nexport function createStaticHandler(\n routes: AgnosticRouteObject[],\n opts?: CreateStaticHandlerOptions\n): StaticHandler {\n invariant(\n routes.length > 0,\n \"You must provide a non-empty routes array to createStaticHandler\"\n );\n\n let manifest: RouteManifest = {};\n let basename = (opts ? opts.basename : null) || \"/\";\n let mapRouteProperties: MapRoutePropertiesFunction;\n if (opts?.mapRouteProperties) {\n mapRouteProperties = opts.mapRouteProperties;\n } else if (opts?.detectErrorBoundary) {\n // If they are still using the deprecated version, wrap it with the new API\n let detectErrorBoundary = opts.detectErrorBoundary;\n mapRouteProperties = (route) => ({\n hasErrorBoundary: detectErrorBoundary(route),\n });\n } else {\n mapRouteProperties = defaultMapRouteProperties;\n }\n\n let dataRoutes = convertRoutesToDataRoutes(\n routes,\n mapRouteProperties,\n undefined,\n manifest\n );\n\n /**\n * The query() method is intended for document requests, in which we want to\n * call an optional action and potentially multiple loaders for all nested\n * routes. It returns a StaticHandlerContext object, which is very similar\n * to the router state (location, loaderData, actionData, errors, etc.) and\n * also adds SSR-specific information such as the statusCode and headers\n * from action/loaders Responses.\n *\n * It _should_ never throw and should report all errors through the\n * returned context.errors object, properly associating errors to their error\n * boundary. Additionally, it tracks _deepestRenderedBoundaryId which can be\n * used to emulate React error boundaries during SSr by performing a second\n * pass only down to the boundaryId.\n *\n * The one exception where we do not return a StaticHandlerContext is when a\n * redirect response is returned or thrown from any action/loader. We\n * propagate that out and return the raw Response so the HTTP server can\n * return it directly.\n */\n async function query(\n request: Request,\n { requestContext }: { requestContext?: unknown } = {}\n ): Promise {\n let url = new URL(request.url);\n let method = request.method;\n let location = createLocation(\"\", createPath(url), null, \"default\");\n let matches = matchRoutes(dataRoutes, location, basename);\n\n // SSR supports HEAD requests while SPA doesn't\n if (!isValidMethod(method) && method !== \"HEAD\") {\n let error = getInternalRouterError(405, { method });\n let { matches: methodNotAllowedMatches, route } =\n getShortCircuitMatches(dataRoutes);\n return {\n basename,\n location,\n matches: methodNotAllowedMatches,\n loaderData: {},\n actionData: null,\n errors: {\n [route.id]: error,\n },\n statusCode: error.status,\n loaderHeaders: {},\n actionHeaders: {},\n activeDeferreds: null,\n };\n } else if (!matches) {\n let error = getInternalRouterError(404, { pathname: location.pathname });\n let { matches: notFoundMatches, route } =\n getShortCircuitMatches(dataRoutes);\n return {\n basename,\n location,\n matches: notFoundMatches,\n loaderData: {},\n actionData: null,\n errors: {\n [route.id]: error,\n },\n statusCode: error.status,\n loaderHeaders: {},\n actionHeaders: {},\n activeDeferreds: null,\n };\n }\n\n let result = await queryImpl(request, location, matches, requestContext);\n if (isResponse(result)) {\n return result;\n }\n\n // When returning StaticHandlerContext, we patch back in the location here\n // since we need it for React Context. But this helps keep our submit and\n // loadRouteData operating on a Request instead of a Location\n return { location, basename, ...result };\n }\n\n /**\n * The queryRoute() method is intended for targeted route requests, either\n * for fetch ?_data requests or resource route requests. In this case, we\n * are only ever calling a single action or loader, and we are returning the\n * returned value directly. In most cases, this will be a Response returned\n * from the action/loader, but it may be a primitive or other value as well -\n * and in such cases the calling context should handle that accordingly.\n *\n * We do respect the throw/return differentiation, so if an action/loader\n * throws, then this method will throw the value. This is important so we\n * can do proper boundary identification in Remix where a thrown Response\n * must go to the Catch Boundary but a returned Response is happy-path.\n *\n * One thing to note is that any Router-initiated Errors that make sense\n * to associate with a status code will be thrown as an ErrorResponse\n * instance which include the raw Error, such that the calling context can\n * serialize the error as they see fit while including the proper response\n * code. Examples here are 404 and 405 errors that occur prior to reaching\n * any user-defined loaders.\n */\n async function queryRoute(\n request: Request,\n {\n routeId,\n requestContext,\n }: { requestContext?: unknown; routeId?: string } = {}\n ): Promise {\n let url = new URL(request.url);\n let method = request.method;\n let location = createLocation(\"\", createPath(url), null, \"default\");\n let matches = matchRoutes(dataRoutes, location, basename);\n\n // SSR supports HEAD requests while SPA doesn't\n if (!isValidMethod(method) && method !== \"HEAD\" && method !== \"OPTIONS\") {\n throw getInternalRouterError(405, { method });\n } else if (!matches) {\n throw getInternalRouterError(404, { pathname: location.pathname });\n }\n\n let match = routeId\n ? matches.find((m) => m.route.id === routeId)\n : getTargetMatch(matches, location);\n\n if (routeId && !match) {\n throw getInternalRouterError(403, {\n pathname: location.pathname,\n routeId,\n });\n } else if (!match) {\n // This should never hit I don't think?\n throw getInternalRouterError(404, { pathname: location.pathname });\n }\n\n let result = await queryImpl(\n request,\n location,\n matches,\n requestContext,\n match\n );\n if (isResponse(result)) {\n return result;\n }\n\n let error = result.errors ? Object.values(result.errors)[0] : undefined;\n if (error !== undefined) {\n // If we got back result.errors, that means the loader/action threw\n // _something_ that wasn't a Response, but it's not guaranteed/required\n // to be an `instanceof Error` either, so we have to use throw here to\n // preserve the \"error\" state outside of queryImpl.\n throw error;\n }\n\n // Pick off the right state value to return\n if (result.actionData) {\n return Object.values(result.actionData)[0];\n }\n\n if (result.loaderData) {\n let data = Object.values(result.loaderData)[0];\n if (result.activeDeferreds?.[match.route.id]) {\n data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];\n }\n return data;\n }\n\n return undefined;\n }\n\n async function queryImpl(\n request: Request,\n location: Location,\n matches: AgnosticDataRouteMatch[],\n requestContext: unknown,\n routeMatch?: AgnosticDataRouteMatch\n ): Promise | Response> {\n invariant(\n request.signal,\n \"query()/queryRoute() requests must contain an AbortController signal\"\n );\n\n try {\n if (isMutationMethod(request.method.toLowerCase())) {\n let result = await submit(\n request,\n matches,\n routeMatch || getTargetMatch(matches, location),\n requestContext,\n routeMatch != null\n );\n return result;\n }\n\n let result = await loadRouteData(\n request,\n matches,\n requestContext,\n routeMatch\n );\n return isResponse(result)\n ? result\n : {\n ...result,\n actionData: null,\n actionHeaders: {},\n };\n } catch (e) {\n // If the user threw/returned a Response in callLoaderOrAction, we throw\n // it to bail out and then return or throw here based on whether the user\n // returned or threw\n if (isQueryRouteResponse(e)) {\n if (e.type === ResultType.error) {\n throw e.response;\n }\n return e.response;\n }\n // Redirects are always returned since they don't propagate to catch\n // boundaries\n if (isRedirectResponse(e)) {\n return e;\n }\n throw e;\n }\n }\n\n async function submit(\n request: Request,\n matches: AgnosticDataRouteMatch[],\n actionMatch: AgnosticDataRouteMatch,\n requestContext: unknown,\n isRouteRequest: boolean\n ): Promise | Response> {\n let result: DataResult;\n\n if (!actionMatch.route.action && !actionMatch.route.lazy) {\n let error = getInternalRouterError(405, {\n method: request.method,\n pathname: new URL(request.url).pathname,\n routeId: actionMatch.route.id,\n });\n if (isRouteRequest) {\n throw error;\n }\n result = {\n type: ResultType.error,\n error,\n };\n } else {\n result = await callLoaderOrAction(\n \"action\",\n request,\n actionMatch,\n matches,\n manifest,\n mapRouteProperties,\n basename,\n { isStaticRequest: true, isRouteRequest, requestContext }\n );\n\n if (request.signal.aborted) {\n let method = isRouteRequest ? \"queryRoute\" : \"query\";\n throw new Error(\n `${method}() call aborted: ${request.method} ${request.url}`\n );\n }\n }\n\n if (isRedirectResult(result)) {\n // Uhhhh - this should never happen, we should always throw these from\n // callLoaderOrAction, but the type narrowing here keeps TS happy and we\n // can get back on the \"throw all redirect responses\" train here should\n // this ever happen :/\n throw new Response(null, {\n status: result.status,\n headers: {\n Location: result.location,\n },\n });\n }\n\n if (isDeferredResult(result)) {\n let error = getInternalRouterError(400, { type: \"defer-action\" });\n if (isRouteRequest) {\n throw error;\n }\n result = {\n type: ResultType.error,\n error,\n };\n }\n\n if (isRouteRequest) {\n // Note: This should only be non-Response values if we get here, since\n // isRouteRequest should throw any Response received in callLoaderOrAction\n if (isErrorResult(result)) {\n throw result.error;\n }\n\n return {\n matches: [actionMatch],\n loaderData: {},\n actionData: { [actionMatch.route.id]: result.data },\n errors: null,\n // Note: statusCode + headers are unused here since queryRoute will\n // return the raw Response or value\n statusCode: 200,\n loaderHeaders: {},\n actionHeaders: {},\n activeDeferreds: null,\n };\n }\n\n if (isErrorResult(result)) {\n // Store off the pending error - we use it to determine which loaders\n // to call and will commit it when we complete the navigation\n let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);\n let context = await loadRouteData(\n request,\n matches,\n requestContext,\n undefined,\n {\n [boundaryMatch.route.id]: result.error,\n }\n );\n\n // action status codes take precedence over loader status codes\n return {\n ...context,\n statusCode: isRouteErrorResponse(result.error)\n ? result.error.status\n : 500,\n actionData: null,\n actionHeaders: {\n ...(result.headers ? { [actionMatch.route.id]: result.headers } : {}),\n },\n };\n }\n\n // Create a GET request for the loaders\n let loaderRequest = new Request(request.url, {\n headers: request.headers,\n redirect: request.redirect,\n signal: request.signal,\n });\n let context = await loadRouteData(loaderRequest, matches, requestContext);\n\n return {\n ...context,\n // action status codes take precedence over loader status codes\n ...(result.statusCode ? { statusCode: result.statusCode } : {}),\n actionData: {\n [actionMatch.route.id]: result.data,\n },\n actionHeaders: {\n ...(result.headers ? { [actionMatch.route.id]: result.headers } : {}),\n },\n };\n }\n\n async function loadRouteData(\n request: Request,\n matches: AgnosticDataRouteMatch[],\n requestContext: unknown,\n routeMatch?: AgnosticDataRouteMatch,\n pendingActionError?: RouteData\n ): Promise<\n | Omit<\n StaticHandlerContext,\n \"location\" | \"basename\" | \"actionData\" | \"actionHeaders\"\n >\n | Response\n > {\n let isRouteRequest = routeMatch != null;\n\n // Short circuit if we have no loaders to run (queryRoute())\n if (\n isRouteRequest &&\n !routeMatch?.route.loader &&\n !routeMatch?.route.lazy\n ) {\n throw getInternalRouterError(400, {\n method: request.method,\n pathname: new URL(request.url).pathname,\n routeId: routeMatch?.route.id,\n });\n }\n\n let requestMatches = routeMatch\n ? [routeMatch]\n : getLoaderMatchesUntilBoundary(\n matches,\n Object.keys(pendingActionError || {})[0]\n );\n let matchesToLoad = requestMatches.filter(\n (m) => m.route.loader || m.route.lazy\n );\n\n // Short circuit if we have no loaders to run (query())\n if (matchesToLoad.length === 0) {\n return {\n matches,\n // Add a null for all matched routes for proper revalidation on the client\n loaderData: matches.reduce(\n (acc, m) => Object.assign(acc, { [m.route.id]: null }),\n {}\n ),\n errors: pendingActionError || null,\n statusCode: 200,\n loaderHeaders: {},\n activeDeferreds: null,\n };\n }\n\n let results = await Promise.all([\n ...matchesToLoad.map((match) =>\n callLoaderOrAction(\n \"loader\",\n request,\n match,\n matches,\n manifest,\n mapRouteProperties,\n basename,\n { isStaticRequest: true, isRouteRequest, requestContext }\n )\n ),\n ]);\n\n if (request.signal.aborted) {\n let method = isRouteRequest ? \"queryRoute\" : \"query\";\n throw new Error(\n `${method}() call aborted: ${request.method} ${request.url}`\n );\n }\n\n // Process and commit output from loaders\n let activeDeferreds = new Map();\n let context = processRouteLoaderData(\n matches,\n matchesToLoad,\n results,\n pendingActionError,\n activeDeferreds\n );\n\n // Add a null for any non-loader matches for proper revalidation on the client\n let executedLoaders = new Set(\n matchesToLoad.map((match) => match.route.id)\n );\n matches.forEach((match) => {\n if (!executedLoaders.has(match.route.id)) {\n context.loaderData[match.route.id] = null;\n }\n });\n\n return {\n ...context,\n matches,\n activeDeferreds:\n activeDeferreds.size > 0\n ? Object.fromEntries(activeDeferreds.entries())\n : null,\n };\n }\n\n return {\n dataRoutes,\n query,\n queryRoute,\n };\n}\n\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Helpers\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * Given an existing StaticHandlerContext and an error thrown at render time,\n * provide an updated StaticHandlerContext suitable for a second SSR render\n */\nexport function getStaticContextFromError(\n routes: AgnosticDataRouteObject[],\n context: StaticHandlerContext,\n error: any\n) {\n let newContext: StaticHandlerContext = {\n ...context,\n statusCode: 500,\n errors: {\n [context._deepestRenderedBoundaryId || routes[0].id]: error,\n },\n };\n return newContext;\n}\n\nfunction isSubmissionNavigation(\n opts: BaseNavigateOrFetchOptions\n): opts is SubmissionNavigateOptions {\n return (\n opts != null &&\n ((\"formData\" in opts && opts.formData != null) ||\n (\"body\" in opts && opts.body !== undefined))\n );\n}\n\nfunction normalizeTo(\n location: Path,\n matches: AgnosticDataRouteMatch[],\n basename: string,\n prependBasename: boolean,\n to: To | null,\n fromRouteId?: string,\n relative?: RelativeRoutingType\n) {\n let contextualMatches: AgnosticDataRouteMatch[];\n let activeRouteMatch: AgnosticDataRouteMatch | undefined;\n if (fromRouteId != null && relative !== \"path\") {\n // Grab matches up to the calling route so our route-relative logic is\n // relative to the correct source route. When using relative:path,\n // fromRouteId is ignored since that is always relative to the current\n // location path\n contextualMatches = [];\n for (let match of matches) {\n contextualMatches.push(match);\n if (match.route.id === fromRouteId) {\n activeRouteMatch = match;\n break;\n }\n }\n } else {\n contextualMatches = matches;\n activeRouteMatch = matches[matches.length - 1];\n }\n\n // Resolve the relative path\n let path = resolveTo(\n to ? to : \".\",\n getPathContributingMatches(contextualMatches).map((m) => m.pathnameBase),\n stripBasename(location.pathname, basename) || location.pathname,\n relative === \"path\"\n );\n\n // When `to` is not specified we inherit search/hash from the current\n // location, unlike when to=\".\" and we just inherit the path.\n // See https://github.com/remix-run/remix/issues/927\n if (to == null) {\n path.search = location.search;\n path.hash = location.hash;\n }\n\n // Add an ?index param for matched index routes if we don't already have one\n if (\n (to == null || to === \"\" || to === \".\") &&\n activeRouteMatch &&\n activeRouteMatch.route.index &&\n !hasNakedIndexQuery(path.search)\n ) {\n path.search = path.search\n ? path.search.replace(/^\\?/, \"?index&\")\n : \"?index\";\n }\n\n // If we're operating within a basename, prepend it to the pathname. If\n // this is a root navigation, then just use the raw basename which allows\n // the basename to have full control over the presence of a trailing slash\n // on root actions\n if (prependBasename && basename !== \"/\") {\n path.pathname =\n path.pathname === \"/\" ? basename : joinPaths([basename, path.pathname]);\n }\n\n return createPath(path);\n}\n\n// Normalize navigation options by converting formMethod=GET formData objects to\n// URLSearchParams so they behave identically to links with query params\nfunction normalizeNavigateOptions(\n normalizeFormMethod: boolean,\n isFetcher: boolean,\n path: string,\n opts?: BaseNavigateOrFetchOptions\n): {\n path: string;\n submission?: Submission;\n error?: ErrorResponseImpl;\n} {\n // Return location verbatim on non-submission navigations\n if (!opts || !isSubmissionNavigation(opts)) {\n return { path };\n }\n\n if (opts.formMethod && !isValidMethod(opts.formMethod)) {\n return {\n path,\n error: getInternalRouterError(405, { method: opts.formMethod }),\n };\n }\n\n let getInvalidBodyError = () => ({\n path,\n error: getInternalRouterError(400, { type: \"invalid-body\" }),\n });\n\n // Create a Submission on non-GET navigations\n let rawFormMethod = opts.formMethod || \"get\";\n let formMethod = normalizeFormMethod\n ? (rawFormMethod.toUpperCase() as V7_FormMethod)\n : (rawFormMethod.toLowerCase() as FormMethod);\n let formAction = stripHashFromPath(path);\n\n if (opts.body !== undefined) {\n if (opts.formEncType === \"text/plain\") {\n // text only support POST/PUT/PATCH/DELETE submissions\n if (!isMutationMethod(formMethod)) {\n return getInvalidBodyError();\n }\n\n let text =\n typeof opts.body === \"string\"\n ? opts.body\n : opts.body instanceof FormData ||\n opts.body instanceof URLSearchParams\n ? // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data\n Array.from(opts.body.entries()).reduce(\n (acc, [name, value]) => `${acc}${name}=${value}\\n`,\n \"\"\n )\n : String(opts.body);\n\n return {\n path,\n submission: {\n formMethod,\n formAction,\n formEncType: opts.formEncType,\n formData: undefined,\n json: undefined,\n text,\n },\n };\n } else if (opts.formEncType === \"application/json\") {\n // json only supports POST/PUT/PATCH/DELETE submissions\n if (!isMutationMethod(formMethod)) {\n return getInvalidBodyError();\n }\n\n try {\n let json =\n typeof opts.body === \"string\" ? JSON.parse(opts.body) : opts.body;\n\n return {\n path,\n submission: {\n formMethod,\n formAction,\n formEncType: opts.formEncType,\n formData: undefined,\n json,\n text: undefined,\n },\n };\n } catch (e) {\n return getInvalidBodyError();\n }\n }\n }\n\n invariant(\n typeof FormData === \"function\",\n \"FormData is not available in this environment\"\n );\n\n let searchParams: URLSearchParams;\n let formData: FormData;\n\n if (opts.formData) {\n searchParams = convertFormDataToSearchParams(opts.formData);\n formData = opts.formData;\n } else if (opts.body instanceof FormData) {\n searchParams = convertFormDataToSearchParams(opts.body);\n formData = opts.body;\n } else if (opts.body instanceof URLSearchParams) {\n searchParams = opts.body;\n formData = convertSearchParamsToFormData(searchParams);\n } else if (opts.body == null) {\n searchParams = new URLSearchParams();\n formData = new FormData();\n } else {\n try {\n searchParams = new URLSearchParams(opts.body);\n formData = convertSearchParamsToFormData(searchParams);\n } catch (e) {\n return getInvalidBodyError();\n }\n }\n\n let submission: Submission = {\n formMethod,\n formAction,\n formEncType:\n (opts && opts.formEncType) || \"application/x-www-form-urlencoded\",\n formData,\n json: undefined,\n text: undefined,\n };\n\n if (isMutationMethod(submission.formMethod)) {\n return { path, submission };\n }\n\n // Flatten submission onto URLSearchParams for GET submissions\n let parsedPath = parsePath(path);\n // On GET navigation submissions we can drop the ?index param from the\n // resulting location since all loaders will run. But fetcher GET submissions\n // only run a single loader so we need to preserve any incoming ?index params\n if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {\n searchParams.append(\"index\", \"\");\n }\n parsedPath.search = `?${searchParams}`;\n\n return { path: createPath(parsedPath), submission };\n}\n\n// Filter out all routes below any caught error as they aren't going to\n// render so we don't need to load them\nfunction getLoaderMatchesUntilBoundary(\n matches: AgnosticDataRouteMatch[],\n boundaryId?: string\n) {\n let boundaryMatches = matches;\n if (boundaryId) {\n let index = matches.findIndex((m) => m.route.id === boundaryId);\n if (index >= 0) {\n boundaryMatches = matches.slice(0, index);\n }\n }\n return boundaryMatches;\n}\n\nfunction getMatchesToLoad(\n history: History,\n state: RouterState,\n matches: AgnosticDataRouteMatch[],\n submission: Submission | undefined,\n location: Location,\n isRevalidationRequired: boolean,\n cancelledDeferredRoutes: string[],\n cancelledFetcherLoads: string[],\n fetchLoadMatches: Map,\n fetchRedirectIds: Set,\n routesToUse: AgnosticDataRouteObject[],\n basename: string | undefined,\n pendingActionData?: RouteData,\n pendingError?: RouteData\n): [AgnosticDataRouteMatch[], RevalidatingFetcher[]] {\n let actionResult = pendingError\n ? Object.values(pendingError)[0]\n : pendingActionData\n ? Object.values(pendingActionData)[0]\n : undefined;\n\n let currentUrl = history.createURL(state.location);\n let nextUrl = history.createURL(location);\n\n // Pick navigation matches that are net-new or qualify for revalidation\n let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;\n let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);\n\n let navigationMatches = boundaryMatches.filter((match, index) => {\n if (match.route.lazy) {\n // We haven't loaded this route yet so we don't know if it's got a loader!\n return true;\n }\n if (match.route.loader == null) {\n return false;\n }\n\n // Always call the loader on new route instances and pending defer cancellations\n if (\n isNewLoader(state.loaderData, state.matches[index], match) ||\n cancelledDeferredRoutes.some((id) => id === match.route.id)\n ) {\n return true;\n }\n\n // This is the default implementation for when we revalidate. If the route\n // provides it's own implementation, then we give them full control but\n // provide this value so they can leverage it if needed after they check\n // their own specific use cases\n let currentRouteMatch = state.matches[index];\n let nextRouteMatch = match;\n\n return shouldRevalidateLoader(match, {\n currentUrl,\n currentParams: currentRouteMatch.params,\n nextUrl,\n nextParams: nextRouteMatch.params,\n ...submission,\n actionResult,\n defaultShouldRevalidate:\n // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate\n isRevalidationRequired ||\n // Clicked the same link, resubmitted a GET form\n currentUrl.pathname + currentUrl.search ===\n nextUrl.pathname + nextUrl.search ||\n // Search params affect all loaders\n currentUrl.search !== nextUrl.search ||\n isNewRouteInstance(currentRouteMatch, nextRouteMatch),\n });\n });\n\n // Pick fetcher.loads that need to be revalidated\n let revalidatingFetchers: RevalidatingFetcher[] = [];\n fetchLoadMatches.forEach((f, key) => {\n // Don't revalidate if fetcher won't be present in the subsequent render\n if (!matches.some((m) => m.route.id === f.routeId)) {\n return;\n }\n\n let fetcherMatches = matchRoutes(routesToUse, f.path, basename);\n\n // If the fetcher path no longer matches, push it in with null matches so\n // we can trigger a 404 in callLoadersAndMaybeResolveData. Note this is\n // currently only a use-case for Remix HMR where the route tree can change\n // at runtime and remove a route previously loaded via a fetcher\n if (!fetcherMatches) {\n revalidatingFetchers.push({\n key,\n routeId: f.routeId,\n path: f.path,\n matches: null,\n match: null,\n controller: null,\n });\n return;\n }\n\n // Revalidating fetchers are decoupled from the route matches since they\n // load from a static href. They revalidate based on explicit revalidation\n // (submission, useRevalidator, or X-Remix-Revalidate)\n let fetcher = state.fetchers.get(key);\n let fetcherMatch = getTargetMatch(fetcherMatches, f.path);\n\n let shouldRevalidate = false;\n if (fetchRedirectIds.has(key)) {\n // Never trigger a revalidation of an actively redirecting fetcher\n shouldRevalidate = false;\n } else if (cancelledFetcherLoads.includes(key)) {\n // Always revalidate if the fetcher was cancelled\n shouldRevalidate = true;\n } else if (\n fetcher &&\n fetcher.state !== \"idle\" &&\n fetcher.data === undefined\n ) {\n // If the fetcher hasn't ever completed loading yet, then this isn't a\n // revalidation, it would just be a brand new load if an explicit\n // revalidation is required\n shouldRevalidate = isRevalidationRequired;\n } else {\n // Otherwise fall back on any user-defined shouldRevalidate, defaulting\n // to explicit revalidations only\n shouldRevalidate = shouldRevalidateLoader(fetcherMatch, {\n currentUrl,\n currentParams: state.matches[state.matches.length - 1].params,\n nextUrl,\n nextParams: matches[matches.length - 1].params,\n ...submission,\n actionResult,\n defaultShouldRevalidate: isRevalidationRequired,\n });\n }\n\n if (shouldRevalidate) {\n revalidatingFetchers.push({\n key,\n routeId: f.routeId,\n path: f.path,\n matches: fetcherMatches,\n match: fetcherMatch,\n controller: new AbortController(),\n });\n }\n });\n\n return [navigationMatches, revalidatingFetchers];\n}\n\nfunction isNewLoader(\n currentLoaderData: RouteData,\n currentMatch: AgnosticDataRouteMatch,\n match: AgnosticDataRouteMatch\n) {\n let isNew =\n // [a] -> [a, b]\n !currentMatch ||\n // [a, b] -> [a, c]\n match.route.id !== currentMatch.route.id;\n\n // Handle the case that we don't have data for a re-used route, potentially\n // from a prior error or from a cancelled pending deferred\n let isMissingData = currentLoaderData[match.route.id] === undefined;\n\n // Always load if this is a net-new route or we don't yet have data\n return isNew || isMissingData;\n}\n\nfunction isNewRouteInstance(\n currentMatch: AgnosticDataRouteMatch,\n match: AgnosticDataRouteMatch\n) {\n let currentPath = currentMatch.route.path;\n return (\n // param change for this match, /users/123 -> /users/456\n currentMatch.pathname !== match.pathname ||\n // splat param changed, which is not present in match.path\n // e.g. /files/images/avatar.jpg -> files/finances.xls\n (currentPath != null &&\n currentPath.endsWith(\"*\") &&\n currentMatch.params[\"*\"] !== match.params[\"*\"])\n );\n}\n\nfunction shouldRevalidateLoader(\n loaderMatch: AgnosticDataRouteMatch,\n arg: ShouldRevalidateFunctionArgs\n) {\n if (loaderMatch.route.shouldRevalidate) {\n let routeChoice = loaderMatch.route.shouldRevalidate(arg);\n if (typeof routeChoice === \"boolean\") {\n return routeChoice;\n }\n }\n\n return arg.defaultShouldRevalidate;\n}\n\n/**\n * Execute route.lazy() methods to lazily load route modules (loader, action,\n * shouldRevalidate) and update the routeManifest in place which shares objects\n * with dataRoutes so those get updated as well.\n */\nasync function loadLazyRouteModule(\n route: AgnosticDataRouteObject,\n mapRouteProperties: MapRoutePropertiesFunction,\n manifest: RouteManifest\n) {\n if (!route.lazy) {\n return;\n }\n\n let lazyRoute = await route.lazy();\n\n // If the lazy route function was executed and removed by another parallel\n // call then we can return - first lazy() to finish wins because the return\n // value of lazy is expected to be static\n if (!route.lazy) {\n return;\n }\n\n let routeToUpdate = manifest[route.id];\n invariant(routeToUpdate, \"No route found in manifest\");\n\n // Update the route in place. This should be safe because there's no way\n // we could yet be sitting on this route as we can't get there without\n // resolving lazy() first.\n //\n // This is different than the HMR \"update\" use-case where we may actively be\n // on the route being updated. The main concern boils down to \"does this\n // mutation affect any ongoing navigations or any current state.matches\n // values?\". If not, it should be safe to update in place.\n let routeUpdates: Record = {};\n for (let lazyRouteProperty in lazyRoute) {\n let staticRouteValue =\n routeToUpdate[lazyRouteProperty as keyof typeof routeToUpdate];\n\n let isPropertyStaticallyDefined =\n staticRouteValue !== undefined &&\n // This property isn't static since it should always be updated based\n // on the route updates\n lazyRouteProperty !== \"hasErrorBoundary\";\n\n warning(\n !isPropertyStaticallyDefined,\n `Route \"${routeToUpdate.id}\" has a static property \"${lazyRouteProperty}\" ` +\n `defined but its lazy function is also returning a value for this property. ` +\n `The lazy route property \"${lazyRouteProperty}\" will be ignored.`\n );\n\n if (\n !isPropertyStaticallyDefined &&\n !immutableRouteKeys.has(lazyRouteProperty as ImmutableRouteKey)\n ) {\n routeUpdates[lazyRouteProperty] =\n lazyRoute[lazyRouteProperty as keyof typeof lazyRoute];\n }\n }\n\n // Mutate the route with the provided updates. Do this first so we pass\n // the updated version to mapRouteProperties\n Object.assign(routeToUpdate, routeUpdates);\n\n // Mutate the `hasErrorBoundary` property on the route based on the route\n // updates and remove the `lazy` function so we don't resolve the lazy\n // route again.\n Object.assign(routeToUpdate, {\n // To keep things framework agnostic, we use the provided\n // `mapRouteProperties` (or wrapped `detectErrorBoundary`) function to\n // set the framework-aware properties (`element`/`hasErrorBoundary`) since\n // the logic will differ between frameworks.\n ...mapRouteProperties(routeToUpdate),\n lazy: undefined,\n });\n}\n\nasync function callLoaderOrAction(\n type: \"loader\" | \"action\",\n request: Request,\n match: AgnosticDataRouteMatch,\n matches: AgnosticDataRouteMatch[],\n manifest: RouteManifest,\n mapRouteProperties: MapRoutePropertiesFunction,\n basename: string,\n opts: {\n isStaticRequest?: boolean;\n isRouteRequest?: boolean;\n requestContext?: unknown;\n } = {}\n): Promise {\n let resultType;\n let result;\n let onReject: (() => void) | undefined;\n\n let runHandler = (handler: ActionFunction | LoaderFunction) => {\n // Setup a promise we can race against so that abort signals short circuit\n let reject: () => void;\n let abortPromise = new Promise((_, r) => (reject = r));\n onReject = () => reject();\n request.signal.addEventListener(\"abort\", onReject);\n return Promise.race([\n handler({\n request,\n params: match.params,\n context: opts.requestContext,\n }),\n abortPromise,\n ]);\n };\n\n try {\n let handler = match.route[type];\n\n if (match.route.lazy) {\n if (handler) {\n // Run statically defined handler in parallel with lazy()\n let handlerError;\n let values = await Promise.all([\n // If the handler throws, don't let it immediately bubble out,\n // since we need to let the lazy() execution finish so we know if this\n // route has a boundary that can handle the error\n runHandler(handler).catch((e) => {\n handlerError = e;\n }),\n loadLazyRouteModule(match.route, mapRouteProperties, manifest),\n ]);\n if (handlerError) {\n throw handlerError;\n }\n result = values[0];\n } else {\n // Load lazy route module, then run any returned handler\n await loadLazyRouteModule(match.route, mapRouteProperties, manifest);\n\n handler = match.route[type];\n if (handler) {\n // Handler still run even if we got interrupted to maintain consistency\n // with un-abortable behavior of handler execution on non-lazy or\n // previously-lazy-loaded routes\n result = await runHandler(handler);\n } else if (type === \"action\") {\n let url = new URL(request.url);\n let pathname = url.pathname + url.search;\n throw getInternalRouterError(405, {\n method: request.method,\n pathname,\n routeId: match.route.id,\n });\n } else {\n // lazy() route has no loader to run. Short circuit here so we don't\n // hit the invariant below that errors on returning undefined.\n return { type: ResultType.data, data: undefined };\n }\n }\n } else if (!handler) {\n let url = new URL(request.url);\n let pathname = url.pathname + url.search;\n throw getInternalRouterError(404, {\n pathname,\n });\n } else {\n result = await runHandler(handler);\n }\n\n invariant(\n result !== undefined,\n `You defined ${type === \"action\" ? \"an action\" : \"a loader\"} for route ` +\n `\"${match.route.id}\" but didn't return anything from your \\`${type}\\` ` +\n `function. Please return a value or \\`null\\`.`\n );\n } catch (e) {\n resultType = ResultType.error;\n result = e;\n } finally {\n if (onReject) {\n request.signal.removeEventListener(\"abort\", onReject);\n }\n }\n\n if (isResponse(result)) {\n let status = result.status;\n\n // Process redirects\n if (redirectStatusCodes.has(status)) {\n let location = result.headers.get(\"Location\");\n invariant(\n location,\n \"Redirects returned/thrown from loaders/actions must have a Location header\"\n );\n\n // Support relative routing in internal redirects\n if (!ABSOLUTE_URL_REGEX.test(location)) {\n location = normalizeTo(\n new URL(request.url),\n matches.slice(0, matches.indexOf(match) + 1),\n basename,\n true,\n location\n );\n } else if (!opts.isStaticRequest) {\n // Strip off the protocol+origin for same-origin + same-basename absolute\n // redirects. If this is a static request, we can let it go back to the\n // browser as-is\n let currentUrl = new URL(request.url);\n let url = location.startsWith(\"//\")\n ? new URL(currentUrl.protocol + location)\n : new URL(location);\n let isSameBasename = stripBasename(url.pathname, basename) != null;\n if (url.origin === currentUrl.origin && isSameBasename) {\n location = url.pathname + url.search + url.hash;\n }\n }\n\n // Don't process redirects in the router during static requests requests.\n // Instead, throw the Response and let the server handle it with an HTTP\n // redirect. We also update the Location header in place in this flow so\n // basename and relative routing is taken into account\n if (opts.isStaticRequest) {\n result.headers.set(\"Location\", location);\n throw result;\n }\n\n return {\n type: ResultType.redirect,\n status,\n location,\n revalidate: result.headers.get(\"X-Remix-Revalidate\") !== null,\n reloadDocument: result.headers.get(\"X-Remix-Reload-Document\") !== null,\n };\n }\n\n // For SSR single-route requests, we want to hand Responses back directly\n // without unwrapping. We do this with the QueryRouteResponse wrapper\n // interface so we can know whether it was returned or thrown\n if (opts.isRouteRequest) {\n let queryRouteResponse: QueryRouteResponse = {\n type:\n resultType === ResultType.error ? ResultType.error : ResultType.data,\n response: result,\n };\n throw queryRouteResponse;\n }\n\n let data: any;\n let contentType = result.headers.get(\"Content-Type\");\n // Check between word boundaries instead of startsWith() due to the last\n // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type\n if (contentType && /\\bapplication\\/json\\b/.test(contentType)) {\n data = await result.json();\n } else {\n data = await result.text();\n }\n\n if (resultType === ResultType.error) {\n return {\n type: resultType,\n error: new ErrorResponseImpl(status, result.statusText, data),\n headers: result.headers,\n };\n }\n\n return {\n type: ResultType.data,\n data,\n statusCode: result.status,\n headers: result.headers,\n };\n }\n\n if (resultType === ResultType.error) {\n return { type: resultType, error: result };\n }\n\n if (isDeferredData(result)) {\n return {\n type: ResultType.deferred,\n deferredData: result,\n statusCode: result.init?.status,\n headers: result.init?.headers && new Headers(result.init.headers),\n };\n }\n\n return { type: ResultType.data, data: result };\n}\n\n// Utility method for creating the Request instances for loaders/actions during\n// client-side navigations and fetches. During SSR we will always have a\n// Request instance from the static handler (query/queryRoute)\nfunction createClientSideRequest(\n history: History,\n location: string | Location,\n signal: AbortSignal,\n submission?: Submission\n): Request {\n let url = history.createURL(stripHashFromPath(location)).toString();\n let init: RequestInit = { signal };\n\n if (submission && isMutationMethod(submission.formMethod)) {\n let { formMethod, formEncType } = submission;\n // Didn't think we needed this but it turns out unlike other methods, patch\n // won't be properly normalized to uppercase and results in a 405 error.\n // See: https://fetch.spec.whatwg.org/#concept-method\n init.method = formMethod.toUpperCase();\n\n if (formEncType === \"application/json\") {\n init.headers = new Headers({ \"Content-Type\": formEncType });\n init.body = JSON.stringify(submission.json);\n } else if (formEncType === \"text/plain\") {\n // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)\n init.body = submission.text;\n } else if (\n formEncType === \"application/x-www-form-urlencoded\" &&\n submission.formData\n ) {\n // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)\n init.body = convertFormDataToSearchParams(submission.formData);\n } else {\n // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)\n init.body = submission.formData;\n }\n }\n\n return new Request(url, init);\n}\n\nfunction convertFormDataToSearchParams(formData: FormData): URLSearchParams {\n let searchParams = new URLSearchParams();\n\n for (let [key, value] of formData.entries()) {\n // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs\n searchParams.append(key, typeof value === \"string\" ? value : value.name);\n }\n\n return searchParams;\n}\n\nfunction convertSearchParamsToFormData(\n searchParams: URLSearchParams\n): FormData {\n let formData = new FormData();\n for (let [key, value] of searchParams.entries()) {\n formData.append(key, value);\n }\n return formData;\n}\n\nfunction processRouteLoaderData(\n matches: AgnosticDataRouteMatch[],\n matchesToLoad: AgnosticDataRouteMatch[],\n results: DataResult[],\n pendingError: RouteData | undefined,\n activeDeferreds: Map\n): {\n loaderData: RouterState[\"loaderData\"];\n errors: RouterState[\"errors\"] | null;\n statusCode: number;\n loaderHeaders: Record;\n} {\n // Fill in loaderData/errors from our loaders\n let loaderData: RouterState[\"loaderData\"] = {};\n let errors: RouterState[\"errors\"] | null = null;\n let statusCode: number | undefined;\n let foundError = false;\n let loaderHeaders: Record = {};\n\n // Process loader results into state.loaderData/state.errors\n results.forEach((result, index) => {\n let id = matchesToLoad[index].route.id;\n invariant(\n !isRedirectResult(result),\n \"Cannot handle redirect results in processLoaderData\"\n );\n if (isErrorResult(result)) {\n // Look upwards from the matched route for the closest ancestor\n // error boundary, defaulting to the root match\n let boundaryMatch = findNearestBoundary(matches, id);\n let error = result.error;\n // If we have a pending action error, we report it at the highest-route\n // that throws a loader error, and then clear it out to indicate that\n // it was consumed\n if (pendingError) {\n error = Object.values(pendingError)[0];\n pendingError = undefined;\n }\n\n errors = errors || {};\n\n // Prefer higher error values if lower errors bubble to the same boundary\n if (errors[boundaryMatch.route.id] == null) {\n errors[boundaryMatch.route.id] = error;\n }\n\n // Clear our any prior loaderData for the throwing route\n loaderData[id] = undefined;\n\n // Once we find our first (highest) error, we set the status code and\n // prevent deeper status codes from overriding\n if (!foundError) {\n foundError = true;\n statusCode = isRouteErrorResponse(result.error)\n ? result.error.status\n : 500;\n }\n if (result.headers) {\n loaderHeaders[id] = result.headers;\n }\n } else {\n if (isDeferredResult(result)) {\n activeDeferreds.set(id, result.deferredData);\n loaderData[id] = result.deferredData.data;\n } else {\n loaderData[id] = result.data;\n }\n\n // Error status codes always override success status codes, but if all\n // loaders are successful we take the deepest status code.\n if (\n result.statusCode != null &&\n result.statusCode !== 200 &&\n !foundError\n ) {\n statusCode = result.statusCode;\n }\n if (result.headers) {\n loaderHeaders[id] = result.headers;\n }\n }\n });\n\n // If we didn't consume the pending action error (i.e., all loaders\n // resolved), then consume it here. Also clear out any loaderData for the\n // throwing route\n if (pendingError) {\n errors = pendingError;\n loaderData[Object.keys(pendingError)[0]] = undefined;\n }\n\n return {\n loaderData,\n errors,\n statusCode: statusCode || 200,\n loaderHeaders,\n };\n}\n\nfunction processLoaderData(\n state: RouterState,\n matches: AgnosticDataRouteMatch[],\n matchesToLoad: AgnosticDataRouteMatch[],\n results: DataResult[],\n pendingError: RouteData | undefined,\n revalidatingFetchers: RevalidatingFetcher[],\n fetcherResults: DataResult[],\n activeDeferreds: Map\n): {\n loaderData: RouterState[\"loaderData\"];\n errors?: RouterState[\"errors\"];\n} {\n let { loaderData, errors } = processRouteLoaderData(\n matches,\n matchesToLoad,\n results,\n pendingError,\n activeDeferreds\n );\n\n // Process results from our revalidating fetchers\n for (let index = 0; index < revalidatingFetchers.length; index++) {\n let { key, match, controller } = revalidatingFetchers[index];\n invariant(\n fetcherResults !== undefined && fetcherResults[index] !== undefined,\n \"Did not find corresponding fetcher result\"\n );\n let result = fetcherResults[index];\n\n // Process fetcher non-redirect errors\n if (controller && controller.signal.aborted) {\n // Nothing to do for aborted fetchers\n continue;\n } else if (isErrorResult(result)) {\n let boundaryMatch = findNearestBoundary(state.matches, match?.route.id);\n if (!(errors && errors[boundaryMatch.route.id])) {\n errors = {\n ...errors,\n [boundaryMatch.route.id]: result.error,\n };\n }\n state.fetchers.delete(key);\n } else if (isRedirectResult(result)) {\n // Should never get here, redirects should get processed above, but we\n // keep this to type narrow to a success result in the else\n invariant(false, \"Unhandled fetcher revalidation redirect\");\n } else if (isDeferredResult(result)) {\n // Should never get here, deferred data should be awaited for fetchers\n // in resolveDeferredResults\n invariant(false, \"Unhandled fetcher deferred data\");\n } else {\n let doneFetcher = getDoneFetcher(result.data);\n state.fetchers.set(key, doneFetcher);\n }\n }\n\n return { loaderData, errors };\n}\n\nfunction mergeLoaderData(\n loaderData: RouteData,\n newLoaderData: RouteData,\n matches: AgnosticDataRouteMatch[],\n errors: RouteData | null | undefined\n): RouteData {\n let mergedLoaderData = { ...newLoaderData };\n for (let match of matches) {\n let id = match.route.id;\n if (newLoaderData.hasOwnProperty(id)) {\n if (newLoaderData[id] !== undefined) {\n mergedLoaderData[id] = newLoaderData[id];\n } else {\n // No-op - this is so we ignore existing data if we have a key in the\n // incoming object with an undefined value, which is how we unset a prior\n // loaderData if we encounter a loader error\n }\n } else if (loaderData[id] !== undefined && match.route.loader) {\n // Preserve existing keys not included in newLoaderData and where a loader\n // wasn't removed by HMR\n mergedLoaderData[id] = loaderData[id];\n }\n\n if (errors && errors.hasOwnProperty(id)) {\n // Don't keep any loader data below the boundary\n break;\n }\n }\n return mergedLoaderData;\n}\n\n// Find the nearest error boundary, looking upwards from the leaf route (or the\n// route specified by routeId) for the closest ancestor error boundary,\n// defaulting to the root match\nfunction findNearestBoundary(\n matches: AgnosticDataRouteMatch[],\n routeId?: string\n): AgnosticDataRouteMatch {\n let eligibleMatches = routeId\n ? matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1)\n : [...matches];\n return (\n eligibleMatches.reverse().find((m) => m.route.hasErrorBoundary === true) ||\n matches[0]\n );\n}\n\nfunction getShortCircuitMatches(routes: AgnosticDataRouteObject[]): {\n matches: AgnosticDataRouteMatch[];\n route: AgnosticDataRouteObject;\n} {\n // Prefer a root layout route if present, otherwise shim in a route object\n let route =\n routes.length === 1\n ? routes[0]\n : routes.find((r) => r.index || !r.path || r.path === \"/\") || {\n id: `__shim-error-route__`,\n };\n\n return {\n matches: [\n {\n params: {},\n pathname: \"\",\n pathnameBase: \"\",\n route,\n },\n ],\n route,\n };\n}\n\nfunction getInternalRouterError(\n status: number,\n {\n pathname,\n routeId,\n method,\n type,\n }: {\n pathname?: string;\n routeId?: string;\n method?: string;\n type?: \"defer-action\" | \"invalid-body\";\n } = {}\n) {\n let statusText = \"Unknown Server Error\";\n let errorMessage = \"Unknown @remix-run/router error\";\n\n if (status === 400) {\n statusText = \"Bad Request\";\n if (method && pathname && routeId) {\n errorMessage =\n `You made a ${method} request to \"${pathname}\" but ` +\n `did not provide a \\`loader\\` for route \"${routeId}\", ` +\n `so there is no way to handle the request.`;\n } else if (type === \"defer-action\") {\n errorMessage = \"defer() is not supported in actions\";\n } else if (type === \"invalid-body\") {\n errorMessage = \"Unable to encode submission body\";\n }\n } else if (status === 403) {\n statusText = \"Forbidden\";\n errorMessage = `Route \"${routeId}\" does not match URL \"${pathname}\"`;\n } else if (status === 404) {\n statusText = \"Not Found\";\n errorMessage = `No route matches URL \"${pathname}\"`;\n } else if (status === 405) {\n statusText = \"Method Not Allowed\";\n if (method && pathname && routeId) {\n errorMessage =\n `You made a ${method.toUpperCase()} request to \"${pathname}\" but ` +\n `did not provide an \\`action\\` for route \"${routeId}\", ` +\n `so there is no way to handle the request.`;\n } else if (method) {\n errorMessage = `Invalid request method \"${method.toUpperCase()}\"`;\n }\n }\n\n return new ErrorResponseImpl(\n status || 500,\n statusText,\n new Error(errorMessage),\n true\n );\n}\n\n// Find any returned redirect errors, starting from the lowest match\nfunction findRedirect(\n results: DataResult[]\n): { result: RedirectResult; idx: number } | undefined {\n for (let i = results.length - 1; i >= 0; i--) {\n let result = results[i];\n if (isRedirectResult(result)) {\n return { result, idx: i };\n }\n }\n}\n\nfunction stripHashFromPath(path: To) {\n let parsedPath = typeof path === \"string\" ? parsePath(path) : path;\n return createPath({ ...parsedPath, hash: \"\" });\n}\n\nfunction isHashChangeOnly(a: Location, b: Location): boolean {\n if (a.pathname !== b.pathname || a.search !== b.search) {\n return false;\n }\n\n if (a.hash === \"\") {\n // /page -> /page#hash\n return b.hash !== \"\";\n } else if (a.hash === b.hash) {\n // /page#hash -> /page#hash\n return true;\n } else if (b.hash !== \"\") {\n // /page#hash -> /page#other\n return true;\n }\n\n // If the hash is removed the browser will re-perform a request to the server\n // /page#hash -> /page\n return false;\n}\n\nfunction isDeferredResult(result: DataResult): result is DeferredResult {\n return result.type === ResultType.deferred;\n}\n\nfunction isErrorResult(result: DataResult): result is ErrorResult {\n return result.type === ResultType.error;\n}\n\nfunction isRedirectResult(result?: DataResult): result is RedirectResult {\n return (result && result.type) === ResultType.redirect;\n}\n\nexport function isDeferredData(value: any): value is DeferredData {\n let deferred: DeferredData = value;\n return (\n deferred &&\n typeof deferred === \"object\" &&\n typeof deferred.data === \"object\" &&\n typeof deferred.subscribe === \"function\" &&\n typeof deferred.cancel === \"function\" &&\n typeof deferred.resolveData === \"function\"\n );\n}\n\nfunction isResponse(value: any): value is Response {\n return (\n value != null &&\n typeof value.status === \"number\" &&\n typeof value.statusText === \"string\" &&\n typeof value.headers === \"object\" &&\n typeof value.body !== \"undefined\"\n );\n}\n\nfunction isRedirectResponse(result: any): result is Response {\n if (!isResponse(result)) {\n return false;\n }\n\n let status = result.status;\n let location = result.headers.get(\"Location\");\n return status >= 300 && status <= 399 && location != null;\n}\n\nfunction isQueryRouteResponse(obj: any): obj is QueryRouteResponse {\n return (\n obj &&\n isResponse(obj.response) &&\n (obj.type === ResultType.data || obj.type === ResultType.error)\n );\n}\n\nfunction isValidMethod(method: string): method is FormMethod | V7_FormMethod {\n return validRequestMethods.has(method.toLowerCase() as FormMethod);\n}\n\nfunction isMutationMethod(\n method: string\n): method is MutationFormMethod | V7_MutationFormMethod {\n return validMutationMethods.has(method.toLowerCase() as MutationFormMethod);\n}\n\nasync function resolveDeferredResults(\n currentMatches: AgnosticDataRouteMatch[],\n matchesToLoad: (AgnosticDataRouteMatch | null)[],\n results: DataResult[],\n signals: (AbortSignal | null)[],\n isFetcher: boolean,\n currentLoaderData?: RouteData\n) {\n for (let index = 0; index < results.length; index++) {\n let result = results[index];\n let match = matchesToLoad[index];\n // If we don't have a match, then we can have a deferred result to do\n // anything with. This is for revalidating fetchers where the route was\n // removed during HMR\n if (!match) {\n continue;\n }\n\n let currentMatch = currentMatches.find(\n (m) => m.route.id === match!.route.id\n );\n let isRevalidatingLoader =\n currentMatch != null &&\n !isNewRouteInstance(currentMatch, match) &&\n (currentLoaderData && currentLoaderData[match.route.id]) !== undefined;\n\n if (isDeferredResult(result) && (isFetcher || isRevalidatingLoader)) {\n // Note: we do not have to touch activeDeferreds here since we race them\n // against the signal in resolveDeferredData and they'll get aborted\n // there if needed\n let signal = signals[index];\n invariant(\n signal,\n \"Expected an AbortSignal for revalidating fetcher deferred result\"\n );\n await resolveDeferredData(result, signal, isFetcher).then((result) => {\n if (result) {\n results[index] = result || results[index];\n }\n });\n }\n }\n}\n\nasync function resolveDeferredData(\n result: DeferredResult,\n signal: AbortSignal,\n unwrap = false\n): Promise {\n let aborted = await result.deferredData.resolveData(signal);\n if (aborted) {\n return;\n }\n\n if (unwrap) {\n try {\n return {\n type: ResultType.data,\n data: result.deferredData.unwrappedData,\n };\n } catch (e) {\n // Handle any TrackedPromise._error values encountered while unwrapping\n return {\n type: ResultType.error,\n error: e,\n };\n }\n }\n\n return {\n type: ResultType.data,\n data: result.deferredData.data,\n };\n}\n\nfunction hasNakedIndexQuery(search: string): boolean {\n return new URLSearchParams(search).getAll(\"index\").some((v) => v === \"\");\n}\n\nfunction getTargetMatch(\n matches: AgnosticDataRouteMatch[],\n location: Location | string\n) {\n let search =\n typeof location === \"string\" ? parsePath(location).search : location.search;\n if (\n matches[matches.length - 1].route.index &&\n hasNakedIndexQuery(search || \"\")\n ) {\n // Return the leaf index route when index is present\n return matches[matches.length - 1];\n }\n // Otherwise grab the deepest \"path contributing\" match (ignoring index and\n // pathless layout routes)\n let pathMatches = getPathContributingMatches(matches);\n return pathMatches[pathMatches.length - 1];\n}\n\nfunction getSubmissionFromNavigation(\n navigation: Navigation\n): Submission | undefined {\n let { formMethod, formAction, formEncType, text, formData, json } =\n navigation;\n if (!formMethod || !formAction || !formEncType) {\n return;\n }\n\n if (text != null) {\n return {\n formMethod,\n formAction,\n formEncType,\n formData: undefined,\n json: undefined,\n text,\n };\n } else if (formData != null) {\n return {\n formMethod,\n formAction,\n formEncType,\n formData,\n json: undefined,\n text: undefined,\n };\n } else if (json !== undefined) {\n return {\n formMethod,\n formAction,\n formEncType,\n formData: undefined,\n json,\n text: undefined,\n };\n }\n}\n\nfunction getLoadingNavigation(\n location: Location,\n submission?: Submission\n): NavigationStates[\"Loading\"] {\n if (submission) {\n let navigation: NavigationStates[\"Loading\"] = {\n state: \"loading\",\n location,\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n };\n return navigation;\n } else {\n let navigation: NavigationStates[\"Loading\"] = {\n state: \"loading\",\n location,\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n };\n return navigation;\n }\n}\n\nfunction getSubmittingNavigation(\n location: Location,\n submission: Submission\n): NavigationStates[\"Submitting\"] {\n let navigation: NavigationStates[\"Submitting\"] = {\n state: \"submitting\",\n location,\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n };\n return navigation;\n}\n\nfunction getLoadingFetcher(\n submission?: Submission,\n data?: Fetcher[\"data\"]\n): FetcherStates[\"Loading\"] {\n if (submission) {\n let fetcher: FetcherStates[\"Loading\"] = {\n state: \"loading\",\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n data,\n };\n return fetcher;\n } else {\n let fetcher: FetcherStates[\"Loading\"] = {\n state: \"loading\",\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n data,\n };\n return fetcher;\n }\n}\n\nfunction getSubmittingFetcher(\n submission: Submission,\n existingFetcher?: Fetcher\n): FetcherStates[\"Submitting\"] {\n let fetcher: FetcherStates[\"Submitting\"] = {\n state: \"submitting\",\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n data: existingFetcher ? existingFetcher.data : undefined,\n };\n return fetcher;\n}\n\nfunction getDoneFetcher(data: Fetcher[\"data\"]): FetcherStates[\"Idle\"] {\n let fetcher: FetcherStates[\"Idle\"] = {\n state: \"idle\",\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n data,\n };\n return fetcher;\n}\n\nfunction restoreAppliedTransitions(\n _window: Window,\n transitions: Map>\n) {\n try {\n let sessionPositions = _window.sessionStorage.getItem(\n TRANSITIONS_STORAGE_KEY\n );\n if (sessionPositions) {\n let json = JSON.parse(sessionPositions);\n for (let [k, v] of Object.entries(json || {})) {\n if (v && Array.isArray(v)) {\n transitions.set(k, new Set(v || []));\n }\n }\n }\n } catch (e) {\n // no-op, use default empty object\n }\n}\n\nfunction persistAppliedTransitions(\n _window: Window,\n transitions: Map>\n) {\n if (transitions.size > 0) {\n let json: Record = {};\n for (let [k, v] of transitions) {\n json[k] = [...v];\n }\n try {\n _window.sessionStorage.setItem(\n TRANSITIONS_STORAGE_KEY,\n JSON.stringify(json)\n );\n } catch (error) {\n warning(\n false,\n `Failed to save applied view transitions in sessionStorage (${error}).`\n );\n }\n }\n}\n\n//#endregion\n","import * as React from \"react\";\nimport type {\n AgnosticIndexRouteObject,\n AgnosticNonIndexRouteObject,\n AgnosticRouteMatch,\n History,\n LazyRouteFunction,\n Location,\n Action as NavigationType,\n RelativeRoutingType,\n Router,\n StaticHandlerContext,\n To,\n TrackedPromise,\n} from \"@remix-run/router\";\n\n// Create react-specific types from the agnostic types in @remix-run/router to\n// export from react-router\nexport interface IndexRouteObject {\n caseSensitive?: AgnosticIndexRouteObject[\"caseSensitive\"];\n path?: AgnosticIndexRouteObject[\"path\"];\n id?: AgnosticIndexRouteObject[\"id\"];\n loader?: AgnosticIndexRouteObject[\"loader\"];\n action?: AgnosticIndexRouteObject[\"action\"];\n hasErrorBoundary?: AgnosticIndexRouteObject[\"hasErrorBoundary\"];\n shouldRevalidate?: AgnosticIndexRouteObject[\"shouldRevalidate\"];\n handle?: AgnosticIndexRouteObject[\"handle\"];\n index: true;\n children?: undefined;\n element?: React.ReactNode | null;\n errorElement?: React.ReactNode | null;\n Component?: React.ComponentType | null;\n ErrorBoundary?: React.ComponentType | null;\n lazy?: LazyRouteFunction;\n}\n\nexport interface NonIndexRouteObject {\n caseSensitive?: AgnosticNonIndexRouteObject[\"caseSensitive\"];\n path?: AgnosticNonIndexRouteObject[\"path\"];\n id?: AgnosticNonIndexRouteObject[\"id\"];\n loader?: AgnosticNonIndexRouteObject[\"loader\"];\n action?: AgnosticNonIndexRouteObject[\"action\"];\n hasErrorBoundary?: AgnosticNonIndexRouteObject[\"hasErrorBoundary\"];\n shouldRevalidate?: AgnosticNonIndexRouteObject[\"shouldRevalidate\"];\n handle?: AgnosticNonIndexRouteObject[\"handle\"];\n index?: false;\n children?: RouteObject[];\n element?: React.ReactNode | null;\n errorElement?: React.ReactNode | null;\n Component?: React.ComponentType | null;\n ErrorBoundary?: React.ComponentType | null;\n lazy?: LazyRouteFunction;\n}\n\nexport type RouteObject = IndexRouteObject | NonIndexRouteObject;\n\nexport type DataRouteObject = RouteObject & {\n children?: DataRouteObject[];\n id: string;\n};\n\nexport interface RouteMatch<\n ParamKey extends string = string,\n RouteObjectType extends RouteObject = RouteObject\n> extends AgnosticRouteMatch {}\n\nexport interface DataRouteMatch extends RouteMatch {}\n\nexport interface DataRouterContextObject extends NavigationContextObject {\n router: Router;\n staticContext?: StaticHandlerContext;\n}\n\nexport const DataRouterContext =\n React.createContext(null);\nif (__DEV__) {\n DataRouterContext.displayName = \"DataRouter\";\n}\n\nexport const DataRouterStateContext = React.createContext<\n Router[\"state\"] | null\n>(null);\nif (__DEV__) {\n DataRouterStateContext.displayName = \"DataRouterState\";\n}\n\nexport const AwaitContext = React.createContext(null);\nif (__DEV__) {\n AwaitContext.displayName = \"Await\";\n}\n\nexport interface NavigateOptions {\n replace?: boolean;\n state?: any;\n preventScrollReset?: boolean;\n relative?: RelativeRoutingType;\n unstable_viewTransition?: boolean;\n}\n\n/**\n * A Navigator is a \"location changer\"; it's how you get to different locations.\n *\n * Every history instance conforms to the Navigator interface, but the\n * distinction is useful primarily when it comes to the low-level `` API\n * where both the location and a navigator must be provided separately in order\n * to avoid \"tearing\" that may occur in a suspense-enabled app if the action\n * and/or location were to be read directly from the history instance.\n */\nexport interface Navigator {\n createHref: History[\"createHref\"];\n // Optional for backwards-compat with Router/HistoryRouter usage (edge case)\n encodeLocation?: History[\"encodeLocation\"];\n go: History[\"go\"];\n push(to: To, state?: any, opts?: NavigateOptions): void;\n replace(to: To, state?: any, opts?: NavigateOptions): void;\n}\n\ninterface NavigationContextObject {\n basename: string;\n navigator: Navigator;\n static: boolean;\n}\n\nexport const NavigationContext = React.createContext(\n null!\n);\n\nif (__DEV__) {\n NavigationContext.displayName = \"Navigation\";\n}\n\ninterface LocationContextObject {\n location: Location;\n navigationType: NavigationType;\n}\n\nexport const LocationContext = React.createContext(\n null!\n);\n\nif (__DEV__) {\n LocationContext.displayName = \"Location\";\n}\n\nexport interface RouteContextObject {\n outlet: React.ReactElement | null;\n matches: RouteMatch[];\n isDataRoute: boolean;\n}\n\nexport const RouteContext = React.createContext({\n outlet: null,\n matches: [],\n isDataRoute: false,\n});\n\nif (__DEV__) {\n RouteContext.displayName = \"Route\";\n}\n\nexport const RouteErrorContext = React.createContext(null);\n\nif (__DEV__) {\n RouteErrorContext.displayName = \"RouteError\";\n}\n","import * as React from \"react\";\nimport type {\n Blocker,\n BlockerFunction,\n Location,\n ParamParseKey,\n Params,\n Path,\n PathMatch,\n PathPattern,\n RelativeRoutingType,\n Router as RemixRouter,\n RevalidationState,\n To,\n UIMatch,\n} from \"@remix-run/router\";\nimport {\n IDLE_BLOCKER,\n Action as NavigationType,\n UNSAFE_convertRouteMatchToUiMatch as convertRouteMatchToUiMatch,\n UNSAFE_getPathContributingMatches as getPathContributingMatches,\n UNSAFE_invariant as invariant,\n isRouteErrorResponse,\n joinPaths,\n matchPath,\n matchRoutes,\n parsePath,\n resolveTo,\n stripBasename,\n UNSAFE_warning as warning,\n} from \"@remix-run/router\";\n\nimport type {\n DataRouteMatch,\n NavigateOptions,\n RouteContextObject,\n RouteMatch,\n RouteObject,\n} from \"./context\";\nimport {\n AwaitContext,\n DataRouterContext,\n DataRouterStateContext,\n LocationContext,\n NavigationContext,\n RouteContext,\n RouteErrorContext,\n} from \"./context\";\n\n/**\n * Returns the full href for the given \"to\" value. This is useful for building\n * custom links that are also accessible and preserve right-click behavior.\n *\n * @see https://reactrouter.com/hooks/use-href\n */\nexport function useHref(\n to: To,\n { relative }: { relative?: RelativeRoutingType } = {}\n): string {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useHref() may be used only in the context of a component.`\n );\n\n let { basename, navigator } = React.useContext(NavigationContext);\n let { hash, pathname, search } = useResolvedPath(to, { relative });\n\n let joinedPathname = pathname;\n\n // If we're operating within a basename, prepend it to the pathname prior\n // to creating the href. If this is a root navigation, then just use the raw\n // basename which allows the basename to have full control over the presence\n // of a trailing slash on root links\n if (basename !== \"/\") {\n joinedPathname =\n pathname === \"/\" ? basename : joinPaths([basename, pathname]);\n }\n\n return navigator.createHref({ pathname: joinedPathname, search, hash });\n}\n\n/**\n * Returns true if this component is a descendant of a ``.\n *\n * @see https://reactrouter.com/hooks/use-in-router-context\n */\nexport function useInRouterContext(): boolean {\n return React.useContext(LocationContext) != null;\n}\n\n/**\n * Returns the current location object, which represents the current URL in web\n * browsers.\n *\n * Note: If you're using this it may mean you're doing some of your own\n * \"routing\" in your app, and we'd like to know what your use case is. We may\n * be able to provide something higher-level to better suit your needs.\n *\n * @see https://reactrouter.com/hooks/use-location\n */\nexport function useLocation(): Location {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useLocation() may be used only in the context of a component.`\n );\n\n return React.useContext(LocationContext).location;\n}\n\n/**\n * Returns the current navigation action which describes how the router came to\n * the current location, either by a pop, push, or replace on the history stack.\n *\n * @see https://reactrouter.com/hooks/use-navigation-type\n */\nexport function useNavigationType(): NavigationType {\n return React.useContext(LocationContext).navigationType;\n}\n\n/**\n * Returns a PathMatch object if the given pattern matches the current URL.\n * This is useful for components that need to know \"active\" state, e.g.\n * ``.\n *\n * @see https://reactrouter.com/hooks/use-match\n */\nexport function useMatch<\n ParamKey extends ParamParseKey,\n Path extends string\n>(pattern: PathPattern | Path): PathMatch | null {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useMatch() may be used only in the context of a component.`\n );\n\n let { pathname } = useLocation();\n return React.useMemo(\n () => matchPath(pattern, pathname),\n [pathname, pattern]\n );\n}\n\n/**\n * The interface for the navigate() function returned from useNavigate().\n */\nexport interface NavigateFunction {\n (to: To, options?: NavigateOptions): void;\n (delta: number): void;\n}\n\nconst navigateEffectWarning =\n `You should call navigate() in a React.useEffect(), not when ` +\n `your component is first rendered.`;\n\n// Mute warnings for calls to useNavigate in SSR environments\nfunction useIsomorphicLayoutEffect(\n cb: Parameters[0]\n) {\n let isStatic = React.useContext(NavigationContext).static;\n if (!isStatic) {\n // We should be able to get rid of this once react 18.3 is released\n // See: https://github.com/facebook/react/pull/26395\n // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useLayoutEffect(cb);\n }\n}\n\n/**\n * Returns an imperative method for changing the location. Used by ``s, but\n * may also be used by other elements to change the location.\n *\n * @see https://reactrouter.com/hooks/use-navigate\n */\nexport function useNavigate(): NavigateFunction {\n let { isDataRoute } = React.useContext(RouteContext);\n // Conditional usage is OK here because the usage of a data router is static\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return isDataRoute ? useNavigateStable() : useNavigateUnstable();\n}\n\nfunction useNavigateUnstable(): NavigateFunction {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useNavigate() may be used only in the context of a component.`\n );\n\n let dataRouterContext = React.useContext(DataRouterContext);\n let { basename, navigator } = React.useContext(NavigationContext);\n let { matches } = React.useContext(RouteContext);\n let { pathname: locationPathname } = useLocation();\n\n let routePathnamesJson = JSON.stringify(\n getPathContributingMatches(matches).map((match) => match.pathnameBase)\n );\n\n let activeRef = React.useRef(false);\n useIsomorphicLayoutEffect(() => {\n activeRef.current = true;\n });\n\n let navigate: NavigateFunction = React.useCallback(\n (to: To | number, options: NavigateOptions = {}) => {\n warning(activeRef.current, navigateEffectWarning);\n\n // Short circuit here since if this happens on first render the navigate\n // is useless because we haven't wired up our history listener yet\n if (!activeRef.current) return;\n\n if (typeof to === \"number\") {\n navigator.go(to);\n return;\n }\n\n let path = resolveTo(\n to,\n JSON.parse(routePathnamesJson),\n locationPathname,\n options.relative === \"path\"\n );\n\n // If we're operating within a basename, prepend it to the pathname prior\n // to handing off to history (but only if we're not in a data router,\n // otherwise it'll prepend the basename inside of the router).\n // If this is a root navigation, then we navigate to the raw basename\n // which allows the basename to have full control over the presence of a\n // trailing slash on root links\n if (dataRouterContext == null && basename !== \"/\") {\n path.pathname =\n path.pathname === \"/\"\n ? basename\n : joinPaths([basename, path.pathname]);\n }\n\n (!!options.replace ? navigator.replace : navigator.push)(\n path,\n options.state,\n options\n );\n },\n [\n basename,\n navigator,\n routePathnamesJson,\n locationPathname,\n dataRouterContext,\n ]\n );\n\n return navigate;\n}\n\nconst OutletContext = React.createContext(null);\n\n/**\n * Returns the context (if provided) for the child route at this level of the route\n * hierarchy.\n * @see https://reactrouter.com/hooks/use-outlet-context\n */\nexport function useOutletContext(): Context {\n return React.useContext(OutletContext) as Context;\n}\n\n/**\n * Returns the element for the child route at this level of the route\n * hierarchy. Used internally by `` to render child routes.\n *\n * @see https://reactrouter.com/hooks/use-outlet\n */\nexport function useOutlet(context?: unknown): React.ReactElement | null {\n let outlet = React.useContext(RouteContext).outlet;\n if (outlet) {\n return (\n {outlet}\n );\n }\n return outlet;\n}\n\n/**\n * Returns an object of key/value pairs of the dynamic params from the current\n * URL that were matched by the route path.\n *\n * @see https://reactrouter.com/hooks/use-params\n */\nexport function useParams<\n ParamsOrKey extends string | Record = string\n>(): Readonly<\n [ParamsOrKey] extends [string] ? Params : Partial\n> {\n let { matches } = React.useContext(RouteContext);\n let routeMatch = matches[matches.length - 1];\n return routeMatch ? (routeMatch.params as any) : {};\n}\n\n/**\n * Resolves the pathname of the given `to` value against the current location.\n *\n * @see https://reactrouter.com/hooks/use-resolved-path\n */\nexport function useResolvedPath(\n to: To,\n { relative }: { relative?: RelativeRoutingType } = {}\n): Path {\n let { matches } = React.useContext(RouteContext);\n let { pathname: locationPathname } = useLocation();\n\n let routePathnamesJson = JSON.stringify(\n getPathContributingMatches(matches).map((match) => match.pathnameBase)\n );\n\n return React.useMemo(\n () =>\n resolveTo(\n to,\n JSON.parse(routePathnamesJson),\n locationPathname,\n relative === \"path\"\n ),\n [to, routePathnamesJson, locationPathname, relative]\n );\n}\n\n/**\n * Returns the element of the route that matched the current location, prepared\n * with the correct context to render the remainder of the route tree. Route\n * elements in the tree must render an `` to render their child route's\n * element.\n *\n * @see https://reactrouter.com/hooks/use-routes\n */\nexport function useRoutes(\n routes: RouteObject[],\n locationArg?: Partial | string\n): React.ReactElement | null {\n return useRoutesImpl(routes, locationArg);\n}\n\n// Internal implementation with accept optional param for RouterProvider usage\nexport function useRoutesImpl(\n routes: RouteObject[],\n locationArg?: Partial | string,\n dataRouterState?: RemixRouter[\"state\"]\n): React.ReactElement | null {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useRoutes() may be used only in the context of a component.`\n );\n\n let { navigator } = React.useContext(NavigationContext);\n let { matches: parentMatches } = React.useContext(RouteContext);\n let routeMatch = parentMatches[parentMatches.length - 1];\n let parentParams = routeMatch ? routeMatch.params : {};\n let parentPathname = routeMatch ? routeMatch.pathname : \"/\";\n let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : \"/\";\n let parentRoute = routeMatch && routeMatch.route;\n\n if (__DEV__) {\n // You won't get a warning about 2 different under a \n // without a trailing *, but this is a best-effort warning anyway since we\n // cannot even give the warning unless they land at the parent route.\n //\n // Example:\n //\n // \n // {/* This route path MUST end with /* because otherwise\n // it will never match /blog/post/123 */}\n // } />\n // } />\n // \n //\n // function Blog() {\n // return (\n // \n // } />\n // \n // );\n // }\n let parentPath = (parentRoute && parentRoute.path) || \"\";\n warningOnce(\n parentPathname,\n !parentRoute || parentPath.endsWith(\"*\"),\n `You rendered descendant (or called \\`useRoutes()\\`) at ` +\n `\"${parentPathname}\" (under ) but the ` +\n `parent route path has no trailing \"*\". This means if you navigate ` +\n `deeper, the parent won't match anymore and therefore the child ` +\n `routes will never render.\\n\\n` +\n `Please change the parent to .`\n );\n }\n\n let locationFromContext = useLocation();\n\n let location;\n if (locationArg) {\n let parsedLocationArg =\n typeof locationArg === \"string\" ? parsePath(locationArg) : locationArg;\n\n invariant(\n parentPathnameBase === \"/\" ||\n parsedLocationArg.pathname?.startsWith(parentPathnameBase),\n `When overriding the location using \\`\\` or \\`useRoutes(routes, location)\\`, ` +\n `the location pathname must begin with the portion of the URL pathname that was ` +\n `matched by all parent routes. The current pathname base is \"${parentPathnameBase}\" ` +\n `but pathname \"${parsedLocationArg.pathname}\" was given in the \\`location\\` prop.`\n );\n\n location = parsedLocationArg;\n } else {\n location = locationFromContext;\n }\n\n let pathname = location.pathname || \"/\";\n let remainingPathname =\n parentPathnameBase === \"/\"\n ? pathname\n : pathname.slice(parentPathnameBase.length) || \"/\";\n\n let matches = matchRoutes(routes, { pathname: remainingPathname });\n\n if (__DEV__) {\n warning(\n parentRoute || matches != null,\n `No routes matched location \"${location.pathname}${location.search}${location.hash}\" `\n );\n\n warning(\n matches == null ||\n matches[matches.length - 1].route.element !== undefined ||\n matches[matches.length - 1].route.Component !== undefined,\n `Matched leaf route at location \"${location.pathname}${location.search}${location.hash}\" ` +\n `does not have an element or Component. This means it will render an with a ` +\n `null value by default resulting in an \"empty\" page.`\n );\n }\n\n let renderedMatches = _renderMatches(\n matches &&\n matches.map((match) =>\n Object.assign({}, match, {\n params: Object.assign({}, parentParams, match.params),\n pathname: joinPaths([\n parentPathnameBase,\n // Re-encode pathnames that were decoded inside matchRoutes\n navigator.encodeLocation\n ? navigator.encodeLocation(match.pathname).pathname\n : match.pathname,\n ]),\n pathnameBase:\n match.pathnameBase === \"/\"\n ? parentPathnameBase\n : joinPaths([\n parentPathnameBase,\n // Re-encode pathnames that were decoded inside matchRoutes\n navigator.encodeLocation\n ? navigator.encodeLocation(match.pathnameBase).pathname\n : match.pathnameBase,\n ]),\n })\n ),\n parentMatches,\n dataRouterState\n );\n\n // When a user passes in a `locationArg`, the associated routes need to\n // be wrapped in a new `LocationContext.Provider` in order for `useLocation`\n // to use the scoped location instead of the global location.\n if (locationArg && renderedMatches) {\n return (\n \n {renderedMatches}\n \n );\n }\n\n return renderedMatches;\n}\n\nfunction DefaultErrorComponent() {\n let error = useRouteError();\n let message = isRouteErrorResponse(error)\n ? `${error.status} ${error.statusText}`\n : error instanceof Error\n ? error.message\n : JSON.stringify(error);\n let stack = error instanceof Error ? error.stack : null;\n let lightgrey = \"rgba(200,200,200, 0.5)\";\n let preStyles = { padding: \"0.5rem\", backgroundColor: lightgrey };\n let codeStyles = { padding: \"2px 4px\", backgroundColor: lightgrey };\n\n let devInfo = null;\n if (__DEV__) {\n console.error(\n \"Error handled by React Router default ErrorBoundary:\",\n error\n );\n\n devInfo = (\n <>\n

💿 Hey developer 👋

\n

\n You can provide a way better UX than this when your app throws errors\n by providing your own ErrorBoundary or{\" \"}\n errorElement prop on your route.\n

\n \n );\n }\n\n return (\n <>\n

Unexpected Application Error!

\n

{message}

\n {stack ?
{stack}
: null}\n {devInfo}\n \n );\n}\n\nconst defaultErrorElement = ;\n\ntype RenderErrorBoundaryProps = React.PropsWithChildren<{\n location: Location;\n revalidation: RevalidationState;\n error: any;\n component: React.ReactNode;\n routeContext: RouteContextObject;\n}>;\n\ntype RenderErrorBoundaryState = {\n location: Location;\n revalidation: RevalidationState;\n error: any;\n};\n\nexport class RenderErrorBoundary extends React.Component<\n RenderErrorBoundaryProps,\n RenderErrorBoundaryState\n> {\n constructor(props: RenderErrorBoundaryProps) {\n super(props);\n this.state = {\n location: props.location,\n revalidation: props.revalidation,\n error: props.error,\n };\n }\n\n static getDerivedStateFromError(error: any) {\n return { error: error };\n }\n\n static getDerivedStateFromProps(\n props: RenderErrorBoundaryProps,\n state: RenderErrorBoundaryState\n ) {\n // When we get into an error state, the user will likely click \"back\" to the\n // previous page that didn't have an error. Because this wraps the entire\n // application, that will have no effect--the error page continues to display.\n // This gives us a mechanism to recover from the error when the location changes.\n //\n // Whether we're in an error state or not, we update the location in state\n // so that when we are in an error state, it gets reset when a new location\n // comes in and the user recovers from the error.\n if (\n state.location !== props.location ||\n (state.revalidation !== \"idle\" && props.revalidation === \"idle\")\n ) {\n return {\n error: props.error,\n location: props.location,\n revalidation: props.revalidation,\n };\n }\n\n // If we're not changing locations, preserve the location but still surface\n // any new errors that may come through. We retain the existing error, we do\n // this because the error provided from the app state may be cleared without\n // the location changing.\n return {\n error: props.error || state.error,\n location: state.location,\n revalidation: props.revalidation || state.revalidation,\n };\n }\n\n componentDidCatch(error: any, errorInfo: any) {\n console.error(\n \"React Router caught the following error during render\",\n error,\n errorInfo\n );\n }\n\n render() {\n return this.state.error ? (\n \n \n \n ) : (\n this.props.children\n );\n }\n}\n\ninterface RenderedRouteProps {\n routeContext: RouteContextObject;\n match: RouteMatch;\n children: React.ReactNode | null;\n}\n\nfunction RenderedRoute({ routeContext, match, children }: RenderedRouteProps) {\n let dataRouterContext = React.useContext(DataRouterContext);\n\n // Track how deep we got in our render pass to emulate SSR componentDidCatch\n // in a DataStaticRouter\n if (\n dataRouterContext &&\n dataRouterContext.static &&\n dataRouterContext.staticContext &&\n (match.route.errorElement || match.route.ErrorBoundary)\n ) {\n dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;\n }\n\n return (\n \n {children}\n \n );\n}\n\nexport function _renderMatches(\n matches: RouteMatch[] | null,\n parentMatches: RouteMatch[] = [],\n dataRouterState: RemixRouter[\"state\"] | null = null\n): React.ReactElement | null {\n if (matches == null) {\n if (dataRouterState?.errors) {\n // Don't bail if we have data router errors so we can render them in the\n // boundary. Use the pre-matched (or shimmed) matches\n matches = dataRouterState.matches as DataRouteMatch[];\n } else {\n return null;\n }\n }\n\n let renderedMatches = matches;\n\n // If we have data errors, trim matches to the highest error boundary\n let errors = dataRouterState?.errors;\n if (errors != null) {\n let errorIndex = renderedMatches.findIndex(\n (m) => m.route.id && errors?.[m.route.id]\n );\n invariant(\n errorIndex >= 0,\n `Could not find a matching route for errors on route IDs: ${Object.keys(\n errors\n ).join(\",\")}`\n );\n renderedMatches = renderedMatches.slice(\n 0,\n Math.min(renderedMatches.length, errorIndex + 1)\n );\n }\n\n return renderedMatches.reduceRight((outlet, match, index) => {\n let error = match.route.id ? errors?.[match.route.id] : null;\n // Only data routers handle errors\n let errorElement: React.ReactNode | null = null;\n if (dataRouterState) {\n errorElement = match.route.errorElement || defaultErrorElement;\n }\n let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));\n let getChildren = () => {\n let children: React.ReactNode;\n if (error) {\n children = errorElement;\n } else if (match.route.Component) {\n // Note: This is a de-optimized path since React won't re-use the\n // ReactElement since it's identity changes with each new\n // React.createElement call. We keep this so folks can use\n // `` in `` but generally `Component`\n // usage is only advised in `RouterProvider` when we can convert it to\n // `element` ahead of time.\n children = ;\n } else if (match.route.element) {\n children = match.route.element;\n } else {\n children = outlet;\n }\n return (\n \n );\n };\n // Only wrap in an error boundary within data router usages when we have an\n // ErrorBoundary/errorElement on this route. Otherwise let it bubble up to\n // an ancestor ErrorBoundary/errorElement\n return dataRouterState &&\n (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? (\n \n ) : (\n getChildren()\n );\n }, null as React.ReactElement | null);\n}\n\nenum DataRouterHook {\n UseBlocker = \"useBlocker\",\n UseRevalidator = \"useRevalidator\",\n UseNavigateStable = \"useNavigate\",\n}\n\nenum DataRouterStateHook {\n UseBlocker = \"useBlocker\",\n UseLoaderData = \"useLoaderData\",\n UseActionData = \"useActionData\",\n UseRouteError = \"useRouteError\",\n UseNavigation = \"useNavigation\",\n UseRouteLoaderData = \"useRouteLoaderData\",\n UseMatches = \"useMatches\",\n UseRevalidator = \"useRevalidator\",\n UseNavigateStable = \"useNavigate\",\n UseRouteId = \"useRouteId\",\n}\n\nfunction getDataRouterConsoleError(\n hookName: DataRouterHook | DataRouterStateHook\n) {\n return `${hookName} must be used within a data router. See https://reactrouter.com/routers/picking-a-router.`;\n}\n\nfunction useDataRouterContext(hookName: DataRouterHook) {\n let ctx = React.useContext(DataRouterContext);\n invariant(ctx, getDataRouterConsoleError(hookName));\n return ctx;\n}\n\nfunction useDataRouterState(hookName: DataRouterStateHook) {\n let state = React.useContext(DataRouterStateContext);\n invariant(state, getDataRouterConsoleError(hookName));\n return state;\n}\n\nfunction useRouteContext(hookName: DataRouterStateHook) {\n let route = React.useContext(RouteContext);\n invariant(route, getDataRouterConsoleError(hookName));\n return route;\n}\n\n// Internal version with hookName-aware debugging\nfunction useCurrentRouteId(hookName: DataRouterStateHook) {\n let route = useRouteContext(hookName);\n let thisRoute = route.matches[route.matches.length - 1];\n invariant(\n thisRoute.route.id,\n `${hookName} can only be used on routes that contain a unique \"id\"`\n );\n return thisRoute.route.id;\n}\n\n/**\n * Returns the ID for the nearest contextual route\n */\nexport function useRouteId() {\n return useCurrentRouteId(DataRouterStateHook.UseRouteId);\n}\n\n/**\n * Returns the current navigation, defaulting to an \"idle\" navigation when\n * no navigation is in progress\n */\nexport function useNavigation() {\n let state = useDataRouterState(DataRouterStateHook.UseNavigation);\n return state.navigation;\n}\n\n/**\n * Returns a revalidate function for manually triggering revalidation, as well\n * as the current state of any manual revalidations\n */\nexport function useRevalidator() {\n let dataRouterContext = useDataRouterContext(DataRouterHook.UseRevalidator);\n let state = useDataRouterState(DataRouterStateHook.UseRevalidator);\n return React.useMemo(\n () => ({\n revalidate: dataRouterContext.router.revalidate,\n state: state.revalidation,\n }),\n [dataRouterContext.router.revalidate, state.revalidation]\n );\n}\n\n/**\n * Returns the active route matches, useful for accessing loaderData for\n * parent/child routes or the route \"handle\" property\n */\nexport function useMatches(): UIMatch[] {\n let { matches, loaderData } = useDataRouterState(\n DataRouterStateHook.UseMatches\n );\n return React.useMemo(\n () => matches.map((m) => convertRouteMatchToUiMatch(m, loaderData)),\n [matches, loaderData]\n );\n}\n\n/**\n * Returns the loader data for the nearest ancestor Route loader\n */\nexport function useLoaderData(): unknown {\n let state = useDataRouterState(DataRouterStateHook.UseLoaderData);\n let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);\n\n if (state.errors && state.errors[routeId] != null) {\n console.error(\n `You cannot \\`useLoaderData\\` in an errorElement (routeId: ${routeId})`\n );\n return undefined;\n }\n return state.loaderData[routeId];\n}\n\n/**\n * Returns the loaderData for the given routeId\n */\nexport function useRouteLoaderData(routeId: string): unknown {\n let state = useDataRouterState(DataRouterStateHook.UseRouteLoaderData);\n return state.loaderData[routeId];\n}\n\n/**\n * Returns the action data for the nearest ancestor Route action\n */\nexport function useActionData(): unknown {\n let state = useDataRouterState(DataRouterStateHook.UseActionData);\n\n let route = React.useContext(RouteContext);\n invariant(route, `useActionData must be used inside a RouteContext`);\n\n return Object.values(state?.actionData || {})[0];\n}\n\n/**\n * Returns the nearest ancestor Route error, which could be a loader/action\n * error or a render error. This is intended to be called from your\n * ErrorBoundary/errorElement to display a proper error message.\n */\nexport function useRouteError(): unknown {\n let error = React.useContext(RouteErrorContext);\n let state = useDataRouterState(DataRouterStateHook.UseRouteError);\n let routeId = useCurrentRouteId(DataRouterStateHook.UseRouteError);\n\n // If this was a render error, we put it in a RouteError context inside\n // of RenderErrorBoundary\n if (error) {\n return error;\n }\n\n // Otherwise look for errors from our data router state\n return state.errors?.[routeId];\n}\n\n/**\n * Returns the happy-path data from the nearest ancestor `` value\n */\nexport function useAsyncValue(): unknown {\n let value = React.useContext(AwaitContext);\n return value?._data;\n}\n\n/**\n * Returns the error from the nearest ancestor `` value\n */\nexport function useAsyncError(): unknown {\n let value = React.useContext(AwaitContext);\n return value?._error;\n}\n\nlet blockerId = 0;\n\n/**\n * Allow the application to block navigations within the SPA and present the\n * user a confirmation dialog to confirm the navigation. Mostly used to avoid\n * using half-filled form data. This does not handle hard-reloads or\n * cross-origin navigations.\n */\nexport function useBlocker(shouldBlock: boolean | BlockerFunction): Blocker {\n let { router, basename } = useDataRouterContext(DataRouterHook.UseBlocker);\n let state = useDataRouterState(DataRouterStateHook.UseBlocker);\n\n let [blockerKey, setBlockerKey] = React.useState(\"\");\n let blockerFunction = React.useCallback(\n (arg) => {\n if (typeof shouldBlock !== \"function\") {\n return !!shouldBlock;\n }\n if (basename === \"/\") {\n return shouldBlock(arg);\n }\n\n // If they provided us a function and we've got an active basename, strip\n // it from the locations we expose to the user to match the behavior of\n // useLocation\n let { currentLocation, nextLocation, historyAction } = arg;\n return shouldBlock({\n currentLocation: {\n ...currentLocation,\n pathname:\n stripBasename(currentLocation.pathname, basename) ||\n currentLocation.pathname,\n },\n nextLocation: {\n ...nextLocation,\n pathname:\n stripBasename(nextLocation.pathname, basename) ||\n nextLocation.pathname,\n },\n historyAction,\n });\n },\n [basename, shouldBlock]\n );\n\n // This effect is in charge of blocker key assignment and deletion (which is\n // tightly coupled to the key)\n React.useEffect(() => {\n let key = String(++blockerId);\n setBlockerKey(key);\n return () => router.deleteBlocker(key);\n }, [router]);\n\n // This effect handles assigning the blockerFunction. This is to handle\n // unstable blocker function identities, and happens only after the prior\n // effect so we don't get an orphaned blockerFunction in the router with a\n // key of \"\". Until then we just have the IDLE_BLOCKER.\n React.useEffect(() => {\n if (blockerKey !== \"\") {\n router.getBlocker(blockerKey, blockerFunction);\n }\n }, [router, blockerKey, blockerFunction]);\n\n // Prefer the blocker from `state` not `router.state` since DataRouterContext\n // is memoized so this ensures we update on blocker state updates\n return blockerKey && state.blockers.has(blockerKey)\n ? state.blockers.get(blockerKey)!\n : IDLE_BLOCKER;\n}\n\n/**\n * Stable version of useNavigate that is used when we are in the context of\n * a RouterProvider.\n */\nfunction useNavigateStable(): NavigateFunction {\n let { router } = useDataRouterContext(DataRouterHook.UseNavigateStable);\n let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);\n\n let activeRef = React.useRef(false);\n useIsomorphicLayoutEffect(() => {\n activeRef.current = true;\n });\n\n let navigate: NavigateFunction = React.useCallback(\n (to: To | number, options: NavigateOptions = {}) => {\n warning(activeRef.current, navigateEffectWarning);\n\n // Short circuit here since if this happens on first render the navigate\n // is useless because we haven't wired up our router subscriber yet\n if (!activeRef.current) return;\n\n if (typeof to === \"number\") {\n router.navigate(to);\n } else {\n router.navigate(to, { fromRouteId: id, ...options });\n }\n },\n [router, id]\n );\n\n return navigate;\n}\n\nconst alreadyWarned: Record = {};\n\nfunction warningOnce(key: string, cond: boolean, message: string) {\n if (!cond && !alreadyWarned[key]) {\n alreadyWarned[key] = true;\n warning(false, message);\n }\n}\n","import type {\n InitialEntry,\n LazyRouteFunction,\n Location,\n MemoryHistory,\n RelativeRoutingType,\n Router as RemixRouter,\n RouterState,\n RouterSubscriber,\n To,\n TrackedPromise,\n} from \"@remix-run/router\";\nimport {\n AbortedDeferredError,\n Action as NavigationType,\n createMemoryHistory,\n UNSAFE_getPathContributingMatches as getPathContributingMatches,\n UNSAFE_invariant as invariant,\n parsePath,\n resolveTo,\n stripBasename,\n UNSAFE_warning as warning,\n} from \"@remix-run/router\";\nimport * as React from \"react\";\n\nimport type {\n DataRouteObject,\n IndexRouteObject,\n Navigator,\n NonIndexRouteObject,\n RouteMatch,\n RouteObject,\n} from \"./context\";\nimport {\n AwaitContext,\n DataRouterContext,\n DataRouterStateContext,\n LocationContext,\n NavigationContext,\n RouteContext,\n} from \"./context\";\nimport {\n _renderMatches,\n useAsyncValue,\n useInRouterContext,\n useLocation,\n useNavigate,\n useOutlet,\n useRoutes,\n useRoutesImpl,\n} from \"./hooks\";\n\nexport interface FutureConfig {\n v7_startTransition: boolean;\n}\n\nexport interface RouterProviderProps {\n fallbackElement?: React.ReactNode;\n router: RemixRouter;\n future?: Partial;\n}\n\n/**\n Webpack + React 17 fails to compile on any of the following because webpack\n complains that `startTransition` doesn't exist in `React`:\n * import { startTransition } from \"react\"\n * import * as React from from \"react\";\n \"startTransition\" in React ? React.startTransition(() => setState()) : setState()\n * import * as React from from \"react\";\n \"startTransition\" in React ? React[\"startTransition\"](() => setState()) : setState()\n\n Moving it to a constant such as the following solves the Webpack/React 17 issue:\n * import * as React from from \"react\";\n const START_TRANSITION = \"startTransition\";\n START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState()\n\n However, that introduces webpack/terser minification issues in production builds\n in React 18 where minification/obfuscation ends up removing the call of\n React.startTransition entirely from the first half of the ternary. Grabbing\n this exported reference once up front resolves that issue.\n\n See https://github.com/remix-run/react-router/issues/10579\n*/\nconst START_TRANSITION = \"startTransition\";\nconst startTransitionImpl = React[START_TRANSITION];\n\n/**\n * Given a Remix Router instance, render the appropriate UI\n */\nexport function RouterProvider({\n fallbackElement,\n router,\n future,\n}: RouterProviderProps): React.ReactElement {\n let [state, setStateImpl] = React.useState(router.state);\n let { v7_startTransition } = future || {};\n\n let setState = React.useCallback(\n (newState: RouterState) => {\n if (v7_startTransition && startTransitionImpl) {\n startTransitionImpl(() => setStateImpl(newState));\n } else {\n setStateImpl(newState);\n }\n },\n [setStateImpl, v7_startTransition]\n );\n\n // Need to use a layout effect here so we are subscribed early enough to\n // pick up on any render-driven redirects/navigations (useEffect/)\n React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);\n\n let navigator = React.useMemo((): Navigator => {\n return {\n createHref: router.createHref,\n encodeLocation: router.encodeLocation,\n go: (n) => router.navigate(n),\n push: (to, state, opts) =>\n router.navigate(to, {\n state,\n preventScrollReset: opts?.preventScrollReset,\n }),\n replace: (to, state, opts) =>\n router.navigate(to, {\n replace: true,\n state,\n preventScrollReset: opts?.preventScrollReset,\n }),\n };\n }, [router]);\n\n let basename = router.basename || \"/\";\n\n let dataRouterContext = React.useMemo(\n () => ({\n router,\n navigator,\n static: false,\n basename,\n }),\n [router, navigator, basename]\n );\n\n // The fragment and {null} here are important! We need them to keep React 18's\n // useId happy when we are server-rendering since we may have a
\ No newline at end of file diff --git a/my-app/build/manifest.json b/my-app/build/manifest.json deleted file mode 100644 index 77aec56..0000000 --- a/my-app/build/manifest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "short_name": "Sunny Braille", - "name": "Online Braille Transcription Service, Sunny Braille", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/my-app/build/robots.txt b/my-app/build/robots.txt deleted file mode 100644 index e9e57dc..0000000 --- a/my-app/build/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/my-app/build/static/css/main.d5c25553.css b/my-app/build/static/css/main.d5c25553.css deleted file mode 100644 index 3a8b6f4..0000000 --- a/my-app/build/static/css/main.d5c25553.css +++ /dev/null @@ -1,4 +0,0 @@ -/* -! tailwindcss v3.3.5 | MIT License | https://tailwindcss.com -*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.link-underline{display:inline-block;position:relative}.link-underline:after{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity));bottom:.125rem;content:"";height:.125rem;left:50%;position:absolute;transition-duration:.3s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);width:0}.link-underline:hover:after{left:0;width:100%}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.bottom-0{bottom:0}.bottom-\[-100px\]{bottom:-100px}.bottom-\[33px\]{bottom:33px}.left-0{left:0}.left-\[11\.83px\]{left:11.83px}.left-\[126\.53px\]{left:126.53px}.left-\[13\.14px\]{left:13.14px}.left-\[150px\]{left:150px}.left-\[18\.72px\]{left:18.72px}.left-\[31\.21px\]{left:31.21px}.left-\[33\.18px\]{left:33.18px}.left-\[38\.11px\]{left:38.11px}.left-\[40\.08px\]{left:40.08px}.left-\[45px\]{left:45px}.left-\[50\.59px\]{left:50.59px}.left-\[51px\]{left:51px}.left-\[53\.22px\]{left:53.22px}.left-\[57\.49px\]{left:57.49px}.left-\[62px\]{left:62px}.left-\[630px\]{left:630px}.left-\[69\.97px\]{left:69.97px}.left-\[76\.87px\]{left:76.87px}.left-\[89\.35px\]{left:89.35px}.left-\[96\.25px\]{left:96.25px}.right-10{right:2.5rem}.right-\[-180px\]{right:-180px}.top-0{top:0}.top-\[13\.80px\]{top:13.8px}.top-\[150px\]{top:150px}.top-\[200px\]{top:200px}.top-\[22px\]{top:22px}.top-\[24px\]{top:24px}.top-\[290px\]{top:290px}.top-\[350px\]{top:350px}.top-\[6\.90px\]{top:6.9px}.top-\[80px\]{top:80px}.z-0{z-index:0}.z-10{z-index:10}.m-auto{margin:auto}.mx-auto{margin-left:auto;margin-right:auto}.my-\[180px\]{margin-bottom:180px;margin-top:180px}.my-\[20px\]{margin-bottom:20px;margin-top:20px}.my-\[30px\]{margin-bottom:30px;margin-top:30px}.my-\[40px\]{margin-bottom:40px;margin-top:40px}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.mr-4{margin-right:1rem}.mr-auto{margin-right:auto}.mt-4{margin-top:1rem}.flex{display:flex}.inline-flex{display:inline-flex}.hidden{display:none}.h-10{height:2.5rem}.h-6{height:1.5rem}.h-\[130px\]{height:130px}.h-\[19\.05px\]{height:19.05px}.h-\[300px\]{height:300px}.h-\[36px\]{height:36px}.h-\[38px\]{height:38px}.h-\[40px\]{height:40px}.h-\[450px\]{height:450px}.h-\[5\.26px\]{height:5.26px}.h-\[50px\]{height:50px}.h-\[52px\]{height:52px}.h-\[650px\]{height:650px}.h-\[72px\]{height:72px}.h-\[75px\]{height:75px}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[300px\]{max-height:300px}.w-1\/2{width:50%}.w-6{width:1.5rem}.w-\[101\.51px\]{width:101.51px}.w-\[170px\]{width:170px}.w-\[185px\]{width:185px}.w-\[300px\]{width:300px}.w-\[320px\]{width:320px}.w-\[38px\]{width:38px}.w-\[40px\]{width:40px}.w-\[5\.26px\]{width:5.26px}.w-\[58\.47px\]{width:58.47px}.w-\[650px\]{width:650px}.w-\[90px\]{width:90px}.w-\[926px\]{width:926px}.w-auto{width:auto}.w-full{width:100%}.max-w-\[300px\]{max-width:300px}.cursor-pointer{cursor:pointer}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-4{gap:1rem}.gap-\[6\.45px\]{gap:6.45px}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.border{border-width:1px}.border-neutral-800{--tw-border-opacity:1;border-color:rgb(38 38 38/var(--tw-border-opacity))}.bg-\[\#2B2B2B\]{--tw-bg-opacity:1;background-color:rgb(43 43 43/var(--tw-bg-opacity))}.bg-\[\#FF6A3F\]{--tw-bg-opacity:1;background-color:rgb(255 106 63/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-neutral-800{--tw-bg-opacity:1;background-color:rgb(38 38 38/var(--tw-bg-opacity))}.bg-stone-200{--tw-bg-opacity:1;background-color:rgb(231 229 228/var(--tw-bg-opacity))}.bg-stone-800{--tw-bg-opacity:1;background-color:rgb(41 37 36/var(--tw-bg-opacity))}.bg-transparent{background-color:initial}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-yellow-300{--tw-bg-opacity:1;background-color:rgb(253 224 71/var(--tw-bg-opacity))}.bg-opacity-75{--tw-bg-opacity:0.75}.object-fill{object-fit:fill}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-2\.5{padding-bottom:.625rem;padding-top:.625rem}.text-left{text-align:left}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-\[\'Pretendard\'\]{font-family:Pretendard}.font-\[\'Univers\'\]{font-family:Univers}.font-eng{font-family:Figtree,sans-serif}.font-kor{font-family:Pretendard,sans-serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-5xl{font-size:3rem;line-height:1}.text-6xl{font-size:3.75rem;line-height:1}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.leading-4{line-height:1rem}.leading-9{line-height:2.25rem}.leading-\[15\.12px\]{line-height:15.12px}.leading-\[18\.90px\]{line-height:18.9px}.leading-\[20px\]{line-height:20px}.leading-\[25px\]{line-height:25px}.leading-\[37px\]{line-height:37px}.leading-\[57px\]{line-height:57px}.leading-\[60px\]{line-height:60px}.leading-\[72px\]{line-height:72px}.leading-none{line-height:1}.tracking-wide{letter-spacing:.025em}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-neutral-800{--tw-text-opacity:1;color:rgb(38 38 38/var(--tw-text-opacity))}.text-stone-200{--tw-text-opacity:1;color:rgb(231 229 228/var(--tw-text-opacity))}.text-stone-800{--tw-text-opacity:1;color:rgb(41 37 36/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-yellow-300{--tw-text-opacity:1;color:rgb(253 224 71/var(--tw-text-opacity))}.text-opacity-50{--tw-text-opacity:0.5}.opacity-50{opacity:.5}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:bg-\[\#E6552F\]:hover{--tw-bg-opacity:1;background-color:rgb(230 85 47/var(--tw-bg-opacity))}.hover\:bg-neutral-600:hover{--tw-bg-opacity:1;background-color:rgb(82 82 82/var(--tw-bg-opacity))}.hover\:bg-stone-600:hover{--tw-bg-opacity:1;background-color:rgb(87 83 78/var(--tw-bg-opacity))}.hover\:bg-yellow-600:hover{--tw-bg-opacity:1;background-color:rgb(202 138 4/var(--tw-bg-opacity))}.hover\:font-bold:hover{font-weight:700}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),0 0 #0000;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-white:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.focus\:ring-offset-stone-200:focus{--tw-ring-offset-color:#e7e5e4} -/*# sourceMappingURL=main.d5c25553.css.map*/ \ No newline at end of file diff --git a/my-app/build/static/css/main.d5c25553.css.map b/my-app/build/static/css/main.d5c25553.css.map deleted file mode 100644 index bbb230b..0000000 --- a/my-app/build/static/css/main.d5c25553.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"static/css/main.d5c25553.css","mappings":"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","sources":["tailwind.css"],"sourcesContent":["@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer components {\n .link-underline {\n @apply relative;\n @apply inline-block;\n }\n .link-underline::after {\n content: '';\n @apply absolute;\n @apply w-0;\n @apply h-0.5;\n @apply bg-neutral-800;\n @apply bottom-0.5;\n @apply left-1/2;\n @apply transition-all;\n @apply duration-300;\n }\n .link-underline:hover::after {\n @apply w-full;\n @apply left-0;\n }\n }"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/my-app/build/static/js/787.d4aba7ab.chunk.js b/my-app/build/static/js/787.d4aba7ab.chunk.js deleted file mode 100644 index a41e13c..0000000 --- a/my-app/build/static/js/787.d4aba7ab.chunk.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";(self.webpackChunkmy_app=self.webpackChunkmy_app||[]).push([[787],{787:(e,t,n)=>{n.r(t),n.d(t,{getCLS:()=>y,getFCP:()=>g,getFID:()=>C,getLCP:()=>P,getTTFB:()=>D});var i,r,a,o,u=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v2-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},c=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},f=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},s=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},m=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},v=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},d=function(){f((function(e){var t=e.timeStamp;v=t}),!0)},l=function(){return v<0&&(v=p(),d(),s((function(){setTimeout((function(){v=p(),d()}),0)}))),{get firstHiddenTime(){return v}}},g=function(e,t){var n,i=l(),r=u("FCP"),a=function(e){"first-contentful-paint"===e.name&&(f&&f.disconnect(),e.startTime-1&&e(t)},r=u("CLS",0),a=0,o=[],v=function(e){if(!e.hadRecentInput){var t=o[0],i=o[o.length-1];a&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(a+=e.value,o.push(e)):(a=e.value,o=[e]),a>r.value&&(r.value=a,r.entries=o,n())}},p=c("layout-shift",v);p&&(n=m(i,r,t),f((function(){p.takeRecords().map(v),n(!0)})),s((function(){a=0,T=-1,r=u("CLS",0),n=m(i,r,t)})))},E={passive:!0,capture:!0},w=new Date,L=function(e,t){i||(i=t,r=e,a=new Date,F(removeEventListener),S())},S=function(){if(r>=0&&r1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){L(e,t),r()},i=function(){r()},r=function(){removeEventListener("pointerup",n,E),removeEventListener("pointercancel",i,E)};addEventListener("pointerup",n,E),addEventListener("pointercancel",i,E)}(t,e):L(t,e)}},F=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,b,E)}))},C=function(e,t){var n,a=l(),v=u("FID"),p=function(e){e.startTimeperformance.now())return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("load",(function(){return setTimeout(t,0)}))}}}]); -//# sourceMappingURL=787.d4aba7ab.chunk.js.map \ No newline at end of file diff --git a/my-app/build/static/js/787.d4aba7ab.chunk.js.map b/my-app/build/static/js/787.d4aba7ab.chunk.js.map deleted file mode 100644 index 2b0bfb5..0000000 --- a/my-app/build/static/js/787.d4aba7ab.chunk.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"static/js/787.d4aba7ab.chunk.js","mappings":"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","sources":["../node_modules/web-vitals/dist/web-vitals.js"],"sourcesContent":["var e,t,n,i,r=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:\"v2-\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12)}},a=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if(\"first-input\"===e&&!(\"PerformanceEventTiming\"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},o=function(e,t){var n=function n(i){\"pagehide\"!==i.type&&\"hidden\"!==document.visibilityState||(e(i),t&&(removeEventListener(\"visibilitychange\",n,!0),removeEventListener(\"pagehide\",n,!0)))};addEventListener(\"visibilitychange\",n,!0),addEventListener(\"pagehide\",n,!0)},u=function(e){addEventListener(\"pageshow\",(function(t){t.persisted&&e(t)}),!0)},c=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},f=-1,s=function(){return\"hidden\"===document.visibilityState?0:1/0},m=function(){o((function(e){var t=e.timeStamp;f=t}),!0)},v=function(){return f<0&&(f=s(),m(),u((function(){setTimeout((function(){f=s(),m()}),0)}))),{get firstHiddenTime(){return f}}},d=function(e,t){var n,i=v(),o=r(\"FCP\"),f=function(e){\"first-contentful-paint\"===e.name&&(m&&m.disconnect(),e.startTime-1&&e(t)},f=r(\"CLS\",0),s=0,m=[],v=function(e){if(!e.hadRecentInput){var t=m[0],i=m[m.length-1];s&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(s+=e.value,m.push(e)):(s=e.value,m=[e]),s>f.value&&(f.value=s,f.entries=m,n())}},h=a(\"layout-shift\",v);h&&(n=c(i,f,t),o((function(){h.takeRecords().map(v),n(!0)})),u((function(){s=0,l=-1,f=r(\"CLS\",0),n=c(i,f,t)})))},T={passive:!0,capture:!0},y=new Date,g=function(i,r){e||(e=r,t=i,n=new Date,w(removeEventListener),E())},E=function(){if(t>=0&&t1e12?new Date:performance.now())-e.timeStamp;\"pointerdown\"==e.type?function(e,t){var n=function(){g(e,t),r()},i=function(){r()},r=function(){removeEventListener(\"pointerup\",n,T),removeEventListener(\"pointercancel\",i,T)};addEventListener(\"pointerup\",n,T),addEventListener(\"pointercancel\",i,T)}(t,e):g(t,e)}},w=function(e){[\"mousedown\",\"keydown\",\"touchstart\",\"pointerdown\"].forEach((function(t){return e(t,S,T)}))},L=function(n,f){var s,m=v(),d=r(\"FID\"),p=function(e){e.startTimeperformance.now())return;n.entries=[t],e(n)}catch(e){}},\"complete\"===document.readyState?setTimeout(t,0):addEventListener(\"load\",(function(){return setTimeout(t,0)}))};export{h as getCLS,d as getFCP,L as getFID,F as getLCP,P as getTTFB};\n"],"names":["e","t","n","i","r","name","value","delta","entries","id","concat","Date","now","Math","floor","random","a","PerformanceObserver","supportedEntryTypes","includes","self","getEntries","map","observe","type","buffered","o","document","visibilityState","removeEventListener","addEventListener","u","persisted","c","f","s","m","timeStamp","v","setTimeout","firstHiddenTime","d","disconnect","startTime","push","window","performance","getEntriesByName","requestAnimationFrame","p","l","h","hadRecentInput","length","takeRecords","T","passive","capture","y","g","w","E","entryType","target","cancelable","processingStart","forEach","S","L","b","F","once","P","getEntriesByType","timing","max","navigationStart","responseStart","readyState"],"sourceRoot":""} \ No newline at end of file diff --git a/my-app/build/static/js/main.c90bec40.js b/my-app/build/static/js/main.c90bec40.js deleted file mode 100644 index f9349af..0000000 --- a/my-app/build/static/js/main.c90bec40.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! For license information please see main.c90bec40.js.LICENSE.txt */ -(()=>{var e={463:(e,t,n)=>{"use strict";var r=n(791),a=n(296);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n
attribute.\n *\n * @param to - The destination URL\n */\n createHref(to: To): string;\n\n /**\n * Returns a URL for the given `to` value\n *\n * @param to - The destination URL\n */\n createURL(to: To): URL;\n\n /**\n * Encode a location the same way window.history would do (no-op for memory\n * history) so we ensure our PUSH/REPLACE navigations for data routers\n * behave the same as POP\n *\n * @param to Unencoded path\n */\n encodeLocation(to: To): Path;\n\n /**\n * Pushes a new location onto the history stack, increasing its length by one.\n * If there were any entries in the stack after the current one, they are\n * lost.\n *\n * @param to - The new URL\n * @param state - Data to associate with the new location\n */\n push(to: To, state?: any): void;\n\n /**\n * Replaces the current location in the history stack with a new one. The\n * location that was replaced will no longer be available.\n *\n * @param to - The new URL\n * @param state - Data to associate with the new location\n */\n replace(to: To, state?: any): void;\n\n /**\n * Navigates `n` entries backward/forward in the history stack relative to the\n * current index. For example, a \"back\" navigation would use go(-1).\n *\n * @param delta - The delta in the stack index\n */\n go(delta: number): void;\n\n /**\n * Sets up a listener that will be called whenever the current location\n * changes.\n *\n * @param listener - A function that will be called when the location changes\n * @returns unlisten - A function that may be used to stop listening\n */\n listen(listener: Listener): () => void;\n}\n\ntype HistoryState = {\n usr: any;\n key?: string;\n idx: number;\n};\n\nconst PopStateEventType = \"popstate\";\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Memory History\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A user-supplied object that describes a location. Used when providing\n * entries to `createMemoryHistory` via its `initialEntries` option.\n */\nexport type InitialEntry = string | Partial;\n\nexport type MemoryHistoryOptions = {\n initialEntries?: InitialEntry[];\n initialIndex?: number;\n v5Compat?: boolean;\n};\n\n/**\n * A memory history stores locations in memory. This is useful in stateful\n * environments where there is no web browser, such as node tests or React\n * Native.\n */\nexport interface MemoryHistory extends History {\n /**\n * The current index in the history stack.\n */\n readonly index: number;\n}\n\n/**\n * Memory history stores the current location in memory. It is designed for use\n * in stateful non-browser environments like tests and React Native.\n */\nexport function createMemoryHistory(\n options: MemoryHistoryOptions = {}\n): MemoryHistory {\n let { initialEntries = [\"/\"], initialIndex, v5Compat = false } = options;\n let entries: Location[]; // Declare so we can access from createMemoryLocation\n entries = initialEntries.map((entry, index) =>\n createMemoryLocation(\n entry,\n typeof entry === \"string\" ? null : entry.state,\n index === 0 ? \"default\" : undefined\n )\n );\n let index = clampIndex(\n initialIndex == null ? entries.length - 1 : initialIndex\n );\n let action = Action.Pop;\n let listener: Listener | null = null;\n\n function clampIndex(n: number): number {\n return Math.min(Math.max(n, 0), entries.length - 1);\n }\n function getCurrentLocation(): Location {\n return entries[index];\n }\n function createMemoryLocation(\n to: To,\n state: any = null,\n key?: string\n ): Location {\n let location = createLocation(\n entries ? getCurrentLocation().pathname : \"/\",\n to,\n state,\n key\n );\n warning(\n location.pathname.charAt(0) === \"/\",\n `relative pathnames are not supported in memory history: ${JSON.stringify(\n to\n )}`\n );\n return location;\n }\n\n function createHref(to: To) {\n return typeof to === \"string\" ? to : createPath(to);\n }\n\n let history: MemoryHistory = {\n get index() {\n return index;\n },\n get action() {\n return action;\n },\n get location() {\n return getCurrentLocation();\n },\n createHref,\n createURL(to) {\n return new URL(createHref(to), \"http://localhost\");\n },\n encodeLocation(to: To) {\n let path = typeof to === \"string\" ? parsePath(to) : to;\n return {\n pathname: path.pathname || \"\",\n search: path.search || \"\",\n hash: path.hash || \"\",\n };\n },\n push(to, state) {\n action = Action.Push;\n let nextLocation = createMemoryLocation(to, state);\n index += 1;\n entries.splice(index, entries.length, nextLocation);\n if (v5Compat && listener) {\n listener({ action, location: nextLocation, delta: 1 });\n }\n },\n replace(to, state) {\n action = Action.Replace;\n let nextLocation = createMemoryLocation(to, state);\n entries[index] = nextLocation;\n if (v5Compat && listener) {\n listener({ action, location: nextLocation, delta: 0 });\n }\n },\n go(delta) {\n action = Action.Pop;\n let nextIndex = clampIndex(index + delta);\n let nextLocation = entries[nextIndex];\n index = nextIndex;\n if (listener) {\n listener({ action, location: nextLocation, delta });\n }\n },\n listen(fn: Listener) {\n listener = fn;\n return () => {\n listener = null;\n };\n },\n };\n\n return history;\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Browser History\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A browser history stores the current location in regular URLs in a web\n * browser environment. This is the standard for most web apps and provides the\n * cleanest URLs the browser's address bar.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#browserhistory\n */\nexport interface BrowserHistory extends UrlHistory {}\n\nexport type BrowserHistoryOptions = UrlHistoryOptions;\n\n/**\n * Browser history stores the location in regular URLs. This is the standard for\n * most web apps, but it requires some configuration on the server to ensure you\n * serve the same app at multiple URLs.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createbrowserhistory\n */\nexport function createBrowserHistory(\n options: BrowserHistoryOptions = {}\n): BrowserHistory {\n function createBrowserLocation(\n window: Window,\n globalHistory: Window[\"history\"]\n ) {\n let { pathname, search, hash } = window.location;\n return createLocation(\n \"\",\n { pathname, search, hash },\n // state defaults to `null` because `window.history.state` does\n (globalHistory.state && globalHistory.state.usr) || null,\n (globalHistory.state && globalHistory.state.key) || \"default\"\n );\n }\n\n function createBrowserHref(window: Window, to: To) {\n return typeof to === \"string\" ? to : createPath(to);\n }\n\n return getUrlBasedHistory(\n createBrowserLocation,\n createBrowserHref,\n null,\n options\n );\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Hash History\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A hash history stores the current location in the fragment identifier portion\n * of the URL in a web browser environment.\n *\n * This is ideal for apps that do not control the server for some reason\n * (because the fragment identifier is never sent to the server), including some\n * shared hosting environments that do not provide fine-grained controls over\n * which pages are served at which URLs.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#hashhistory\n */\nexport interface HashHistory extends UrlHistory {}\n\nexport type HashHistoryOptions = UrlHistoryOptions;\n\n/**\n * Hash history stores the location in window.location.hash. This makes it ideal\n * for situations where you don't want to send the location to the server for\n * some reason, either because you do cannot configure it or the URL space is\n * reserved for something else.\n *\n * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createhashhistory\n */\nexport function createHashHistory(\n options: HashHistoryOptions = {}\n): HashHistory {\n function createHashLocation(\n window: Window,\n globalHistory: Window[\"history\"]\n ) {\n let {\n pathname = \"/\",\n search = \"\",\n hash = \"\",\n } = parsePath(window.location.hash.substr(1));\n\n // Hash URL should always have a leading / just like window.location.pathname\n // does, so if an app ends up at a route like /#something then we add a\n // leading slash so all of our path-matching behaves the same as if it would\n // in a browser router. This is particularly important when there exists a\n // root splat route () since that matches internally against\n // \"/*\" and we'd expect /#something to 404 in a hash router app.\n if (!pathname.startsWith(\"/\") && !pathname.startsWith(\".\")) {\n pathname = \"/\" + pathname;\n }\n\n return createLocation(\n \"\",\n { pathname, search, hash },\n // state defaults to `null` because `window.history.state` does\n (globalHistory.state && globalHistory.state.usr) || null,\n (globalHistory.state && globalHistory.state.key) || \"default\"\n );\n }\n\n function createHashHref(window: Window, to: To) {\n let base = window.document.querySelector(\"base\");\n let href = \"\";\n\n if (base && base.getAttribute(\"href\")) {\n let url = window.location.href;\n let hashIndex = url.indexOf(\"#\");\n href = hashIndex === -1 ? url : url.slice(0, hashIndex);\n }\n\n return href + \"#\" + (typeof to === \"string\" ? to : createPath(to));\n }\n\n function validateHashLocation(location: Location, to: To) {\n warning(\n location.pathname.charAt(0) === \"/\",\n `relative pathnames are not supported in hash history.push(${JSON.stringify(\n to\n )})`\n );\n }\n\n return getUrlBasedHistory(\n createHashLocation,\n createHashHref,\n validateHashLocation,\n options\n );\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region UTILS\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * @private\n */\nexport function invariant(value: boolean, message?: string): asserts value;\nexport function invariant(\n value: T | null | undefined,\n message?: string\n): asserts value is T;\nexport function invariant(value: any, message?: string) {\n if (value === false || value === null || typeof value === \"undefined\") {\n throw new Error(message);\n }\n}\n\nexport function warning(cond: any, message: string) {\n if (!cond) {\n // eslint-disable-next-line no-console\n if (typeof console !== \"undefined\") console.warn(message);\n\n try {\n // Welcome to debugging history!\n //\n // This error is thrown as a convenience, so you can more easily\n // find the source for a warning that appears in the console by\n // enabling \"pause on exceptions\" in your JavaScript debugger.\n throw new Error(message);\n // eslint-disable-next-line no-empty\n } catch (e) {}\n }\n}\n\nfunction createKey() {\n return Math.random().toString(36).substr(2, 8);\n}\n\n/**\n * For browser-based histories, we combine the state and key into an object\n */\nfunction getHistoryState(location: Location, index: number): HistoryState {\n return {\n usr: location.state,\n key: location.key,\n idx: index,\n };\n}\n\n/**\n * Creates a Location object with a unique key from the given Path\n */\nexport function createLocation(\n current: string | Location,\n to: To,\n state: any = null,\n key?: string\n): Readonly {\n let location: Readonly = {\n pathname: typeof current === \"string\" ? current : current.pathname,\n search: \"\",\n hash: \"\",\n ...(typeof to === \"string\" ? parsePath(to) : to),\n state,\n // TODO: This could be cleaned up. push/replace should probably just take\n // full Locations now and avoid the need to run through this flow at all\n // But that's a pretty big refactor to the current test suite so going to\n // keep as is for the time being and just let any incoming keys take precedence\n key: (to && (to as Location).key) || key || createKey(),\n };\n return location;\n}\n\n/**\n * Creates a string URL path from the given pathname, search, and hash components.\n */\nexport function createPath({\n pathname = \"/\",\n search = \"\",\n hash = \"\",\n}: Partial) {\n if (search && search !== \"?\")\n pathname += search.charAt(0) === \"?\" ? search : \"?\" + search;\n if (hash && hash !== \"#\")\n pathname += hash.charAt(0) === \"#\" ? hash : \"#\" + hash;\n return pathname;\n}\n\n/**\n * Parses a string URL path into its separate pathname, search, and hash components.\n */\nexport function parsePath(path: string): Partial {\n let parsedPath: Partial = {};\n\n if (path) {\n let hashIndex = path.indexOf(\"#\");\n if (hashIndex >= 0) {\n parsedPath.hash = path.substr(hashIndex);\n path = path.substr(0, hashIndex);\n }\n\n let searchIndex = path.indexOf(\"?\");\n if (searchIndex >= 0) {\n parsedPath.search = path.substr(searchIndex);\n path = path.substr(0, searchIndex);\n }\n\n if (path) {\n parsedPath.pathname = path;\n }\n }\n\n return parsedPath;\n}\n\nexport interface UrlHistory extends History {}\n\nexport type UrlHistoryOptions = {\n window?: Window;\n v5Compat?: boolean;\n};\n\nfunction getUrlBasedHistory(\n getLocation: (window: Window, globalHistory: Window[\"history\"]) => Location,\n createHref: (window: Window, to: To) => string,\n validateLocation: ((location: Location, to: To) => void) | null,\n options: UrlHistoryOptions = {}\n): UrlHistory {\n let { window = document.defaultView!, v5Compat = false } = options;\n let globalHistory = window.history;\n let action = Action.Pop;\n let listener: Listener | null = null;\n\n let index = getIndex()!;\n // Index should only be null when we initialize. If not, it's because the\n // user called history.pushState or history.replaceState directly, in which\n // case we should log a warning as it will result in bugs.\n if (index == null) {\n index = 0;\n globalHistory.replaceState({ ...globalHistory.state, idx: index }, \"\");\n }\n\n function getIndex(): number {\n let state = globalHistory.state || { idx: null };\n return state.idx;\n }\n\n function handlePop() {\n action = Action.Pop;\n let nextIndex = getIndex();\n let delta = nextIndex == null ? null : nextIndex - index;\n index = nextIndex;\n if (listener) {\n listener({ action, location: history.location, delta });\n }\n }\n\n function push(to: To, state?: any) {\n action = Action.Push;\n let location = createLocation(history.location, to, state);\n if (validateLocation) validateLocation(location, to);\n\n index = getIndex() + 1;\n let historyState = getHistoryState(location, index);\n let url = history.createHref(location);\n\n // try...catch because iOS limits us to 100 pushState calls :/\n try {\n globalHistory.pushState(historyState, \"\", url);\n } catch (error) {\n // If the exception is because `state` can't be serialized, let that throw\n // outwards just like a replace call would so the dev knows the cause\n // https://html.spec.whatwg.org/multipage/nav-history-apis.html#shared-history-push/replace-state-steps\n // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal\n if (error instanceof DOMException && error.name === \"DataCloneError\") {\n throw error;\n }\n // They are going to lose state here, but there is no real\n // way to warn them about it since the page will refresh...\n window.location.assign(url);\n }\n\n if (v5Compat && listener) {\n listener({ action, location: history.location, delta: 1 });\n }\n }\n\n function replace(to: To, state?: any) {\n action = Action.Replace;\n let location = createLocation(history.location, to, state);\n if (validateLocation) validateLocation(location, to);\n\n index = getIndex();\n let historyState = getHistoryState(location, index);\n let url = history.createHref(location);\n globalHistory.replaceState(historyState, \"\", url);\n\n if (v5Compat && listener) {\n listener({ action, location: history.location, delta: 0 });\n }\n }\n\n function createURL(to: To): URL {\n // window.location.origin is \"null\" (the literal string value) in Firefox\n // under certain conditions, notably when serving from a local HTML file\n // See https://bugzilla.mozilla.org/show_bug.cgi?id=878297\n let base =\n window.location.origin !== \"null\"\n ? window.location.origin\n : window.location.href;\n\n let href = typeof to === \"string\" ? to : createPath(to);\n invariant(\n base,\n `No window.location.(origin|href) available to create URL for href: ${href}`\n );\n return new URL(href, base);\n }\n\n let history: History = {\n get action() {\n return action;\n },\n get location() {\n return getLocation(window, globalHistory);\n },\n listen(fn: Listener) {\n if (listener) {\n throw new Error(\"A history only accepts one active listener\");\n }\n window.addEventListener(PopStateEventType, handlePop);\n listener = fn;\n\n return () => {\n window.removeEventListener(PopStateEventType, handlePop);\n listener = null;\n };\n },\n createHref(to) {\n return createHref(window, to);\n },\n createURL,\n encodeLocation(to) {\n // Encode a Location the same way window.location would\n let url = createURL(to);\n return {\n pathname: url.pathname,\n search: url.search,\n hash: url.hash,\n };\n },\n push,\n replace,\n go(n) {\n return globalHistory.go(n);\n },\n };\n\n return history;\n}\n\n//#endregion\n","import type { Location, Path, To } from \"./history\";\nimport { invariant, parsePath, warning } from \"./history\";\n\n/**\n * Map of routeId -> data returned from a loader/action/error\n */\nexport interface RouteData {\n [routeId: string]: any;\n}\n\nexport enum ResultType {\n data = \"data\",\n deferred = \"deferred\",\n redirect = \"redirect\",\n error = \"error\",\n}\n\n/**\n * Successful result from a loader or action\n */\nexport interface SuccessResult {\n type: ResultType.data;\n data: any;\n statusCode?: number;\n headers?: Headers;\n}\n\n/**\n * Successful defer() result from a loader or action\n */\nexport interface DeferredResult {\n type: ResultType.deferred;\n deferredData: DeferredData;\n statusCode?: number;\n headers?: Headers;\n}\n\n/**\n * Redirect result from a loader or action\n */\nexport interface RedirectResult {\n type: ResultType.redirect;\n status: number;\n location: string;\n revalidate: boolean;\n reloadDocument?: boolean;\n}\n\n/**\n * Unsuccessful result from a loader or action\n */\nexport interface ErrorResult {\n type: ResultType.error;\n error: any;\n headers?: Headers;\n}\n\n/**\n * Result from a loader or action - potentially successful or unsuccessful\n */\nexport type DataResult =\n | SuccessResult\n | DeferredResult\n | RedirectResult\n | ErrorResult;\n\ntype LowerCaseFormMethod = \"get\" | \"post\" | \"put\" | \"patch\" | \"delete\";\ntype UpperCaseFormMethod = Uppercase;\n\n/**\n * Users can specify either lowercase or uppercase form methods on ``,\n * useSubmit(), ``, etc.\n */\nexport type HTMLFormMethod = LowerCaseFormMethod | UpperCaseFormMethod;\n\n/**\n * Active navigation/fetcher form methods are exposed in lowercase on the\n * RouterState\n */\nexport type FormMethod = LowerCaseFormMethod;\nexport type MutationFormMethod = Exclude;\n\n/**\n * In v7, active navigation/fetcher form methods are exposed in uppercase on the\n * RouterState. This is to align with the normalization done via fetch().\n */\nexport type V7_FormMethod = UpperCaseFormMethod;\nexport type V7_MutationFormMethod = Exclude;\n\nexport type FormEncType =\n | \"application/x-www-form-urlencoded\"\n | \"multipart/form-data\"\n | \"application/json\"\n | \"text/plain\";\n\n// Thanks https://github.com/sindresorhus/type-fest!\ntype JsonObject = { [Key in string]: JsonValue } & {\n [Key in string]?: JsonValue | undefined;\n};\ntype JsonArray = JsonValue[] | readonly JsonValue[];\ntype JsonPrimitive = string | number | boolean | null;\ntype JsonValue = JsonPrimitive | JsonObject | JsonArray;\n\n/**\n * @private\n * Internal interface to pass around for action submissions, not intended for\n * external consumption\n */\nexport type Submission =\n | {\n formMethod: FormMethod | V7_FormMethod;\n formAction: string;\n formEncType: FormEncType;\n formData: FormData;\n json: undefined;\n text: undefined;\n }\n | {\n formMethod: FormMethod | V7_FormMethod;\n formAction: string;\n formEncType: FormEncType;\n formData: undefined;\n json: JsonValue;\n text: undefined;\n }\n | {\n formMethod: FormMethod | V7_FormMethod;\n formAction: string;\n formEncType: FormEncType;\n formData: undefined;\n json: undefined;\n text: string;\n };\n\n/**\n * @private\n * Arguments passed to route loader/action functions. Same for now but we keep\n * this as a private implementation detail in case they diverge in the future.\n */\ninterface DataFunctionArgs {\n request: Request;\n params: Params;\n context?: Context;\n}\n\n// TODO: (v7) Change the defaults from any to unknown in and remove Remix wrappers:\n// ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs\n// Also, make them a type alias instead of an interface\n\n/**\n * Arguments passed to loader functions\n */\nexport interface LoaderFunctionArgs\n extends DataFunctionArgs {}\n\n/**\n * Arguments passed to action functions\n */\nexport interface ActionFunctionArgs\n extends DataFunctionArgs {}\n\n/**\n * Loaders and actions can return anything except `undefined` (`null` is a\n * valid return value if there is no data to return). Responses are preferred\n * and will ease any future migration to Remix\n */\ntype DataFunctionValue = Response | NonNullable | null;\n\n/**\n * Route loader function signature\n */\nexport interface LoaderFunction {\n (args: LoaderFunctionArgs):\n | Promise\n | DataFunctionValue;\n}\n\n/**\n * Route action function signature\n */\nexport interface ActionFunction {\n (args: ActionFunctionArgs):\n | Promise\n | DataFunctionValue;\n}\n\n/**\n * Arguments passed to shouldRevalidate function\n */\nexport interface ShouldRevalidateFunctionArgs {\n currentUrl: URL;\n currentParams: AgnosticDataRouteMatch[\"params\"];\n nextUrl: URL;\n nextParams: AgnosticDataRouteMatch[\"params\"];\n formMethod?: Submission[\"formMethod\"];\n formAction?: Submission[\"formAction\"];\n formEncType?: Submission[\"formEncType\"];\n text?: Submission[\"text\"];\n formData?: Submission[\"formData\"];\n json?: Submission[\"json\"];\n actionResult?: any;\n defaultShouldRevalidate: boolean;\n}\n\n/**\n * Route shouldRevalidate function signature. This runs after any submission\n * (navigation or fetcher), so we flatten the navigation/fetcher submission\n * onto the arguments. It shouldn't matter whether it came from a navigation\n * or a fetcher, what really matters is the URLs and the formData since loaders\n * have to re-run based on the data models that were potentially mutated.\n */\nexport interface ShouldRevalidateFunction {\n (args: ShouldRevalidateFunctionArgs): boolean;\n}\n\n/**\n * Function provided by the framework-aware layers to set `hasErrorBoundary`\n * from the framework-aware `errorElement` prop\n *\n * @deprecated Use `mapRouteProperties` instead\n */\nexport interface DetectErrorBoundaryFunction {\n (route: AgnosticRouteObject): boolean;\n}\n\n/**\n * Function provided by the framework-aware layers to set any framework-specific\n * properties from framework-agnostic properties\n */\nexport interface MapRoutePropertiesFunction {\n (route: AgnosticRouteObject): {\n hasErrorBoundary: boolean;\n } & Record;\n}\n\n/**\n * Keys we cannot change from within a lazy() function. We spread all other keys\n * onto the route. Either they're meaningful to the router, or they'll get\n * ignored.\n */\nexport type ImmutableRouteKey =\n | \"lazy\"\n | \"caseSensitive\"\n | \"path\"\n | \"id\"\n | \"index\"\n | \"children\";\n\nexport const immutableRouteKeys = new Set([\n \"lazy\",\n \"caseSensitive\",\n \"path\",\n \"id\",\n \"index\",\n \"children\",\n]);\n\ntype RequireOne = Exclude<\n {\n [K in keyof T]: K extends Key ? Omit & Required> : never;\n }[keyof T],\n undefined\n>;\n\n/**\n * lazy() function to load a route definition, which can add non-matching\n * related properties to a route\n */\nexport interface LazyRouteFunction {\n (): Promise>>;\n}\n\n/**\n * Base RouteObject with common props shared by all types of routes\n */\ntype AgnosticBaseRouteObject = {\n caseSensitive?: boolean;\n path?: string;\n id?: string;\n loader?: LoaderFunction;\n action?: ActionFunction;\n hasErrorBoundary?: boolean;\n shouldRevalidate?: ShouldRevalidateFunction;\n handle?: any;\n lazy?: LazyRouteFunction;\n};\n\n/**\n * Index routes must not have children\n */\nexport type AgnosticIndexRouteObject = AgnosticBaseRouteObject & {\n children?: undefined;\n index: true;\n};\n\n/**\n * Non-index routes may have children, but cannot have index\n */\nexport type AgnosticNonIndexRouteObject = AgnosticBaseRouteObject & {\n children?: AgnosticRouteObject[];\n index?: false;\n};\n\n/**\n * A route object represents a logical route, with (optionally) its child\n * routes organized in a tree-like structure.\n */\nexport type AgnosticRouteObject =\n | AgnosticIndexRouteObject\n | AgnosticNonIndexRouteObject;\n\nexport type AgnosticDataIndexRouteObject = AgnosticIndexRouteObject & {\n id: string;\n};\n\nexport type AgnosticDataNonIndexRouteObject = AgnosticNonIndexRouteObject & {\n children?: AgnosticDataRouteObject[];\n id: string;\n};\n\n/**\n * A data route object, which is just a RouteObject with a required unique ID\n */\nexport type AgnosticDataRouteObject =\n | AgnosticDataIndexRouteObject\n | AgnosticDataNonIndexRouteObject;\n\nexport type RouteManifest = Record;\n\n// Recursive helper for finding path parameters in the absence of wildcards\ntype _PathParam =\n // split path into individual path segments\n Path extends `${infer L}/${infer R}`\n ? _PathParam | _PathParam\n : // find params after `:`\n Path extends `:${infer Param}`\n ? Param extends `${infer Optional}?`\n ? Optional\n : Param\n : // otherwise, there aren't any params present\n never;\n\n/**\n * Examples:\n * \"/a/b/*\" -> \"*\"\n * \":a\" -> \"a\"\n * \"/a/:b\" -> \"b\"\n * \"/a/blahblahblah:b\" -> \"b\"\n * \"/:a/:b\" -> \"a\" | \"b\"\n * \"/:a/b/:c/*\" -> \"a\" | \"c\" | \"*\"\n */\ntype PathParam =\n // check if path is just a wildcard\n Path extends \"*\" | \"/*\"\n ? \"*\"\n : // look for wildcard at the end of the path\n Path extends `${infer Rest}/*`\n ? \"*\" | _PathParam\n : // look for params in the absence of wildcards\n _PathParam;\n\n// Attempt to parse the given string segment. If it fails, then just return the\n// plain string type as a default fallback. Otherwise, return the union of the\n// parsed string literals that were referenced as dynamic segments in the route.\nexport type ParamParseKey =\n // if you could not find path params, fallback to `string`\n [PathParam] extends [never] ? string : PathParam;\n\n/**\n * The parameters that were parsed from the URL path.\n */\nexport type Params = {\n readonly [key in Key]: string | undefined;\n};\n\n/**\n * A RouteMatch contains info about how a route matched a URL.\n */\nexport interface AgnosticRouteMatch<\n ParamKey extends string = string,\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n> {\n /**\n * The names and values of dynamic parameters in the URL.\n */\n params: Params;\n /**\n * The portion of the URL pathname that was matched.\n */\n pathname: string;\n /**\n * The portion of the URL pathname that was matched before child routes.\n */\n pathnameBase: string;\n /**\n * The route object that was used to match.\n */\n route: RouteObjectType;\n}\n\nexport interface AgnosticDataRouteMatch\n extends AgnosticRouteMatch {}\n\nfunction isIndexRoute(\n route: AgnosticRouteObject\n): route is AgnosticIndexRouteObject {\n return route.index === true;\n}\n\n// Walk the route tree generating unique IDs where necessary, so we are working\n// solely with AgnosticDataRouteObject's within the Router\nexport function convertRoutesToDataRoutes(\n routes: AgnosticRouteObject[],\n mapRouteProperties: MapRoutePropertiesFunction,\n parentPath: number[] = [],\n manifest: RouteManifest = {}\n): AgnosticDataRouteObject[] {\n return routes.map((route, index) => {\n let treePath = [...parentPath, index];\n let id = typeof route.id === \"string\" ? route.id : treePath.join(\"-\");\n invariant(\n route.index !== true || !route.children,\n `Cannot specify children on an index route`\n );\n invariant(\n !manifest[id],\n `Found a route id collision on id \"${id}\". Route ` +\n \"id's must be globally unique within Data Router usages\"\n );\n\n if (isIndexRoute(route)) {\n let indexRoute: AgnosticDataIndexRouteObject = {\n ...route,\n ...mapRouteProperties(route),\n id,\n };\n manifest[id] = indexRoute;\n return indexRoute;\n } else {\n let pathOrLayoutRoute: AgnosticDataNonIndexRouteObject = {\n ...route,\n ...mapRouteProperties(route),\n id,\n children: undefined,\n };\n manifest[id] = pathOrLayoutRoute;\n\n if (route.children) {\n pathOrLayoutRoute.children = convertRoutesToDataRoutes(\n route.children,\n mapRouteProperties,\n treePath,\n manifest\n );\n }\n\n return pathOrLayoutRoute;\n }\n });\n}\n\n/**\n * Matches the given routes to a location and returns the match data.\n *\n * @see https://reactrouter.com/utils/match-routes\n */\nexport function matchRoutes<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n>(\n routes: RouteObjectType[],\n locationArg: Partial | string,\n basename = \"/\"\n): AgnosticRouteMatch[] | null {\n let location =\n typeof locationArg === \"string\" ? parsePath(locationArg) : locationArg;\n\n let pathname = stripBasename(location.pathname || \"/\", basename);\n\n if (pathname == null) {\n return null;\n }\n\n let branches = flattenRoutes(routes);\n rankRouteBranches(branches);\n\n let matches = null;\n for (let i = 0; matches == null && i < branches.length; ++i) {\n matches = matchRouteBranch(\n branches[i],\n // Incoming pathnames are generally encoded from either window.location\n // or from router.navigate, but we want to match against the unencoded\n // paths in the route definitions. Memory router locations won't be\n // encoded here but there also shouldn't be anything to decode so this\n // should be a safe operation. This avoids needing matchRoutes to be\n // history-aware.\n safelyDecodeURI(pathname)\n );\n }\n\n return matches;\n}\n\nexport interface UIMatch {\n id: string;\n pathname: string;\n params: AgnosticRouteMatch[\"params\"];\n data: Data;\n handle: Handle;\n}\n\nexport function convertRouteMatchToUiMatch(\n match: AgnosticDataRouteMatch,\n loaderData: RouteData\n): UIMatch {\n let { route, pathname, params } = match;\n return {\n id: route.id,\n pathname,\n params,\n data: loaderData[route.id],\n handle: route.handle,\n };\n}\n\ninterface RouteMeta<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n> {\n relativePath: string;\n caseSensitive: boolean;\n childrenIndex: number;\n route: RouteObjectType;\n}\n\ninterface RouteBranch<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n> {\n path: string;\n score: number;\n routesMeta: RouteMeta[];\n}\n\nfunction flattenRoutes<\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n>(\n routes: RouteObjectType[],\n branches: RouteBranch[] = [],\n parentsMeta: RouteMeta[] = [],\n parentPath = \"\"\n): RouteBranch[] {\n let flattenRoute = (\n route: RouteObjectType,\n index: number,\n relativePath?: string\n ) => {\n let meta: RouteMeta = {\n relativePath:\n relativePath === undefined ? route.path || \"\" : relativePath,\n caseSensitive: route.caseSensitive === true,\n childrenIndex: index,\n route,\n };\n\n if (meta.relativePath.startsWith(\"/\")) {\n invariant(\n meta.relativePath.startsWith(parentPath),\n `Absolute route path \"${meta.relativePath}\" nested under path ` +\n `\"${parentPath}\" is not valid. An absolute child route path ` +\n `must start with the combined path of all its parent routes.`\n );\n\n meta.relativePath = meta.relativePath.slice(parentPath.length);\n }\n\n let path = joinPaths([parentPath, meta.relativePath]);\n let routesMeta = parentsMeta.concat(meta);\n\n // Add the children before adding this route to the array, so we traverse the\n // route tree depth-first and child routes appear before their parents in\n // the \"flattened\" version.\n if (route.children && route.children.length > 0) {\n invariant(\n // Our types know better, but runtime JS may not!\n // @ts-expect-error\n route.index !== true,\n `Index routes must not have child routes. Please remove ` +\n `all child routes from route path \"${path}\".`\n );\n\n flattenRoutes(route.children, branches, routesMeta, path);\n }\n\n // Routes without a path shouldn't ever match by themselves unless they are\n // index routes, so don't add them to the list of possible branches.\n if (route.path == null && !route.index) {\n return;\n }\n\n branches.push({\n path,\n score: computeScore(path, route.index),\n routesMeta,\n });\n };\n routes.forEach((route, index) => {\n // coarse-grain check for optional params\n if (route.path === \"\" || !route.path?.includes(\"?\")) {\n flattenRoute(route, index);\n } else {\n for (let exploded of explodeOptionalSegments(route.path)) {\n flattenRoute(route, index, exploded);\n }\n }\n });\n\n return branches;\n}\n\n/**\n * Computes all combinations of optional path segments for a given path,\n * excluding combinations that are ambiguous and of lower priority.\n *\n * For example, `/one/:two?/three/:four?/:five?` explodes to:\n * - `/one/three`\n * - `/one/:two/three`\n * - `/one/three/:four`\n * - `/one/three/:five`\n * - `/one/:two/three/:four`\n * - `/one/:two/three/:five`\n * - `/one/three/:four/:five`\n * - `/one/:two/three/:four/:five`\n */\nfunction explodeOptionalSegments(path: string): string[] {\n let segments = path.split(\"/\");\n if (segments.length === 0) return [];\n\n let [first, ...rest] = segments;\n\n // Optional path segments are denoted by a trailing `?`\n let isOptional = first.endsWith(\"?\");\n // Compute the corresponding required segment: `foo?` -> `foo`\n let required = first.replace(/\\?$/, \"\");\n\n if (rest.length === 0) {\n // Intepret empty string as omitting an optional segment\n // `[\"one\", \"\", \"three\"]` corresponds to omitting `:two` from `/one/:two?/three` -> `/one/three`\n return isOptional ? [required, \"\"] : [required];\n }\n\n let restExploded = explodeOptionalSegments(rest.join(\"/\"));\n\n let result: string[] = [];\n\n // All child paths with the prefix. Do this for all children before the\n // optional version for all children, so we get consistent ordering where the\n // parent optional aspect is preferred as required. Otherwise, we can get\n // child sections interspersed where deeper optional segments are higher than\n // parent optional segments, where for example, /:two would explode _earlier_\n // then /:one. By always including the parent as required _for all children_\n // first, we avoid this issue\n result.push(\n ...restExploded.map((subpath) =>\n subpath === \"\" ? required : [required, subpath].join(\"/\")\n )\n );\n\n // Then, if this is an optional value, add all child versions without\n if (isOptional) {\n result.push(...restExploded);\n }\n\n // for absolute paths, ensure `/` instead of empty segment\n return result.map((exploded) =>\n path.startsWith(\"/\") && exploded === \"\" ? \"/\" : exploded\n );\n}\n\nfunction rankRouteBranches(branches: RouteBranch[]): void {\n branches.sort((a, b) =>\n a.score !== b.score\n ? b.score - a.score // Higher score first\n : compareIndexes(\n a.routesMeta.map((meta) => meta.childrenIndex),\n b.routesMeta.map((meta) => meta.childrenIndex)\n )\n );\n}\n\nconst paramRe = /^:\\w+$/;\nconst dynamicSegmentValue = 3;\nconst indexRouteValue = 2;\nconst emptySegmentValue = 1;\nconst staticSegmentValue = 10;\nconst splatPenalty = -2;\nconst isSplat = (s: string) => s === \"*\";\n\nfunction computeScore(path: string, index: boolean | undefined): number {\n let segments = path.split(\"/\");\n let initialScore = segments.length;\n if (segments.some(isSplat)) {\n initialScore += splatPenalty;\n }\n\n if (index) {\n initialScore += indexRouteValue;\n }\n\n return segments\n .filter((s) => !isSplat(s))\n .reduce(\n (score, segment) =>\n score +\n (paramRe.test(segment)\n ? dynamicSegmentValue\n : segment === \"\"\n ? emptySegmentValue\n : staticSegmentValue),\n initialScore\n );\n}\n\nfunction compareIndexes(a: number[], b: number[]): number {\n let siblings =\n a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);\n\n return siblings\n ? // If two routes are siblings, we should try to match the earlier sibling\n // first. This allows people to have fine-grained control over the matching\n // behavior by simply putting routes with identical paths in the order they\n // want them tried.\n a[a.length - 1] - b[b.length - 1]\n : // Otherwise, it doesn't really make sense to rank non-siblings by index,\n // so they sort equally.\n 0;\n}\n\nfunction matchRouteBranch<\n ParamKey extends string = string,\n RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject\n>(\n branch: RouteBranch,\n pathname: string\n): AgnosticRouteMatch[] | null {\n let { routesMeta } = branch;\n\n let matchedParams = {};\n let matchedPathname = \"/\";\n let matches: AgnosticRouteMatch[] = [];\n for (let i = 0; i < routesMeta.length; ++i) {\n let meta = routesMeta[i];\n let end = i === routesMeta.length - 1;\n let remainingPathname =\n matchedPathname === \"/\"\n ? pathname\n : pathname.slice(matchedPathname.length) || \"/\";\n let match = matchPath(\n { path: meta.relativePath, caseSensitive: meta.caseSensitive, end },\n remainingPathname\n );\n\n if (!match) return null;\n\n Object.assign(matchedParams, match.params);\n\n let route = meta.route;\n\n matches.push({\n // TODO: Can this as be avoided?\n params: matchedParams as Params,\n pathname: joinPaths([matchedPathname, match.pathname]),\n pathnameBase: normalizePathname(\n joinPaths([matchedPathname, match.pathnameBase])\n ),\n route,\n });\n\n if (match.pathnameBase !== \"/\") {\n matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);\n }\n }\n\n return matches;\n}\n\n/**\n * Returns a path with params interpolated.\n *\n * @see https://reactrouter.com/utils/generate-path\n */\nexport function generatePath(\n originalPath: Path,\n params: {\n [key in PathParam]: string | null;\n } = {} as any\n): string {\n let path: string = originalPath;\n if (path.endsWith(\"*\") && path !== \"*\" && !path.endsWith(\"/*\")) {\n warning(\n false,\n `Route path \"${path}\" will be treated as if it were ` +\n `\"${path.replace(/\\*$/, \"/*\")}\" because the \\`*\\` character must ` +\n `always follow a \\`/\\` in the pattern. To get rid of this warning, ` +\n `please change the route path to \"${path.replace(/\\*$/, \"/*\")}\".`\n );\n path = path.replace(/\\*$/, \"/*\") as Path;\n }\n\n // ensure `/` is added at the beginning if the path is absolute\n const prefix = path.startsWith(\"/\") ? \"/\" : \"\";\n\n const stringify = (p: any) =>\n p == null ? \"\" : typeof p === \"string\" ? p : String(p);\n\n const segments = path\n .split(/\\/+/)\n .map((segment, index, array) => {\n const isLastSegment = index === array.length - 1;\n\n // only apply the splat if it's the last segment\n if (isLastSegment && segment === \"*\") {\n const star = \"*\" as PathParam;\n // Apply the splat\n return stringify(params[star]);\n }\n\n const keyMatch = segment.match(/^:(\\w+)(\\??)$/);\n if (keyMatch) {\n const [, key, optional] = keyMatch;\n let param = params[key as PathParam];\n invariant(optional === \"?\" || param != null, `Missing \":${key}\" param`);\n return stringify(param);\n }\n\n // Remove any optional markers from optional static segments\n return segment.replace(/\\?$/g, \"\");\n })\n // Remove empty segments\n .filter((segment) => !!segment);\n\n return prefix + segments.join(\"/\");\n}\n\n/**\n * A PathPattern is used to match on some portion of a URL pathname.\n */\nexport interface PathPattern {\n /**\n * A string to match against a URL pathname. May contain `:id`-style segments\n * to indicate placeholders for dynamic parameters. May also end with `/*` to\n * indicate matching the rest of the URL pathname.\n */\n path: Path;\n /**\n * Should be `true` if the static portions of the `path` should be matched in\n * the same case.\n */\n caseSensitive?: boolean;\n /**\n * Should be `true` if this pattern should match the entire URL pathname.\n */\n end?: boolean;\n}\n\n/**\n * A PathMatch contains info about how a PathPattern matched on a URL pathname.\n */\nexport interface PathMatch {\n /**\n * The names and values of dynamic parameters in the URL.\n */\n params: Params;\n /**\n * The portion of the URL pathname that was matched.\n */\n pathname: string;\n /**\n * The portion of the URL pathname that was matched before child routes.\n */\n pathnameBase: string;\n /**\n * The pattern that was used to match.\n */\n pattern: PathPattern;\n}\n\ntype Mutable = {\n -readonly [P in keyof T]: T[P];\n};\n\n/**\n * Performs pattern matching on a URL pathname and returns information about\n * the match.\n *\n * @see https://reactrouter.com/utils/match-path\n */\nexport function matchPath<\n ParamKey extends ParamParseKey,\n Path extends string\n>(\n pattern: PathPattern | Path,\n pathname: string\n): PathMatch | null {\n if (typeof pattern === \"string\") {\n pattern = { path: pattern, caseSensitive: false, end: true };\n }\n\n let [matcher, compiledParams] = compilePath(\n pattern.path,\n pattern.caseSensitive,\n pattern.end\n );\n\n let match = pathname.match(matcher);\n if (!match) return null;\n\n let matchedPathname = match[0];\n let pathnameBase = matchedPathname.replace(/(.)\\/+$/, \"$1\");\n let captureGroups = match.slice(1);\n let params: Params = compiledParams.reduce>(\n (memo, { paramName, isOptional }, index) => {\n // We need to compute the pathnameBase here using the raw splat value\n // instead of using params[\"*\"] later because it will be decoded then\n if (paramName === \"*\") {\n let splatValue = captureGroups[index] || \"\";\n pathnameBase = matchedPathname\n .slice(0, matchedPathname.length - splatValue.length)\n .replace(/(.)\\/+$/, \"$1\");\n }\n\n const value = captureGroups[index];\n if (isOptional && !value) {\n memo[paramName] = undefined;\n } else {\n memo[paramName] = safelyDecodeURIComponent(value || \"\", paramName);\n }\n return memo;\n },\n {}\n );\n\n return {\n params,\n pathname: matchedPathname,\n pathnameBase,\n pattern,\n };\n}\n\ntype CompiledPathParam = { paramName: string; isOptional?: boolean };\n\nfunction compilePath(\n path: string,\n caseSensitive = false,\n end = true\n): [RegExp, CompiledPathParam[]] {\n warning(\n path === \"*\" || !path.endsWith(\"*\") || path.endsWith(\"/*\"),\n `Route path \"${path}\" will be treated as if it were ` +\n `\"${path.replace(/\\*$/, \"/*\")}\" because the \\`*\\` character must ` +\n `always follow a \\`/\\` in the pattern. To get rid of this warning, ` +\n `please change the route path to \"${path.replace(/\\*$/, \"/*\")}\".`\n );\n\n let params: CompiledPathParam[] = [];\n let regexpSource =\n \"^\" +\n path\n .replace(/\\/*\\*?$/, \"\") // Ignore trailing / and /*, we'll handle it below\n .replace(/^\\/*/, \"/\") // Make sure it has a leading /\n .replace(/[\\\\.*+^${}|()[\\]]/g, \"\\\\$&\") // Escape special regex chars\n .replace(/\\/:(\\w+)(\\?)?/g, (_: string, paramName: string, isOptional) => {\n params.push({ paramName, isOptional: isOptional != null });\n return isOptional ? \"/?([^\\\\/]+)?\" : \"/([^\\\\/]+)\";\n });\n\n if (path.endsWith(\"*\")) {\n params.push({ paramName: \"*\" });\n regexpSource +=\n path === \"*\" || path === \"/*\"\n ? \"(.*)$\" // Already matched the initial /, just match the rest\n : \"(?:\\\\/(.+)|\\\\/*)$\"; // Don't include the / in params[\"*\"]\n } else if (end) {\n // When matching to the end, ignore trailing slashes\n regexpSource += \"\\\\/*$\";\n } else if (path !== \"\" && path !== \"/\") {\n // If our path is non-empty and contains anything beyond an initial slash,\n // then we have _some_ form of path in our regex, so we should expect to\n // match only if we find the end of this path segment. Look for an optional\n // non-captured trailing slash (to match a portion of the URL) or the end\n // of the path (if we've matched to the end). We used to do this with a\n // word boundary but that gives false positives on routes like\n // /user-preferences since `-` counts as a word boundary.\n regexpSource += \"(?:(?=\\\\/|$))\";\n } else {\n // Nothing to match for \"\" or \"/\"\n }\n\n let matcher = new RegExp(regexpSource, caseSensitive ? undefined : \"i\");\n\n return [matcher, params];\n}\n\nfunction safelyDecodeURI(value: string) {\n try {\n return decodeURI(value);\n } catch (error) {\n warning(\n false,\n `The URL path \"${value}\" could not be decoded because it is is a ` +\n `malformed URL segment. This is probably due to a bad percent ` +\n `encoding (${error}).`\n );\n\n return value;\n }\n}\n\nfunction safelyDecodeURIComponent(value: string, paramName: string) {\n try {\n return decodeURIComponent(value);\n } catch (error) {\n warning(\n false,\n `The value for the URL param \"${paramName}\" will not be decoded because` +\n ` the string \"${value}\" is a malformed URL segment. This is probably` +\n ` due to a bad percent encoding (${error}).`\n );\n\n return value;\n }\n}\n\n/**\n * @private\n */\nexport function stripBasename(\n pathname: string,\n basename: string\n): string | null {\n if (basename === \"/\") return pathname;\n\n if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {\n return null;\n }\n\n // We want to leave trailing slash behavior in the user's control, so if they\n // specify a basename with a trailing slash, we should support it\n let startIndex = basename.endsWith(\"/\")\n ? basename.length - 1\n : basename.length;\n let nextChar = pathname.charAt(startIndex);\n if (nextChar && nextChar !== \"/\") {\n // pathname does not start with basename/\n return null;\n }\n\n return pathname.slice(startIndex) || \"/\";\n}\n\n/**\n * Returns a resolved path object relative to the given pathname.\n *\n * @see https://reactrouter.com/utils/resolve-path\n */\nexport function resolvePath(to: To, fromPathname = \"/\"): Path {\n let {\n pathname: toPathname,\n search = \"\",\n hash = \"\",\n } = typeof to === \"string\" ? parsePath(to) : to;\n\n let pathname = toPathname\n ? toPathname.startsWith(\"/\")\n ? toPathname\n : resolvePathname(toPathname, fromPathname)\n : fromPathname;\n\n return {\n pathname,\n search: normalizeSearch(search),\n hash: normalizeHash(hash),\n };\n}\n\nfunction resolvePathname(relativePath: string, fromPathname: string): string {\n let segments = fromPathname.replace(/\\/+$/, \"\").split(\"/\");\n let relativeSegments = relativePath.split(\"/\");\n\n relativeSegments.forEach((segment) => {\n if (segment === \"..\") {\n // Keep the root \"\" segment so the pathname starts at /\n if (segments.length > 1) segments.pop();\n } else if (segment !== \".\") {\n segments.push(segment);\n }\n });\n\n return segments.length > 1 ? segments.join(\"/\") : \"/\";\n}\n\nfunction getInvalidPathError(\n char: string,\n field: string,\n dest: string,\n path: Partial\n) {\n return (\n `Cannot include a '${char}' character in a manually specified ` +\n `\\`to.${field}\\` field [${JSON.stringify(\n path\n )}]. Please separate it out to the ` +\n `\\`to.${dest}\\` field. Alternatively you may provide the full path as ` +\n `a string in and the router will parse it for you.`\n );\n}\n\n/**\n * @private\n *\n * When processing relative navigation we want to ignore ancestor routes that\n * do not contribute to the path, such that index/pathless layout routes don't\n * interfere.\n *\n * For example, when moving a route element into an index route and/or a\n * pathless layout route, relative link behavior contained within should stay\n * the same. Both of the following examples should link back to the root:\n *\n * \n * \n * \n *\n * \n * \n * }> // <-- Does not contribute\n * // <-- Does not contribute\n * \n * \n */\nexport function getPathContributingMatches<\n T extends AgnosticRouteMatch = AgnosticRouteMatch\n>(matches: T[]) {\n return matches.filter(\n (match, index) =>\n index === 0 || (match.route.path && match.route.path.length > 0)\n );\n}\n\n/**\n * @private\n */\nexport function resolveTo(\n toArg: To,\n routePathnames: string[],\n locationPathname: string,\n isPathRelative = false\n): Path {\n let to: Partial;\n if (typeof toArg === \"string\") {\n to = parsePath(toArg);\n } else {\n to = { ...toArg };\n\n invariant(\n !to.pathname || !to.pathname.includes(\"?\"),\n getInvalidPathError(\"?\", \"pathname\", \"search\", to)\n );\n invariant(\n !to.pathname || !to.pathname.includes(\"#\"),\n getInvalidPathError(\"#\", \"pathname\", \"hash\", to)\n );\n invariant(\n !to.search || !to.search.includes(\"#\"),\n getInvalidPathError(\"#\", \"search\", \"hash\", to)\n );\n }\n\n let isEmptyPath = toArg === \"\" || to.pathname === \"\";\n let toPathname = isEmptyPath ? \"/\" : to.pathname;\n\n let from: string;\n\n // Routing is relative to the current pathname if explicitly requested.\n //\n // If a pathname is explicitly provided in `to`, it should be relative to the\n // route context. This is explained in `Note on `` values` in our\n // migration guide from v5 as a means of disambiguation between `to` values\n // that begin with `/` and those that do not. However, this is problematic for\n // `to` values that do not provide a pathname. `to` can simply be a search or\n // hash string, in which case we should assume that the navigation is relative\n // to the current location's pathname and *not* the route pathname.\n if (isPathRelative || toPathname == null) {\n from = locationPathname;\n } else {\n let routePathnameIndex = routePathnames.length - 1;\n\n if (toPathname.startsWith(\"..\")) {\n let toSegments = toPathname.split(\"/\");\n\n // Each leading .. segment means \"go up one route\" instead of \"go up one\n // URL segment\". This is a key difference from how works and a\n // major reason we call this a \"to\" value instead of a \"href\".\n while (toSegments[0] === \"..\") {\n toSegments.shift();\n routePathnameIndex -= 1;\n }\n\n to.pathname = toSegments.join(\"/\");\n }\n\n // If there are more \"..\" segments than parent routes, resolve relative to\n // the root / URL.\n from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : \"/\";\n }\n\n let path = resolvePath(to, from);\n\n // Ensure the pathname has a trailing slash if the original \"to\" had one\n let hasExplicitTrailingSlash =\n toPathname && toPathname !== \"/\" && toPathname.endsWith(\"/\");\n // Or if this was a link to the current path which has a trailing slash\n let hasCurrentTrailingSlash =\n (isEmptyPath || toPathname === \".\") && locationPathname.endsWith(\"/\");\n if (\n !path.pathname.endsWith(\"/\") &&\n (hasExplicitTrailingSlash || hasCurrentTrailingSlash)\n ) {\n path.pathname += \"/\";\n }\n\n return path;\n}\n\n/**\n * @private\n */\nexport function getToPathname(to: To): string | undefined {\n // Empty strings should be treated the same as / paths\n return to === \"\" || (to as Path).pathname === \"\"\n ? \"/\"\n : typeof to === \"string\"\n ? parsePath(to).pathname\n : to.pathname;\n}\n\n/**\n * @private\n */\nexport const joinPaths = (paths: string[]): string =>\n paths.join(\"/\").replace(/\\/\\/+/g, \"/\");\n\n/**\n * @private\n */\nexport const normalizePathname = (pathname: string): string =>\n pathname.replace(/\\/+$/, \"\").replace(/^\\/*/, \"/\");\n\n/**\n * @private\n */\nexport const normalizeSearch = (search: string): string =>\n !search || search === \"?\"\n ? \"\"\n : search.startsWith(\"?\")\n ? search\n : \"?\" + search;\n\n/**\n * @private\n */\nexport const normalizeHash = (hash: string): string =>\n !hash || hash === \"#\" ? \"\" : hash.startsWith(\"#\") ? hash : \"#\" + hash;\n\nexport type JsonFunction = (\n data: Data,\n init?: number | ResponseInit\n) => Response;\n\n/**\n * This is a shortcut for creating `application/json` responses. Converts `data`\n * to JSON and sets the `Content-Type` header.\n */\nexport const json: JsonFunction = (data, init = {}) => {\n let responseInit = typeof init === \"number\" ? { status: init } : init;\n\n let headers = new Headers(responseInit.headers);\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json; charset=utf-8\");\n }\n\n return new Response(JSON.stringify(data), {\n ...responseInit,\n headers,\n });\n};\n\nexport interface TrackedPromise extends Promise {\n _tracked?: boolean;\n _data?: any;\n _error?: any;\n}\n\nexport class AbortedDeferredError extends Error {}\n\nexport class DeferredData {\n private pendingKeysSet: Set = new Set();\n private controller: AbortController;\n private abortPromise: Promise;\n private unlistenAbortSignal: () => void;\n private subscribers: Set<(aborted: boolean, settledKey?: string) => void> =\n new Set();\n data: Record;\n init?: ResponseInit;\n deferredKeys: string[] = [];\n\n constructor(data: Record, responseInit?: ResponseInit) {\n invariant(\n data && typeof data === \"object\" && !Array.isArray(data),\n \"defer() only accepts plain objects\"\n );\n\n // Set up an AbortController + Promise we can race against to exit early\n // cancellation\n let reject: (e: AbortedDeferredError) => void;\n this.abortPromise = new Promise((_, r) => (reject = r));\n this.controller = new AbortController();\n let onAbort = () =>\n reject(new AbortedDeferredError(\"Deferred data aborted\"));\n this.unlistenAbortSignal = () =>\n this.controller.signal.removeEventListener(\"abort\", onAbort);\n this.controller.signal.addEventListener(\"abort\", onAbort);\n\n this.data = Object.entries(data).reduce(\n (acc, [key, value]) =>\n Object.assign(acc, {\n [key]: this.trackPromise(key, value),\n }),\n {}\n );\n\n if (this.done) {\n // All incoming values were resolved\n this.unlistenAbortSignal();\n }\n\n this.init = responseInit;\n }\n\n private trackPromise(\n key: string,\n value: Promise | unknown\n ): TrackedPromise | unknown {\n if (!(value instanceof Promise)) {\n return value;\n }\n\n this.deferredKeys.push(key);\n this.pendingKeysSet.add(key);\n\n // We store a little wrapper promise that will be extended with\n // _data/_error props upon resolve/reject\n let promise: TrackedPromise = Promise.race([value, this.abortPromise]).then(\n (data) => this.onSettle(promise, key, undefined, data as unknown),\n (error) => this.onSettle(promise, key, error as unknown)\n );\n\n // Register rejection listeners to avoid uncaught promise rejections on\n // errors or aborted deferred values\n promise.catch(() => {});\n\n Object.defineProperty(promise, \"_tracked\", { get: () => true });\n return promise;\n }\n\n private onSettle(\n promise: TrackedPromise,\n key: string,\n error: unknown,\n data?: unknown\n ): unknown {\n if (\n this.controller.signal.aborted &&\n error instanceof AbortedDeferredError\n ) {\n this.unlistenAbortSignal();\n Object.defineProperty(promise, \"_error\", { get: () => error });\n return Promise.reject(error);\n }\n\n this.pendingKeysSet.delete(key);\n\n if (this.done) {\n // Nothing left to abort!\n this.unlistenAbortSignal();\n }\n\n // If the promise was resolved/rejected with undefined, we'll throw an error as you\n // should always resolve with a value or null\n if (error === undefined && data === undefined) {\n let undefinedError = new Error(\n `Deferred data for key \"${key}\" resolved/rejected with \\`undefined\\`, ` +\n `you must resolve/reject with a value or \\`null\\`.`\n );\n Object.defineProperty(promise, \"_error\", { get: () => undefinedError });\n this.emit(false, key);\n return Promise.reject(undefinedError);\n }\n\n if (data === undefined) {\n Object.defineProperty(promise, \"_error\", { get: () => error });\n this.emit(false, key);\n return Promise.reject(error);\n }\n\n Object.defineProperty(promise, \"_data\", { get: () => data });\n this.emit(false, key);\n return data;\n }\n\n private emit(aborted: boolean, settledKey?: string) {\n this.subscribers.forEach((subscriber) => subscriber(aborted, settledKey));\n }\n\n subscribe(fn: (aborted: boolean, settledKey?: string) => void) {\n this.subscribers.add(fn);\n return () => this.subscribers.delete(fn);\n }\n\n cancel() {\n this.controller.abort();\n this.pendingKeysSet.forEach((v, k) => this.pendingKeysSet.delete(k));\n this.emit(true);\n }\n\n async resolveData(signal: AbortSignal) {\n let aborted = false;\n if (!this.done) {\n let onAbort = () => this.cancel();\n signal.addEventListener(\"abort\", onAbort);\n aborted = await new Promise((resolve) => {\n this.subscribe((aborted) => {\n signal.removeEventListener(\"abort\", onAbort);\n if (aborted || this.done) {\n resolve(aborted);\n }\n });\n });\n }\n return aborted;\n }\n\n get done() {\n return this.pendingKeysSet.size === 0;\n }\n\n get unwrappedData() {\n invariant(\n this.data !== null && this.done,\n \"Can only unwrap data on initialized and settled deferreds\"\n );\n\n return Object.entries(this.data).reduce(\n (acc, [key, value]) =>\n Object.assign(acc, {\n [key]: unwrapTrackedPromise(value),\n }),\n {}\n );\n }\n\n get pendingKeys() {\n return Array.from(this.pendingKeysSet);\n }\n}\n\nfunction isTrackedPromise(value: any): value is TrackedPromise {\n return (\n value instanceof Promise && (value as TrackedPromise)._tracked === true\n );\n}\n\nfunction unwrapTrackedPromise(value: any) {\n if (!isTrackedPromise(value)) {\n return value;\n }\n\n if (value._error) {\n throw value._error;\n }\n return value._data;\n}\n\nexport type DeferFunction = (\n data: Record,\n init?: number | ResponseInit\n) => DeferredData;\n\nexport const defer: DeferFunction = (data, init = {}) => {\n let responseInit = typeof init === \"number\" ? { status: init } : init;\n\n return new DeferredData(data, responseInit);\n};\n\nexport type RedirectFunction = (\n url: string,\n init?: number | ResponseInit\n) => Response;\n\n/**\n * A redirect response. Sets the status code and the `Location` header.\n * Defaults to \"302 Found\".\n */\nexport const redirect: RedirectFunction = (url, init = 302) => {\n let responseInit = init;\n if (typeof responseInit === \"number\") {\n responseInit = { status: responseInit };\n } else if (typeof responseInit.status === \"undefined\") {\n responseInit.status = 302;\n }\n\n let headers = new Headers(responseInit.headers);\n headers.set(\"Location\", url);\n\n return new Response(null, {\n ...responseInit,\n headers,\n });\n};\n\n/**\n * A redirect response that will force a document reload to the new location.\n * Sets the status code and the `Location` header.\n * Defaults to \"302 Found\".\n */\nexport const redirectDocument: RedirectFunction = (url, init) => {\n let response = redirect(url, init);\n response.headers.set(\"X-Remix-Reload-Document\", \"true\");\n return response;\n};\n\nexport type ErrorResponse = {\n status: number;\n statusText: string;\n data: any;\n};\n\n/**\n * @private\n * Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies\n *\n * We don't export the class for public use since it's an implementation\n * detail, but we export the interface above so folks can build their own\n * abstractions around instances via isRouteErrorResponse()\n */\nexport class ErrorResponseImpl implements ErrorResponse {\n status: number;\n statusText: string;\n data: any;\n private error?: Error;\n private internal: boolean;\n\n constructor(\n status: number,\n statusText: string | undefined,\n data: any,\n internal = false\n ) {\n this.status = status;\n this.statusText = statusText || \"\";\n this.internal = internal;\n if (data instanceof Error) {\n this.data = data.toString();\n this.error = data;\n } else {\n this.data = data;\n }\n }\n}\n\n/**\n * Check if the given error is an ErrorResponse generated from a 4xx/5xx\n * Response thrown from an action/loader\n */\nexport function isRouteErrorResponse(error: any): error is ErrorResponse {\n return (\n error != null &&\n typeof error.status === \"number\" &&\n typeof error.statusText === \"string\" &&\n typeof error.internal === \"boolean\" &&\n \"data\" in error\n );\n}\n","import type { History, Location, Path, To } from \"./history\";\nimport {\n Action as HistoryAction,\n createLocation,\n createPath,\n invariant,\n parsePath,\n warning,\n} from \"./history\";\nimport type {\n ActionFunction,\n AgnosticDataRouteMatch,\n AgnosticDataRouteObject,\n AgnosticRouteObject,\n DataResult,\n DeferredData,\n DeferredResult,\n DetectErrorBoundaryFunction,\n ErrorResult,\n FormEncType,\n FormMethod,\n HTMLFormMethod,\n ImmutableRouteKey,\n LoaderFunction,\n MapRoutePropertiesFunction,\n MutationFormMethod,\n RedirectResult,\n RouteData,\n RouteManifest,\n ShouldRevalidateFunctionArgs,\n Submission,\n SuccessResult,\n UIMatch,\n V7_FormMethod,\n V7_MutationFormMethod,\n} from \"./utils\";\nimport {\n ErrorResponseImpl,\n ResultType,\n convertRouteMatchToUiMatch,\n convertRoutesToDataRoutes,\n getPathContributingMatches,\n immutableRouteKeys,\n isRouteErrorResponse,\n joinPaths,\n matchRoutes,\n resolveTo,\n stripBasename,\n} from \"./utils\";\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Types and Constants\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A Router instance manages all navigation and data loading/mutations\n */\nexport interface Router {\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the basename for the router\n */\n get basename(): RouterInit[\"basename\"];\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the current state of the router\n */\n get state(): RouterState;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the routes for this router instance\n */\n get routes(): AgnosticDataRouteObject[];\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Return the window associated with the router\n */\n get window(): RouterInit[\"window\"];\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Initialize the router, including adding history listeners and kicking off\n * initial data fetches. Returns a function to cleanup listeners and abort\n * any in-progress loads\n */\n initialize(): Router;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Subscribe to router.state updates\n *\n * @param fn function to call with the new state\n */\n subscribe(fn: RouterSubscriber): () => void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Enable scroll restoration behavior in the router\n *\n * @param savedScrollPositions Object that will manage positions, in case\n * it's being restored from sessionStorage\n * @param getScrollPosition Function to get the active Y scroll position\n * @param getKey Function to get the key to use for restoration\n */\n enableScrollRestoration(\n savedScrollPositions: Record,\n getScrollPosition: GetScrollPositionFunction,\n getKey?: GetScrollRestorationKeyFunction\n ): () => void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Navigate forward/backward in the history stack\n * @param to Delta to move in the history stack\n */\n navigate(to: number): Promise;\n\n /**\n * Navigate to the given path\n * @param to Path to navigate to\n * @param opts Navigation options (method, submission, etc.)\n */\n navigate(to: To | null, opts?: RouterNavigateOptions): Promise;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Trigger a fetcher load/submission\n *\n * @param key Fetcher key\n * @param routeId Route that owns the fetcher\n * @param href href to fetch\n * @param opts Fetcher options, (method, submission, etc.)\n */\n fetch(\n key: string,\n routeId: string,\n href: string | null,\n opts?: RouterFetchOptions\n ): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Trigger a revalidation of all current route loaders and fetcher loads\n */\n revalidate(): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Utility function to create an href for the given location\n * @param location\n */\n createHref(location: Location | URL): string;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Utility function to URL encode a destination path according to the internal\n * history implementation\n * @param to\n */\n encodeLocation(to: To): Path;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Get/create a fetcher for the given key\n * @param key\n */\n getFetcher(key: string): Fetcher;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Delete the fetcher for a given key\n * @param key\n */\n deleteFetcher(key: string): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Cleanup listeners and abort any in-progress loads\n */\n dispose(): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Get a navigation blocker\n * @param key The identifier for the blocker\n * @param fn The blocker function implementation\n */\n getBlocker(key: string, fn: BlockerFunction): Blocker;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Delete a navigation blocker\n * @param key The identifier for the blocker\n */\n deleteBlocker(key: string): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * HMR needs to pass in-flight route updates to React Router\n * TODO: Replace this with granular route update APIs (addRoute, updateRoute, deleteRoute)\n */\n _internalSetRoutes(routes: AgnosticRouteObject[]): void;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Internal fetch AbortControllers accessed by unit tests\n */\n _internalFetchControllers: Map;\n\n /**\n * @internal\n * PRIVATE - DO NOT USE\n *\n * Internal pending DeferredData instances accessed by unit tests\n */\n _internalActiveDeferreds: Map;\n}\n\n/**\n * State maintained internally by the router. During a navigation, all states\n * reflect the the \"old\" location unless otherwise noted.\n */\nexport interface RouterState {\n /**\n * The action of the most recent navigation\n */\n historyAction: HistoryAction;\n\n /**\n * The current location reflected by the router\n */\n location: Location;\n\n /**\n * The current set of route matches\n */\n matches: AgnosticDataRouteMatch[];\n\n /**\n * Tracks whether we've completed our initial data load\n */\n initialized: boolean;\n\n /**\n * Current scroll position we should start at for a new view\n * - number -> scroll position to restore to\n * - false -> do not restore scroll at all (used during submissions)\n * - null -> don't have a saved position, scroll to hash or top of page\n */\n restoreScrollPosition: number | false | null;\n\n /**\n * Indicate whether this navigation should skip resetting the scroll position\n * if we are unable to restore the scroll position\n */\n preventScrollReset: boolean;\n\n /**\n * Tracks the state of the current navigation\n */\n navigation: Navigation;\n\n /**\n * Tracks any in-progress revalidations\n */\n revalidation: RevalidationState;\n\n /**\n * Data from the loaders for the current matches\n */\n loaderData: RouteData;\n\n /**\n * Data from the action for the current matches\n */\n actionData: RouteData | null;\n\n /**\n * Errors caught from loaders for the current matches\n */\n errors: RouteData | null;\n\n /**\n * Map of current fetchers\n */\n fetchers: Map;\n\n /**\n * Map of current blockers\n */\n blockers: Map;\n}\n\n/**\n * Data that can be passed into hydrate a Router from SSR\n */\nexport type HydrationState = Partial<\n Pick\n>;\n\n/**\n * Future flags to toggle new feature behavior\n */\nexport interface FutureConfig {\n v7_fetcherPersist: boolean;\n v7_normalizeFormMethod: boolean;\n v7_prependBasename: boolean;\n}\n\n/**\n * Initialization options for createRouter\n */\nexport interface RouterInit {\n routes: AgnosticRouteObject[];\n history: History;\n basename?: string;\n /**\n * @deprecated Use `mapRouteProperties` instead\n */\n detectErrorBoundary?: DetectErrorBoundaryFunction;\n mapRouteProperties?: MapRoutePropertiesFunction;\n future?: Partial;\n hydrationData?: HydrationState;\n window?: Window;\n}\n\n/**\n * State returned from a server-side query() call\n */\nexport interface StaticHandlerContext {\n basename: Router[\"basename\"];\n location: RouterState[\"location\"];\n matches: RouterState[\"matches\"];\n loaderData: RouterState[\"loaderData\"];\n actionData: RouterState[\"actionData\"];\n errors: RouterState[\"errors\"];\n statusCode: number;\n loaderHeaders: Record;\n actionHeaders: Record;\n activeDeferreds: Record | null;\n _deepestRenderedBoundaryId?: string | null;\n}\n\n/**\n * A StaticHandler instance manages a singular SSR navigation/fetch event\n */\nexport interface StaticHandler {\n dataRoutes: AgnosticDataRouteObject[];\n query(\n request: Request,\n opts?: { requestContext?: unknown }\n ): Promise;\n queryRoute(\n request: Request,\n opts?: { routeId?: string; requestContext?: unknown }\n ): Promise;\n}\n\ntype ViewTransitionOpts = {\n currentLocation: Location;\n nextLocation: Location;\n};\n\n/**\n * Subscriber function signature for changes to router state\n */\nexport interface RouterSubscriber {\n (\n state: RouterState,\n opts: {\n deletedFetchers: string[];\n unstable_viewTransitionOpts?: ViewTransitionOpts;\n }\n ): void;\n}\n\n/**\n * Function signature for determining the key to be used in scroll restoration\n * for a given location\n */\nexport interface GetScrollRestorationKeyFunction {\n (location: Location, matches: UIMatch[]): string | null;\n}\n\n/**\n * Function signature for determining the current scroll position\n */\nexport interface GetScrollPositionFunction {\n (): number;\n}\n\nexport type RelativeRoutingType = \"route\" | \"path\";\n\n// Allowed for any navigation or fetch\ntype BaseNavigateOrFetchOptions = {\n preventScrollReset?: boolean;\n relative?: RelativeRoutingType;\n};\n\n// Only allowed for navigations\ntype BaseNavigateOptions = BaseNavigateOrFetchOptions & {\n replace?: boolean;\n state?: any;\n fromRouteId?: string;\n unstable_viewTransition?: boolean;\n};\n\n// Only allowed for submission navigations\ntype BaseSubmissionOptions = {\n formMethod?: HTMLFormMethod;\n formEncType?: FormEncType;\n} & (\n | { formData: FormData; body?: undefined }\n | { formData?: undefined; body: any }\n);\n\n/**\n * Options for a navigate() call for a normal (non-submission) navigation\n */\ntype LinkNavigateOptions = BaseNavigateOptions;\n\n/**\n * Options for a navigate() call for a submission navigation\n */\ntype SubmissionNavigateOptions = BaseNavigateOptions & BaseSubmissionOptions;\n\n/**\n * Options to pass to navigate() for a navigation\n */\nexport type RouterNavigateOptions =\n | LinkNavigateOptions\n | SubmissionNavigateOptions;\n\n/**\n * Options for a fetch() load\n */\ntype LoadFetchOptions = BaseNavigateOrFetchOptions;\n\n/**\n * Options for a fetch() submission\n */\ntype SubmitFetchOptions = BaseNavigateOrFetchOptions & BaseSubmissionOptions;\n\n/**\n * Options to pass to fetch()\n */\nexport type RouterFetchOptions = LoadFetchOptions | SubmitFetchOptions;\n\n/**\n * Potential states for state.navigation\n */\nexport type NavigationStates = {\n Idle: {\n state: \"idle\";\n location: undefined;\n formMethod: undefined;\n formAction: undefined;\n formEncType: undefined;\n formData: undefined;\n json: undefined;\n text: undefined;\n };\n Loading: {\n state: \"loading\";\n location: Location;\n formMethod: Submission[\"formMethod\"] | undefined;\n formAction: Submission[\"formAction\"] | undefined;\n formEncType: Submission[\"formEncType\"] | undefined;\n formData: Submission[\"formData\"] | undefined;\n json: Submission[\"json\"] | undefined;\n text: Submission[\"text\"] | undefined;\n };\n Submitting: {\n state: \"submitting\";\n location: Location;\n formMethod: Submission[\"formMethod\"];\n formAction: Submission[\"formAction\"];\n formEncType: Submission[\"formEncType\"];\n formData: Submission[\"formData\"];\n json: Submission[\"json\"];\n text: Submission[\"text\"];\n };\n};\n\nexport type Navigation = NavigationStates[keyof NavigationStates];\n\nexport type RevalidationState = \"idle\" | \"loading\";\n\n/**\n * Potential states for fetchers\n */\ntype FetcherStates = {\n Idle: {\n state: \"idle\";\n formMethod: undefined;\n formAction: undefined;\n formEncType: undefined;\n text: undefined;\n formData: undefined;\n json: undefined;\n data: TData | undefined;\n };\n Loading: {\n state: \"loading\";\n formMethod: Submission[\"formMethod\"] | undefined;\n formAction: Submission[\"formAction\"] | undefined;\n formEncType: Submission[\"formEncType\"] | undefined;\n text: Submission[\"text\"] | undefined;\n formData: Submission[\"formData\"] | undefined;\n json: Submission[\"json\"] | undefined;\n data: TData | undefined;\n };\n Submitting: {\n state: \"submitting\";\n formMethod: Submission[\"formMethod\"];\n formAction: Submission[\"formAction\"];\n formEncType: Submission[\"formEncType\"];\n text: Submission[\"text\"];\n formData: Submission[\"formData\"];\n json: Submission[\"json\"];\n data: TData | undefined;\n };\n};\n\nexport type Fetcher =\n FetcherStates[keyof FetcherStates];\n\ninterface BlockerBlocked {\n state: \"blocked\";\n reset(): void;\n proceed(): void;\n location: Location;\n}\n\ninterface BlockerUnblocked {\n state: \"unblocked\";\n reset: undefined;\n proceed: undefined;\n location: undefined;\n}\n\ninterface BlockerProceeding {\n state: \"proceeding\";\n reset: undefined;\n proceed: undefined;\n location: Location;\n}\n\nexport type Blocker = BlockerUnblocked | BlockerBlocked | BlockerProceeding;\n\nexport type BlockerFunction = (args: {\n currentLocation: Location;\n nextLocation: Location;\n historyAction: HistoryAction;\n}) => boolean;\n\ninterface ShortCircuitable {\n /**\n * startNavigation does not need to complete the navigation because we\n * redirected or got interrupted\n */\n shortCircuited?: boolean;\n}\n\ninterface HandleActionResult extends ShortCircuitable {\n /**\n * Error thrown from the current action, keyed by the route containing the\n * error boundary to render the error. To be committed to the state after\n * loaders have completed\n */\n pendingActionError?: RouteData;\n /**\n * Data returned from the current action, keyed by the route owning the action.\n * To be committed to the state after loaders have completed\n */\n pendingActionData?: RouteData;\n}\n\ninterface HandleLoadersResult extends ShortCircuitable {\n /**\n * loaderData returned from the current set of loaders\n */\n loaderData?: RouterState[\"loaderData\"];\n /**\n * errors thrown from the current set of loaders\n */\n errors?: RouterState[\"errors\"];\n}\n\n/**\n * Cached info for active fetcher.load() instances so they can participate\n * in revalidation\n */\ninterface FetchLoadMatch {\n routeId: string;\n path: string;\n}\n\n/**\n * Identified fetcher.load() calls that need to be revalidated\n */\ninterface RevalidatingFetcher extends FetchLoadMatch {\n key: string;\n match: AgnosticDataRouteMatch | null;\n matches: AgnosticDataRouteMatch[] | null;\n controller: AbortController | null;\n}\n\n/**\n * Wrapper object to allow us to throw any response out from callLoaderOrAction\n * for queryRouter while preserving whether or not it was thrown or returned\n * from the loader/action\n */\ninterface QueryRouteResponse {\n type: ResultType.data | ResultType.error;\n response: Response;\n}\n\nconst validMutationMethodsArr: MutationFormMethod[] = [\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n];\nconst validMutationMethods = new Set(\n validMutationMethodsArr\n);\n\nconst validRequestMethodsArr: FormMethod[] = [\n \"get\",\n ...validMutationMethodsArr,\n];\nconst validRequestMethods = new Set(validRequestMethodsArr);\n\nconst redirectStatusCodes = new Set([301, 302, 303, 307, 308]);\nconst redirectPreserveMethodStatusCodes = new Set([307, 308]);\n\nexport const IDLE_NAVIGATION: NavigationStates[\"Idle\"] = {\n state: \"idle\",\n location: undefined,\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n};\n\nexport const IDLE_FETCHER: FetcherStates[\"Idle\"] = {\n state: \"idle\",\n data: undefined,\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n};\n\nexport const IDLE_BLOCKER: BlockerUnblocked = {\n state: \"unblocked\",\n proceed: undefined,\n reset: undefined,\n location: undefined,\n};\n\nconst ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\\/\\/)/i;\n\nconst defaultMapRouteProperties: MapRoutePropertiesFunction = (route) => ({\n hasErrorBoundary: Boolean(route.hasErrorBoundary),\n});\n\nconst TRANSITIONS_STORAGE_KEY = \"remix-router-transitions\";\n\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region createRouter\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * Create a router and listen to history POP navigations\n */\nexport function createRouter(init: RouterInit): Router {\n const routerWindow = init.window\n ? init.window\n : typeof window !== \"undefined\"\n ? window\n : undefined;\n const isBrowser =\n typeof routerWindow !== \"undefined\" &&\n typeof routerWindow.document !== \"undefined\" &&\n typeof routerWindow.document.createElement !== \"undefined\";\n const isServer = !isBrowser;\n\n invariant(\n init.routes.length > 0,\n \"You must provide a non-empty routes array to createRouter\"\n );\n\n let mapRouteProperties: MapRoutePropertiesFunction;\n if (init.mapRouteProperties) {\n mapRouteProperties = init.mapRouteProperties;\n } else if (init.detectErrorBoundary) {\n // If they are still using the deprecated version, wrap it with the new API\n let detectErrorBoundary = init.detectErrorBoundary;\n mapRouteProperties = (route) => ({\n hasErrorBoundary: detectErrorBoundary(route),\n });\n } else {\n mapRouteProperties = defaultMapRouteProperties;\n }\n\n // Routes keyed by ID\n let manifest: RouteManifest = {};\n // Routes in tree format for matching\n let dataRoutes = convertRoutesToDataRoutes(\n init.routes,\n mapRouteProperties,\n undefined,\n manifest\n );\n let inFlightDataRoutes: AgnosticDataRouteObject[] | undefined;\n let basename = init.basename || \"/\";\n // Config driven behavior flags\n let future: FutureConfig = {\n v7_fetcherPersist: false,\n v7_normalizeFormMethod: false,\n v7_prependBasename: false,\n ...init.future,\n };\n // Cleanup function for history\n let unlistenHistory: (() => void) | null = null;\n // Externally-provided functions to call on all state changes\n let subscribers = new Set();\n // Externally-provided object to hold scroll restoration locations during routing\n let savedScrollPositions: Record | null = null;\n // Externally-provided function to get scroll restoration keys\n let getScrollRestorationKey: GetScrollRestorationKeyFunction | null = null;\n // Externally-provided function to get current scroll position\n let getScrollPosition: GetScrollPositionFunction | null = null;\n // One-time flag to control the initial hydration scroll restoration. Because\n // we don't get the saved positions from until _after_\n // the initial render, we need to manually trigger a separate updateState to\n // send along the restoreScrollPosition\n // Set to true if we have `hydrationData` since we assume we were SSR'd and that\n // SSR did the initial scroll restoration.\n let initialScrollRestored = init.hydrationData != null;\n\n let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);\n let initialErrors: RouteData | null = null;\n\n if (initialMatches == null) {\n // If we do not match a user-provided-route, fall back to the root\n // to allow the error boundary to take over\n let error = getInternalRouterError(404, {\n pathname: init.history.location.pathname,\n });\n let { matches, route } = getShortCircuitMatches(dataRoutes);\n initialMatches = matches;\n initialErrors = { [route.id]: error };\n }\n\n let initialized =\n // All initialMatches need to be loaded before we're ready. If we have lazy\n // functions around still then we'll need to run them in initialize()\n !initialMatches.some((m) => m.route.lazy) &&\n // And we have to either have no loaders or have been provided hydrationData\n (!initialMatches.some((m) => m.route.loader) || init.hydrationData != null);\n\n let router: Router;\n let state: RouterState = {\n historyAction: init.history.action,\n location: init.history.location,\n matches: initialMatches,\n initialized,\n navigation: IDLE_NAVIGATION,\n // Don't restore on initial updateState() if we were SSR'd\n restoreScrollPosition: init.hydrationData != null ? false : null,\n preventScrollReset: false,\n revalidation: \"idle\",\n loaderData: (init.hydrationData && init.hydrationData.loaderData) || {},\n actionData: (init.hydrationData && init.hydrationData.actionData) || null,\n errors: (init.hydrationData && init.hydrationData.errors) || initialErrors,\n fetchers: new Map(),\n blockers: new Map(),\n };\n\n // -- Stateful internal variables to manage navigations --\n // Current navigation in progress (to be committed in completeNavigation)\n let pendingAction: HistoryAction = HistoryAction.Pop;\n\n // Should the current navigation prevent the scroll reset if scroll cannot\n // be restored?\n let pendingPreventScrollReset = false;\n\n // AbortController for the active navigation\n let pendingNavigationController: AbortController | null;\n\n // Should the current navigation enable document.startViewTransition?\n let pendingViewTransitionEnabled = false;\n\n // Store applied view transitions so we can apply them on POP\n let appliedViewTransitions: Map> = new Map<\n string,\n Set\n >();\n\n // Cleanup function for persisting applied transitions to sessionStorage\n let removePageHideEventListener: (() => void) | null = null;\n\n // We use this to avoid touching history in completeNavigation if a\n // revalidation is entirely uninterrupted\n let isUninterruptedRevalidation = false;\n\n // Use this internal flag to force revalidation of all loaders:\n // - submissions (completed or interrupted)\n // - useRevalidator()\n // - X-Remix-Revalidate (from redirect)\n let isRevalidationRequired = false;\n\n // Use this internal array to capture routes that require revalidation due\n // to a cancelled deferred on action submission\n let cancelledDeferredRoutes: string[] = [];\n\n // Use this internal array to capture fetcher loads that were cancelled by an\n // action navigation and require revalidation\n let cancelledFetcherLoads: string[] = [];\n\n // AbortControllers for any in-flight fetchers\n let fetchControllers = new Map();\n\n // Track loads based on the order in which they started\n let incrementingLoadId = 0;\n\n // Track the outstanding pending navigation data load to be compared against\n // the globally incrementing load when a fetcher load lands after a completed\n // navigation\n let pendingNavigationLoadId = -1;\n\n // Fetchers that triggered data reloads as a result of their actions\n let fetchReloadIds = new Map();\n\n // Fetchers that triggered redirect navigations\n let fetchRedirectIds = new Set();\n\n // Most recent href/match for fetcher.load calls for fetchers\n let fetchLoadMatches = new Map();\n\n // Ref-count mounted fetchers so we know when it's ok to clean them up\n let activeFetchers = new Map();\n\n // Fetchers that have requested a delete when using v7_fetcherPersist,\n // they'll be officially removed after they return to idle\n let deletedFetchers = new Set();\n\n // Store DeferredData instances for active route matches. When a\n // route loader returns defer() we stick one in here. Then, when a nested\n // promise resolves we update loaderData. If a new navigation starts we\n // cancel active deferreds for eliminated routes.\n let activeDeferreds = new Map();\n\n // Store blocker functions in a separate Map outside of router state since\n // we don't need to update UI state if they change\n let blockerFunctions = new Map();\n\n // Flag to ignore the next history update, so we can revert the URL change on\n // a POP navigation that was blocked by the user without touching router state\n let ignoreNextHistoryUpdate = false;\n\n // Initialize the router, all side effects should be kicked off from here.\n // Implemented as a Fluent API for ease of:\n // let router = createRouter(init).initialize();\n function initialize() {\n // If history informs us of a POP navigation, start the navigation but do not update\n // state. We'll update our own state once the navigation completes\n unlistenHistory = init.history.listen(\n ({ action: historyAction, location, delta }) => {\n // Ignore this event if it was just us resetting the URL from a\n // blocked POP navigation\n if (ignoreNextHistoryUpdate) {\n ignoreNextHistoryUpdate = false;\n return;\n }\n\n warning(\n blockerFunctions.size === 0 || delta != null,\n \"You are trying to use a blocker on a POP navigation to a location \" +\n \"that was not created by @remix-run/router. This will fail silently in \" +\n \"production. This can happen if you are navigating outside the router \" +\n \"via `window.history.pushState`/`window.location.hash` instead of using \" +\n \"router navigation APIs. This can also happen if you are using \" +\n \"createHashRouter and the user manually changes the URL.\"\n );\n\n let blockerKey = shouldBlockNavigation({\n currentLocation: state.location,\n nextLocation: location,\n historyAction,\n });\n\n if (blockerKey && delta != null) {\n // Restore the URL to match the current UI, but don't update router state\n ignoreNextHistoryUpdate = true;\n init.history.go(delta * -1);\n\n // Put the blocker into a blocked state\n updateBlocker(blockerKey, {\n state: \"blocked\",\n location,\n proceed() {\n updateBlocker(blockerKey!, {\n state: \"proceeding\",\n proceed: undefined,\n reset: undefined,\n location,\n });\n // Re-do the same POP navigation we just blocked\n init.history.go(delta);\n },\n reset() {\n let blockers = new Map(state.blockers);\n blockers.set(blockerKey!, IDLE_BLOCKER);\n updateState({ blockers });\n },\n });\n return;\n }\n\n return startNavigation(historyAction, location);\n }\n );\n\n if (isBrowser) {\n // FIXME: This feels gross. How can we cleanup the lines between\n // scrollRestoration/appliedTransitions persistance?\n restoreAppliedTransitions(routerWindow, appliedViewTransitions);\n let _saveAppliedTransitions = () =>\n persistAppliedTransitions(routerWindow, appliedViewTransitions);\n routerWindow.addEventListener(\"pagehide\", _saveAppliedTransitions);\n removePageHideEventListener = () =>\n routerWindow.removeEventListener(\"pagehide\", _saveAppliedTransitions);\n }\n\n // Kick off initial data load if needed. Use Pop to avoid modifying history\n // Note we don't do any handling of lazy here. For SPA's it'll get handled\n // in the normal navigation flow. For SSR it's expected that lazy modules are\n // resolved prior to router creation since we can't go into a fallbackElement\n // UI for SSR'd apps\n if (!state.initialized) {\n startNavigation(HistoryAction.Pop, state.location);\n }\n\n return router;\n }\n\n // Clean up a router and it's side effects\n function dispose() {\n if (unlistenHistory) {\n unlistenHistory();\n }\n if (removePageHideEventListener) {\n removePageHideEventListener();\n }\n subscribers.clear();\n pendingNavigationController && pendingNavigationController.abort();\n state.fetchers.forEach((_, key) => deleteFetcher(key));\n state.blockers.forEach((_, key) => deleteBlocker(key));\n }\n\n // Subscribe to state updates for the router\n function subscribe(fn: RouterSubscriber) {\n subscribers.add(fn);\n return () => subscribers.delete(fn);\n }\n\n // Update our state and notify the calling context of the change\n function updateState(\n newState: Partial,\n viewTransitionOpts?: ViewTransitionOpts\n ): void {\n state = {\n ...state,\n ...newState,\n };\n\n // Prep fetcher cleanup so we can tell the UI which fetcher data entries\n // can be removed\n let completedFetchers: string[] = [];\n let deletedFetchersKeys: string[] = [];\n\n if (future.v7_fetcherPersist) {\n state.fetchers.forEach((fetcher, key) => {\n if (fetcher.state === \"idle\") {\n if (deletedFetchers.has(key)) {\n // Unmounted from the UI and can be totally removed\n deletedFetchersKeys.push(key);\n } else {\n // Returned to idle but still mounted in the UI, so semi-remains for\n // revalidations and such\n completedFetchers.push(key);\n }\n }\n });\n }\n\n subscribers.forEach((subscriber) =>\n subscriber(state, {\n deletedFetchers: deletedFetchersKeys,\n unstable_viewTransitionOpts: viewTransitionOpts,\n })\n );\n\n // Remove idle fetchers from state since we only care about in-flight fetchers.\n if (future.v7_fetcherPersist) {\n completedFetchers.forEach((key) => state.fetchers.delete(key));\n deletedFetchersKeys.forEach((key) => deleteFetcher(key));\n }\n }\n\n // Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION\n // and setting state.[historyAction/location/matches] to the new route.\n // - Location is a required param\n // - Navigation will always be set to IDLE_NAVIGATION\n // - Can pass any other state in newState\n function completeNavigation(\n location: Location,\n newState: Partial>\n ): void {\n // Deduce if we're in a loading/actionReload state:\n // - We have committed actionData in the store\n // - The current navigation was a mutation submission\n // - We're past the submitting state and into the loading state\n // - The location being loaded is not the result of a redirect\n let isActionReload =\n state.actionData != null &&\n state.navigation.formMethod != null &&\n isMutationMethod(state.navigation.formMethod) &&\n state.navigation.state === \"loading\" &&\n location.state?._isRedirect !== true;\n\n let actionData: RouteData | null;\n if (newState.actionData) {\n if (Object.keys(newState.actionData).length > 0) {\n actionData = newState.actionData;\n } else {\n // Empty actionData -> clear prior actionData due to an action error\n actionData = null;\n }\n } else if (isActionReload) {\n // Keep the current data if we're wrapping up the action reload\n actionData = state.actionData;\n } else {\n // Clear actionData on any other completed navigations\n actionData = null;\n }\n\n // Always preserve any existing loaderData from re-used routes\n let loaderData = newState.loaderData\n ? mergeLoaderData(\n state.loaderData,\n newState.loaderData,\n newState.matches || [],\n newState.errors\n )\n : state.loaderData;\n\n // On a successful navigation we can assume we got through all blockers\n // so we can start fresh\n let blockers = state.blockers;\n if (blockers.size > 0) {\n blockers = new Map(blockers);\n blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));\n }\n\n // Always respect the user flag. Otherwise don't reset on mutation\n // submission navigations unless they redirect\n let preventScrollReset =\n pendingPreventScrollReset === true ||\n (state.navigation.formMethod != null &&\n isMutationMethod(state.navigation.formMethod) &&\n location.state?._isRedirect !== true);\n\n if (inFlightDataRoutes) {\n dataRoutes = inFlightDataRoutes;\n inFlightDataRoutes = undefined;\n }\n\n if (isUninterruptedRevalidation) {\n // If this was an uninterrupted revalidation then do not touch history\n } else if (pendingAction === HistoryAction.Pop) {\n // Do nothing for POP - URL has already been updated\n } else if (pendingAction === HistoryAction.Push) {\n init.history.push(location, location.state);\n } else if (pendingAction === HistoryAction.Replace) {\n init.history.replace(location, location.state);\n }\n\n let viewTransitionOpts: ViewTransitionOpts | undefined;\n\n // On POP, enable transitions if they were enabled on the original navigation\n if (pendingAction === HistoryAction.Pop) {\n // Forward takes precedence so they behave like the original navigation\n let priorPaths = appliedViewTransitions.get(state.location.pathname);\n if (priorPaths && priorPaths.has(location.pathname)) {\n viewTransitionOpts = {\n currentLocation: state.location,\n nextLocation: location,\n };\n } else if (appliedViewTransitions.has(location.pathname)) {\n // If we don't have a previous forward nav, assume we're popping back to\n // the new location and enable if that location previously enabled\n viewTransitionOpts = {\n currentLocation: location,\n nextLocation: state.location,\n };\n }\n } else if (pendingViewTransitionEnabled) {\n // Store the applied transition on PUSH/REPLACE\n let toPaths = appliedViewTransitions.get(state.location.pathname);\n if (toPaths) {\n toPaths.add(location.pathname);\n } else {\n toPaths = new Set([location.pathname]);\n appliedViewTransitions.set(state.location.pathname, toPaths);\n }\n viewTransitionOpts = {\n currentLocation: state.location,\n nextLocation: location,\n };\n }\n\n updateState(\n {\n ...newState, // matches, errors, fetchers go through as-is\n actionData,\n loaderData,\n historyAction: pendingAction,\n location,\n initialized: true,\n navigation: IDLE_NAVIGATION,\n revalidation: \"idle\",\n restoreScrollPosition: getSavedScrollPosition(\n location,\n newState.matches || state.matches\n ),\n preventScrollReset,\n blockers,\n },\n viewTransitionOpts\n );\n\n // Reset stateful navigation vars\n pendingAction = HistoryAction.Pop;\n pendingPreventScrollReset = false;\n pendingViewTransitionEnabled = false;\n isUninterruptedRevalidation = false;\n isRevalidationRequired = false;\n cancelledDeferredRoutes = [];\n cancelledFetcherLoads = [];\n }\n\n // Trigger a navigation event, which can either be a numerical POP or a PUSH\n // replace with an optional submission\n async function navigate(\n to: number | To | null,\n opts?: RouterNavigateOptions\n ): Promise {\n if (typeof to === \"number\") {\n init.history.go(to);\n return;\n }\n\n let normalizedPath = normalizeTo(\n state.location,\n state.matches,\n basename,\n future.v7_prependBasename,\n to,\n opts?.fromRouteId,\n opts?.relative\n );\n let { path, submission, error } = normalizeNavigateOptions(\n future.v7_normalizeFormMethod,\n false,\n normalizedPath,\n opts\n );\n\n let currentLocation = state.location;\n let nextLocation = createLocation(state.location, path, opts && opts.state);\n\n // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded\n // URL from window.location, so we need to encode it here so the behavior\n // remains the same as POP and non-data-router usages. new URL() does all\n // the same encoding we'd get from a history.pushState/window.location read\n // without having to touch history\n nextLocation = {\n ...nextLocation,\n ...init.history.encodeLocation(nextLocation),\n };\n\n let userReplace = opts && opts.replace != null ? opts.replace : undefined;\n\n let historyAction = HistoryAction.Push;\n\n if (userReplace === true) {\n historyAction = HistoryAction.Replace;\n } else if (userReplace === false) {\n // no-op\n } else if (\n submission != null &&\n isMutationMethod(submission.formMethod) &&\n submission.formAction === state.location.pathname + state.location.search\n ) {\n // By default on submissions to the current location we REPLACE so that\n // users don't have to double-click the back button to get to the prior\n // location. If the user redirects to a different location from the\n // action/loader this will be ignored and the redirect will be a PUSH\n historyAction = HistoryAction.Replace;\n }\n\n let preventScrollReset =\n opts && \"preventScrollReset\" in opts\n ? opts.preventScrollReset === true\n : undefined;\n\n let blockerKey = shouldBlockNavigation({\n currentLocation,\n nextLocation,\n historyAction,\n });\n\n if (blockerKey) {\n // Put the blocker into a blocked state\n updateBlocker(blockerKey, {\n state: \"blocked\",\n location: nextLocation,\n proceed() {\n updateBlocker(blockerKey!, {\n state: \"proceeding\",\n proceed: undefined,\n reset: undefined,\n location: nextLocation,\n });\n // Send the same navigation through\n navigate(to, opts);\n },\n reset() {\n let blockers = new Map(state.blockers);\n blockers.set(blockerKey!, IDLE_BLOCKER);\n updateState({ blockers });\n },\n });\n return;\n }\n\n return await startNavigation(historyAction, nextLocation, {\n submission,\n // Send through the formData serialization error if we have one so we can\n // render at the right error boundary after we match routes\n pendingError: error,\n preventScrollReset,\n replace: opts && opts.replace,\n enableViewTransition: opts && opts.unstable_viewTransition,\n });\n }\n\n // Revalidate all current loaders. If a navigation is in progress or if this\n // is interrupted by a navigation, allow this to \"succeed\" by calling all\n // loaders during the next loader round\n function revalidate() {\n interruptActiveLoads();\n updateState({ revalidation: \"loading\" });\n\n // If we're currently submitting an action, we don't need to start a new\n // navigation, we'll just let the follow up loader execution call all loaders\n if (state.navigation.state === \"submitting\") {\n return;\n }\n\n // If we're currently in an idle state, start a new navigation for the current\n // action/location and mark it as uninterrupted, which will skip the history\n // update in completeNavigation\n if (state.navigation.state === \"idle\") {\n startNavigation(state.historyAction, state.location, {\n startUninterruptedRevalidation: true,\n });\n return;\n }\n\n // Otherwise, if we're currently in a loading state, just start a new\n // navigation to the navigation.location but do not trigger an uninterrupted\n // revalidation so that history correctly updates once the navigation completes\n startNavigation(\n pendingAction || state.historyAction,\n state.navigation.location,\n { overrideNavigation: state.navigation }\n );\n }\n\n // Start a navigation to the given action/location. Can optionally provide a\n // overrideNavigation which will override the normalLoad in the case of a redirect\n // navigation\n async function startNavigation(\n historyAction: HistoryAction,\n location: Location,\n opts?: {\n submission?: Submission;\n fetcherSubmission?: Submission;\n overrideNavigation?: Navigation;\n pendingError?: ErrorResponseImpl;\n startUninterruptedRevalidation?: boolean;\n preventScrollReset?: boolean;\n replace?: boolean;\n enableViewTransition?: boolean;\n }\n ): Promise {\n // Abort any in-progress navigations and start a new one. Unset any ongoing\n // uninterrupted revalidations unless told otherwise, since we want this\n // new navigation to update history normally\n pendingNavigationController && pendingNavigationController.abort();\n pendingNavigationController = null;\n pendingAction = historyAction;\n isUninterruptedRevalidation =\n (opts && opts.startUninterruptedRevalidation) === true;\n\n // Save the current scroll position every time we start a new navigation,\n // and track whether we should reset scroll on completion\n saveScrollPosition(state.location, state.matches);\n pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;\n\n pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;\n\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let loadingNavigation = opts && opts.overrideNavigation;\n let matches = matchRoutes(routesToUse, location, basename);\n\n // Short circuit with a 404 on the root error boundary if we match nothing\n if (!matches) {\n let error = getInternalRouterError(404, { pathname: location.pathname });\n let { matches: notFoundMatches, route } =\n getShortCircuitMatches(routesToUse);\n // Cancel all pending deferred on 404s since we don't keep any routes\n cancelActiveDeferreds();\n completeNavigation(location, {\n matches: notFoundMatches,\n loaderData: {},\n errors: {\n [route.id]: error,\n },\n });\n return;\n }\n\n // Short circuit if it's only a hash change and not a revalidation or\n // mutation submission.\n //\n // Ignore on initial page loads because since the initial load will always\n // be \"same hash\". For example, on /page#hash and submit a \n // which will default to a navigation to /page\n if (\n state.initialized &&\n !isRevalidationRequired &&\n isHashChangeOnly(state.location, location) &&\n !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))\n ) {\n completeNavigation(location, { matches });\n return;\n }\n\n // Create a controller/Request for this navigation\n pendingNavigationController = new AbortController();\n let request = createClientSideRequest(\n init.history,\n location,\n pendingNavigationController.signal,\n opts && opts.submission\n );\n let pendingActionData: RouteData | undefined;\n let pendingError: RouteData | undefined;\n\n if (opts && opts.pendingError) {\n // If we have a pendingError, it means the user attempted a GET submission\n // with binary FormData so assign here and skip to handleLoaders. That\n // way we handle calling loaders above the boundary etc. It's not really\n // different from an actionError in that sense.\n pendingError = {\n [findNearestBoundary(matches).route.id]: opts.pendingError,\n };\n } else if (\n opts &&\n opts.submission &&\n isMutationMethod(opts.submission.formMethod)\n ) {\n // Call action if we received an action submission\n let actionOutput = await handleAction(\n request,\n location,\n opts.submission,\n matches,\n { replace: opts.replace }\n );\n\n if (actionOutput.shortCircuited) {\n return;\n }\n\n pendingActionData = actionOutput.pendingActionData;\n pendingError = actionOutput.pendingActionError;\n loadingNavigation = getLoadingNavigation(location, opts.submission);\n\n // Create a GET request for the loaders\n request = new Request(request.url, { signal: request.signal });\n }\n\n // Call loaders\n let { shortCircuited, loaderData, errors } = await handleLoaders(\n request,\n location,\n matches,\n loadingNavigation,\n opts && opts.submission,\n opts && opts.fetcherSubmission,\n opts && opts.replace,\n pendingActionData,\n pendingError\n );\n\n if (shortCircuited) {\n return;\n }\n\n // Clean up now that the action/loaders have completed. Don't clean up if\n // we short circuited because pendingNavigationController will have already\n // been assigned to a new controller for the next navigation\n pendingNavigationController = null;\n\n completeNavigation(location, {\n matches,\n ...(pendingActionData ? { actionData: pendingActionData } : {}),\n loaderData,\n errors,\n });\n }\n\n // Call the action matched by the leaf route for this navigation and handle\n // redirects/errors\n async function handleAction(\n request: Request,\n location: Location,\n submission: Submission,\n matches: AgnosticDataRouteMatch[],\n opts: { replace?: boolean } = {}\n ): Promise {\n interruptActiveLoads();\n\n // Put us in a submitting state\n let navigation = getSubmittingNavigation(location, submission);\n updateState({ navigation });\n\n // Call our action and get the result\n let result: DataResult;\n let actionMatch = getTargetMatch(matches, location);\n\n if (!actionMatch.route.action && !actionMatch.route.lazy) {\n result = {\n type: ResultType.error,\n error: getInternalRouterError(405, {\n method: request.method,\n pathname: location.pathname,\n routeId: actionMatch.route.id,\n }),\n };\n } else {\n result = await callLoaderOrAction(\n \"action\",\n request,\n actionMatch,\n matches,\n manifest,\n mapRouteProperties,\n basename\n );\n\n if (request.signal.aborted) {\n return { shortCircuited: true };\n }\n }\n\n if (isRedirectResult(result)) {\n let replace: boolean;\n if (opts && opts.replace != null) {\n replace = opts.replace;\n } else {\n // If the user didn't explicity indicate replace behavior, replace if\n // we redirected to the exact same location we're currently at to avoid\n // double back-buttons\n replace =\n result.location === state.location.pathname + state.location.search;\n }\n await startRedirectNavigation(state, result, { submission, replace });\n return { shortCircuited: true };\n }\n\n if (isErrorResult(result)) {\n // Store off the pending error - we use it to determine which loaders\n // to call and will commit it when we complete the navigation\n let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);\n\n // By default, all submissions are REPLACE navigations, but if the\n // action threw an error that'll be rendered in an errorElement, we fall\n // back to PUSH so that the user can use the back button to get back to\n // the pre-submission form location to try again\n if ((opts && opts.replace) !== true) {\n pendingAction = HistoryAction.Push;\n }\n\n return {\n // Send back an empty object we can use to clear out any prior actionData\n pendingActionData: {},\n pendingActionError: { [boundaryMatch.route.id]: result.error },\n };\n }\n\n if (isDeferredResult(result)) {\n throw getInternalRouterError(400, { type: \"defer-action\" });\n }\n\n return {\n pendingActionData: { [actionMatch.route.id]: result.data },\n };\n }\n\n // Call all applicable loaders for the given matches, handling redirects,\n // errors, etc.\n async function handleLoaders(\n request: Request,\n location: Location,\n matches: AgnosticDataRouteMatch[],\n overrideNavigation?: Navigation,\n submission?: Submission,\n fetcherSubmission?: Submission,\n replace?: boolean,\n pendingActionData?: RouteData,\n pendingError?: RouteData\n ): Promise {\n // Figure out the right navigation we want to use for data loading\n let loadingNavigation =\n overrideNavigation || getLoadingNavigation(location, submission);\n\n // If this was a redirect from an action we don't have a \"submission\" but\n // we have it on the loading navigation so use that if available\n let activeSubmission =\n submission ||\n fetcherSubmission ||\n getSubmissionFromNavigation(loadingNavigation);\n\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(\n init.history,\n state,\n matches,\n activeSubmission,\n location,\n isRevalidationRequired,\n cancelledDeferredRoutes,\n cancelledFetcherLoads,\n fetchLoadMatches,\n fetchRedirectIds,\n routesToUse,\n basename,\n pendingActionData,\n pendingError\n );\n\n // Cancel pending deferreds for no-longer-matched routes or routes we're\n // about to reload. Note that if this is an action reload we would have\n // already cancelled all pending deferreds so this would be a no-op\n cancelActiveDeferreds(\n (routeId) =>\n !(matches && matches.some((m) => m.route.id === routeId)) ||\n (matchesToLoad && matchesToLoad.some((m) => m.route.id === routeId))\n );\n\n pendingNavigationLoadId = ++incrementingLoadId;\n\n // Short circuit if we have no loaders to run\n if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {\n let updatedFetchers = markFetchRedirectsDone();\n completeNavigation(location, {\n matches,\n loaderData: {},\n // Commit pending error if we're short circuiting\n errors: pendingError || null,\n ...(pendingActionData ? { actionData: pendingActionData } : {}),\n ...(updatedFetchers ? { fetchers: new Map(state.fetchers) } : {}),\n });\n return { shortCircuited: true };\n }\n\n // If this is an uninterrupted revalidation, we remain in our current idle\n // state. If not, we need to switch to our loading state and load data,\n // preserving any new action data or existing action data (in the case of\n // a revalidation interrupting an actionReload)\n if (!isUninterruptedRevalidation) {\n revalidatingFetchers.forEach((rf) => {\n let fetcher = state.fetchers.get(rf.key);\n let revalidatingFetcher = getLoadingFetcher(\n undefined,\n fetcher ? fetcher.data : undefined\n );\n state.fetchers.set(rf.key, revalidatingFetcher);\n });\n let actionData = pendingActionData || state.actionData;\n updateState({\n navigation: loadingNavigation,\n ...(actionData\n ? Object.keys(actionData).length === 0\n ? { actionData: null }\n : { actionData }\n : {}),\n ...(revalidatingFetchers.length > 0\n ? { fetchers: new Map(state.fetchers) }\n : {}),\n });\n }\n\n revalidatingFetchers.forEach((rf) => {\n if (fetchControllers.has(rf.key)) {\n abortFetcher(rf.key);\n }\n if (rf.controller) {\n // Fetchers use an independent AbortController so that aborting a fetcher\n // (via deleteFetcher) does not abort the triggering navigation that\n // triggered the revalidation\n fetchControllers.set(rf.key, rf.controller);\n }\n });\n\n // Proxy navigation abort through to revalidation fetchers\n let abortPendingFetchRevalidations = () =>\n revalidatingFetchers.forEach((f) => abortFetcher(f.key));\n if (pendingNavigationController) {\n pendingNavigationController.signal.addEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n }\n\n let { results, loaderResults, fetcherResults } =\n await callLoadersAndMaybeResolveData(\n state.matches,\n matches,\n matchesToLoad,\n revalidatingFetchers,\n request\n );\n\n if (request.signal.aborted) {\n return { shortCircuited: true };\n }\n\n // Clean up _after_ loaders have completed. Don't clean up if we short\n // circuited because fetchControllers would have been aborted and\n // reassigned to new controllers for the next navigation\n if (pendingNavigationController) {\n pendingNavigationController.signal.removeEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n }\n revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));\n\n // If any loaders returned a redirect Response, start a new REPLACE navigation\n let redirect = findRedirect(results);\n if (redirect) {\n if (redirect.idx >= matchesToLoad.length) {\n // If this redirect came from a fetcher make sure we mark it in\n // fetchRedirectIds so it doesn't get revalidated on the next set of\n // loader executions\n let fetcherKey =\n revalidatingFetchers[redirect.idx - matchesToLoad.length].key;\n fetchRedirectIds.add(fetcherKey);\n }\n await startRedirectNavigation(state, redirect.result, { replace });\n return { shortCircuited: true };\n }\n\n // Process and commit output from loaders\n let { loaderData, errors } = processLoaderData(\n state,\n matches,\n matchesToLoad,\n loaderResults,\n pendingError,\n revalidatingFetchers,\n fetcherResults,\n activeDeferreds\n );\n\n // Wire up subscribers to update loaderData as promises settle\n activeDeferreds.forEach((deferredData, routeId) => {\n deferredData.subscribe((aborted) => {\n // Note: No need to updateState here since the TrackedPromise on\n // loaderData is stable across resolve/reject\n // Remove this instance if we were aborted or if promises have settled\n if (aborted || deferredData.done) {\n activeDeferreds.delete(routeId);\n }\n });\n });\n\n let updatedFetchers = markFetchRedirectsDone();\n let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);\n let shouldUpdateFetchers =\n updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;\n\n return {\n loaderData,\n errors,\n ...(shouldUpdateFetchers ? { fetchers: new Map(state.fetchers) } : {}),\n };\n }\n\n function getFetcher(key: string): Fetcher {\n if (future.v7_fetcherPersist) {\n activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);\n // If this fetcher was previously marked for deletion, unmark it since we\n // have a new instance\n if (deletedFetchers.has(key)) {\n deletedFetchers.delete(key);\n }\n }\n return state.fetchers.get(key) || IDLE_FETCHER;\n }\n\n // Trigger a fetcher load/submit for the given fetcher key\n function fetch(\n key: string,\n routeId: string,\n href: string | null,\n opts?: RouterFetchOptions\n ) {\n if (isServer) {\n throw new Error(\n \"router.fetch() was called during the server render, but it shouldn't be. \" +\n \"You are likely calling a useFetcher() method in the body of your component. \" +\n \"Try moving it to a useEffect or a callback.\"\n );\n }\n\n if (fetchControllers.has(key)) abortFetcher(key);\n\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let normalizedPath = normalizeTo(\n state.location,\n state.matches,\n basename,\n future.v7_prependBasename,\n href,\n routeId,\n opts?.relative\n );\n let matches = matchRoutes(routesToUse, normalizedPath, basename);\n\n if (!matches) {\n setFetcherError(\n key,\n routeId,\n getInternalRouterError(404, { pathname: normalizedPath })\n );\n return;\n }\n\n let { path, submission, error } = normalizeNavigateOptions(\n future.v7_normalizeFormMethod,\n true,\n normalizedPath,\n opts\n );\n\n if (error) {\n setFetcherError(key, routeId, error);\n return;\n }\n\n let match = getTargetMatch(matches, path);\n\n pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;\n\n if (submission && isMutationMethod(submission.formMethod)) {\n handleFetcherAction(key, routeId, path, match, matches, submission);\n return;\n }\n\n // Store off the match so we can call it's shouldRevalidate on subsequent\n // revalidations\n fetchLoadMatches.set(key, { routeId, path });\n handleFetcherLoader(key, routeId, path, match, matches, submission);\n }\n\n // Call the action for the matched fetcher.submit(), and then handle redirects,\n // errors, and revalidation\n async function handleFetcherAction(\n key: string,\n routeId: string,\n path: string,\n match: AgnosticDataRouteMatch,\n requestMatches: AgnosticDataRouteMatch[],\n submission: Submission\n ) {\n interruptActiveLoads();\n fetchLoadMatches.delete(key);\n\n if (!match.route.action && !match.route.lazy) {\n let error = getInternalRouterError(405, {\n method: submission.formMethod,\n pathname: path,\n routeId: routeId,\n });\n setFetcherError(key, routeId, error);\n return;\n }\n\n // Put this fetcher into it's submitting state\n let existingFetcher = state.fetchers.get(key);\n let fetcher = getSubmittingFetcher(submission, existingFetcher);\n state.fetchers.set(key, fetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n\n // Call the action for the fetcher\n let abortController = new AbortController();\n let fetchRequest = createClientSideRequest(\n init.history,\n path,\n abortController.signal,\n submission\n );\n fetchControllers.set(key, abortController);\n\n let originatingLoadId = incrementingLoadId;\n let actionResult = await callLoaderOrAction(\n \"action\",\n fetchRequest,\n match,\n requestMatches,\n manifest,\n mapRouteProperties,\n basename\n );\n\n if (fetchRequest.signal.aborted) {\n // We can delete this so long as we weren't aborted by our own fetcher\n // re-submit which would have put _new_ controller is in fetchControllers\n if (fetchControllers.get(key) === abortController) {\n fetchControllers.delete(key);\n }\n return;\n }\n\n if (deletedFetchers.has(key)) {\n state.fetchers.set(key, getDoneFetcher(undefined));\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n }\n\n if (isRedirectResult(actionResult)) {\n fetchControllers.delete(key);\n if (pendingNavigationLoadId > originatingLoadId) {\n // A new navigation was kicked off after our action started, so that\n // should take precedence over this redirect navigation. We already\n // set isRevalidationRequired so all loaders for the new route should\n // fire unless opted out via shouldRevalidate\n let doneFetcher = getDoneFetcher(undefined);\n state.fetchers.set(key, doneFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n } else {\n fetchRedirectIds.add(key);\n let loadingFetcher = getLoadingFetcher(submission);\n state.fetchers.set(key, loadingFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n\n return startRedirectNavigation(state, actionResult, {\n fetcherSubmission: submission,\n });\n }\n }\n\n // Process any non-redirect errors thrown\n if (isErrorResult(actionResult)) {\n setFetcherError(key, routeId, actionResult.error);\n return;\n }\n\n if (isDeferredResult(actionResult)) {\n throw getInternalRouterError(400, { type: \"defer-action\" });\n }\n\n // Start the data load for current matches, or the next location if we're\n // in the middle of a navigation\n let nextLocation = state.navigation.location || state.location;\n let revalidationRequest = createClientSideRequest(\n init.history,\n nextLocation,\n abortController.signal\n );\n let routesToUse = inFlightDataRoutes || dataRoutes;\n let matches =\n state.navigation.state !== \"idle\"\n ? matchRoutes(routesToUse, state.navigation.location, basename)\n : state.matches;\n\n invariant(matches, \"Didn't find any matches after fetcher action\");\n\n let loadId = ++incrementingLoadId;\n fetchReloadIds.set(key, loadId);\n\n let loadFetcher = getLoadingFetcher(submission, actionResult.data);\n state.fetchers.set(key, loadFetcher);\n\n let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(\n init.history,\n state,\n matches,\n submission,\n nextLocation,\n isRevalidationRequired,\n cancelledDeferredRoutes,\n cancelledFetcherLoads,\n fetchLoadMatches,\n fetchRedirectIds,\n routesToUse,\n basename,\n { [match.route.id]: actionResult.data },\n undefined // No need to send through errors since we short circuit above\n );\n\n // Put all revalidating fetchers into the loading state, except for the\n // current fetcher which we want to keep in it's current loading state which\n // contains it's action submission info + action data\n revalidatingFetchers\n .filter((rf) => rf.key !== key)\n .forEach((rf) => {\n let staleKey = rf.key;\n let existingFetcher = state.fetchers.get(staleKey);\n let revalidatingFetcher = getLoadingFetcher(\n undefined,\n existingFetcher ? existingFetcher.data : undefined\n );\n state.fetchers.set(staleKey, revalidatingFetcher);\n if (fetchControllers.has(staleKey)) {\n abortFetcher(staleKey);\n }\n if (rf.controller) {\n fetchControllers.set(staleKey, rf.controller);\n }\n });\n\n updateState({ fetchers: new Map(state.fetchers) });\n\n let abortPendingFetchRevalidations = () =>\n revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));\n\n abortController.signal.addEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n\n let { results, loaderResults, fetcherResults } =\n await callLoadersAndMaybeResolveData(\n state.matches,\n matches,\n matchesToLoad,\n revalidatingFetchers,\n revalidationRequest\n );\n\n if (abortController.signal.aborted) {\n return;\n }\n\n abortController.signal.removeEventListener(\n \"abort\",\n abortPendingFetchRevalidations\n );\n\n fetchReloadIds.delete(key);\n fetchControllers.delete(key);\n revalidatingFetchers.forEach((r) => fetchControllers.delete(r.key));\n\n let redirect = findRedirect(results);\n if (redirect) {\n if (redirect.idx >= matchesToLoad.length) {\n // If this redirect came from a fetcher make sure we mark it in\n // fetchRedirectIds so it doesn't get revalidated on the next set of\n // loader executions\n let fetcherKey =\n revalidatingFetchers[redirect.idx - matchesToLoad.length].key;\n fetchRedirectIds.add(fetcherKey);\n }\n return startRedirectNavigation(state, redirect.result);\n }\n\n // Process and commit output from loaders\n let { loaderData, errors } = processLoaderData(\n state,\n state.matches,\n matchesToLoad,\n loaderResults,\n undefined,\n revalidatingFetchers,\n fetcherResults,\n activeDeferreds\n );\n\n // Since we let revalidations complete even if the submitting fetcher was\n // deleted, only put it back to idle if it hasn't been deleted\n if (state.fetchers.has(key)) {\n let doneFetcher = getDoneFetcher(actionResult.data);\n state.fetchers.set(key, doneFetcher);\n }\n\n abortStaleFetchLoads(loadId);\n\n // If we are currently in a navigation loading state and this fetcher is\n // more recent than the navigation, we want the newer data so abort the\n // navigation and complete it with the fetcher data\n if (\n state.navigation.state === \"loading\" &&\n loadId > pendingNavigationLoadId\n ) {\n invariant(pendingAction, \"Expected pending action\");\n pendingNavigationController && pendingNavigationController.abort();\n\n completeNavigation(state.navigation.location, {\n matches,\n loaderData,\n errors,\n fetchers: new Map(state.fetchers),\n });\n } else {\n // otherwise just update with the fetcher data, preserving any existing\n // loaderData for loaders that did not need to reload. We have to\n // manually merge here since we aren't going through completeNavigation\n updateState({\n errors,\n loaderData: mergeLoaderData(\n state.loaderData,\n loaderData,\n matches,\n errors\n ),\n fetchers: new Map(state.fetchers),\n });\n isRevalidationRequired = false;\n }\n }\n\n // Call the matched loader for fetcher.load(), handling redirects, errors, etc.\n async function handleFetcherLoader(\n key: string,\n routeId: string,\n path: string,\n match: AgnosticDataRouteMatch,\n matches: AgnosticDataRouteMatch[],\n submission?: Submission\n ) {\n let existingFetcher = state.fetchers.get(key);\n // Put this fetcher into it's loading state\n let loadingFetcher = getLoadingFetcher(\n submission,\n existingFetcher ? existingFetcher.data : undefined\n );\n state.fetchers.set(key, loadingFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n\n // Call the loader for this fetcher route match\n let abortController = new AbortController();\n let fetchRequest = createClientSideRequest(\n init.history,\n path,\n abortController.signal\n );\n fetchControllers.set(key, abortController);\n\n let originatingLoadId = incrementingLoadId;\n let result: DataResult = await callLoaderOrAction(\n \"loader\",\n fetchRequest,\n match,\n matches,\n manifest,\n mapRouteProperties,\n basename\n );\n\n // Deferred isn't supported for fetcher loads, await everything and treat it\n // as a normal load. resolveDeferredData will return undefined if this\n // fetcher gets aborted, so we just leave result untouched and short circuit\n // below if that happens\n if (isDeferredResult(result)) {\n result =\n (await resolveDeferredData(result, fetchRequest.signal, true)) ||\n result;\n }\n\n // We can delete this so long as we weren't aborted by our our own fetcher\n // re-load which would have put _new_ controller is in fetchControllers\n if (fetchControllers.get(key) === abortController) {\n fetchControllers.delete(key);\n }\n\n if (fetchRequest.signal.aborted) {\n return;\n }\n\n if (deletedFetchers.has(key)) {\n state.fetchers.set(key, getDoneFetcher(undefined));\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n }\n\n // If the loader threw a redirect Response, start a new REPLACE navigation\n if (isRedirectResult(result)) {\n if (pendingNavigationLoadId > originatingLoadId) {\n // A new navigation was kicked off after our loader started, so that\n // should take precedence over this redirect navigation\n let doneFetcher = getDoneFetcher(undefined);\n state.fetchers.set(key, doneFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n return;\n } else {\n fetchRedirectIds.add(key);\n await startRedirectNavigation(state, result);\n return;\n }\n }\n\n // Process any non-redirect errors thrown\n if (isErrorResult(result)) {\n setFetcherError(key, routeId, result.error);\n return;\n }\n\n invariant(!isDeferredResult(result), \"Unhandled fetcher deferred data\");\n\n // Put the fetcher back into an idle state\n let doneFetcher = getDoneFetcher(result.data);\n state.fetchers.set(key, doneFetcher);\n updateState({ fetchers: new Map(state.fetchers) });\n }\n\n /**\n * Utility function to handle redirects returned from an action or loader.\n * Normally, a redirect \"replaces\" the navigation that triggered it. So, for\n * example:\n *\n * - user is on /a\n * - user clicks a link to /b\n * - loader for /b redirects to /c\n *\n * In a non-JS app the browser would track the in-flight navigation to /b and\n * then replace it with /c when it encountered the redirect response. In\n * the end it would only ever update the URL bar with /c.\n *\n * In client-side routing using pushState/replaceState, we aim to emulate\n * this behavior and we also do not update history until the end of the\n * navigation (including processed redirects). This means that we never\n * actually touch history until we've processed redirects, so we just use\n * the history action from the original navigation (PUSH or REPLACE).\n */\n async function startRedirectNavigation(\n state: RouterState,\n redirect: RedirectResult,\n {\n submission,\n fetcherSubmission,\n replace,\n }: {\n submission?: Submission;\n fetcherSubmission?: Submission;\n replace?: boolean;\n } = {}\n ) {\n if (redirect.revalidate) {\n isRevalidationRequired = true;\n }\n\n let redirectLocation = createLocation(state.location, redirect.location, {\n _isRedirect: true,\n });\n invariant(\n redirectLocation,\n \"Expected a location on the redirect navigation\"\n );\n\n if (isBrowser) {\n let isDocumentReload = false;\n\n if (redirect.reloadDocument) {\n // Hard reload if the response contained X-Remix-Reload-Document\n isDocumentReload = true;\n } else if (ABSOLUTE_URL_REGEX.test(redirect.location)) {\n const url = init.history.createURL(redirect.location);\n isDocumentReload =\n // Hard reload if it's an absolute URL to a new origin\n url.origin !== routerWindow.location.origin ||\n // Hard reload if it's an absolute URL that does not match our basename\n stripBasename(url.pathname, basename) == null;\n }\n\n if (isDocumentReload) {\n if (replace) {\n routerWindow.location.replace(redirect.location);\n } else {\n routerWindow.location.assign(redirect.location);\n }\n return;\n }\n }\n\n // There's no need to abort on redirects, since we don't detect the\n // redirect until the action/loaders have settled\n pendingNavigationController = null;\n\n let redirectHistoryAction =\n replace === true ? HistoryAction.Replace : HistoryAction.Push;\n\n // Use the incoming submission if provided, fallback on the active one in\n // state.navigation\n let { formMethod, formAction, formEncType } = state.navigation;\n if (\n !submission &&\n !fetcherSubmission &&\n formMethod &&\n formAction &&\n formEncType\n ) {\n submission = getSubmissionFromNavigation(state.navigation);\n }\n\n // If this was a 307/308 submission we want to preserve the HTTP method and\n // re-submit the GET/POST/PUT/PATCH/DELETE as a submission navigation to the\n // redirected location\n let activeSubmission = submission || fetcherSubmission;\n if (\n redirectPreserveMethodStatusCodes.has(redirect.status) &&\n activeSubmission &&\n isMutationMethod(activeSubmission.formMethod)\n ) {\n await startNavigation(redirectHistoryAction, redirectLocation, {\n submission: {\n ...activeSubmission,\n formAction: redirect.location,\n },\n // Preserve this flag across redirects\n preventScrollReset: pendingPreventScrollReset,\n });\n } else {\n // If we have a navigation submission, we will preserve it through the\n // redirect navigation\n let overrideNavigation = getLoadingNavigation(\n redirectLocation,\n submission\n );\n await startNavigation(redirectHistoryAction, redirectLocation, {\n overrideNavigation,\n // Send fetcher submissions through for shouldRevalidate\n fetcherSubmission,\n // Preserve this flag across redirects\n preventScrollReset: pendingPreventScrollReset,\n });\n }\n }\n\n async function callLoadersAndMaybeResolveData(\n currentMatches: AgnosticDataRouteMatch[],\n matches: AgnosticDataRouteMatch[],\n matchesToLoad: AgnosticDataRouteMatch[],\n fetchersToLoad: RevalidatingFetcher[],\n request: Request\n ) {\n // Call all navigation loaders and revalidating fetcher loaders in parallel,\n // then slice off the results into separate arrays so we can handle them\n // accordingly\n let results = await Promise.all([\n ...matchesToLoad.map((match) =>\n callLoaderOrAction(\n \"loader\",\n request,\n match,\n matches,\n manifest,\n mapRouteProperties,\n basename\n )\n ),\n ...fetchersToLoad.map((f) => {\n if (f.matches && f.match && f.controller) {\n return callLoaderOrAction(\n \"loader\",\n createClientSideRequest(init.history, f.path, f.controller.signal),\n f.match,\n f.matches,\n manifest,\n mapRouteProperties,\n basename\n );\n } else {\n let error: ErrorResult = {\n type: ResultType.error,\n error: getInternalRouterError(404, { pathname: f.path }),\n };\n return error;\n }\n }),\n ]);\n let loaderResults = results.slice(0, matchesToLoad.length);\n let fetcherResults = results.slice(matchesToLoad.length);\n\n await Promise.all([\n resolveDeferredResults(\n currentMatches,\n matchesToLoad,\n loaderResults,\n loaderResults.map(() => request.signal),\n false,\n state.loaderData\n ),\n resolveDeferredResults(\n currentMatches,\n fetchersToLoad.map((f) => f.match),\n fetcherResults,\n fetchersToLoad.map((f) => (f.controller ? f.controller.signal : null)),\n true\n ),\n ]);\n\n return { results, loaderResults, fetcherResults };\n }\n\n function interruptActiveLoads() {\n // Every interruption triggers a revalidation\n isRevalidationRequired = true;\n\n // Cancel pending route-level deferreds and mark cancelled routes for\n // revalidation\n cancelledDeferredRoutes.push(...cancelActiveDeferreds());\n\n // Abort in-flight fetcher loads\n fetchLoadMatches.forEach((_, key) => {\n if (fetchControllers.has(key)) {\n cancelledFetcherLoads.push(key);\n abortFetcher(key);\n }\n });\n }\n\n function setFetcherError(key: string, routeId: string, error: any) {\n let boundaryMatch = findNearestBoundary(state.matches, routeId);\n deleteFetcher(key);\n updateState({\n errors: {\n [boundaryMatch.route.id]: error,\n },\n fetchers: new Map(state.fetchers),\n });\n }\n\n function deleteFetcher(key: string): void {\n let fetcher = state.fetchers.get(key);\n // Don't abort the controller if this is a deletion of a fetcher.submit()\n // in it's loading phase since - we don't want to abort the corresponding\n // revalidation and want them to complete and land\n if (\n fetchControllers.has(key) &&\n !(fetcher && fetcher.state === \"loading\" && fetchReloadIds.has(key))\n ) {\n abortFetcher(key);\n }\n fetchLoadMatches.delete(key);\n fetchReloadIds.delete(key);\n fetchRedirectIds.delete(key);\n deletedFetchers.delete(key);\n state.fetchers.delete(key);\n }\n\n function deleteFetcherAndUpdateState(key: string): void {\n if (future.v7_fetcherPersist) {\n let count = (activeFetchers.get(key) || 0) - 1;\n if (count <= 0) {\n activeFetchers.delete(key);\n deletedFetchers.add(key);\n } else {\n activeFetchers.set(key, count);\n }\n } else {\n deleteFetcher(key);\n }\n updateState({ fetchers: new Map(state.fetchers) });\n }\n\n function abortFetcher(key: string) {\n let controller = fetchControllers.get(key);\n invariant(controller, `Expected fetch controller: ${key}`);\n controller.abort();\n fetchControllers.delete(key);\n }\n\n function markFetchersDone(keys: string[]) {\n for (let key of keys) {\n let fetcher = getFetcher(key);\n let doneFetcher = getDoneFetcher(fetcher.data);\n state.fetchers.set(key, doneFetcher);\n }\n }\n\n function markFetchRedirectsDone(): boolean {\n let doneKeys = [];\n let updatedFetchers = false;\n for (let key of fetchRedirectIds) {\n let fetcher = state.fetchers.get(key);\n invariant(fetcher, `Expected fetcher: ${key}`);\n if (fetcher.state === \"loading\") {\n fetchRedirectIds.delete(key);\n doneKeys.push(key);\n updatedFetchers = true;\n }\n }\n markFetchersDone(doneKeys);\n return updatedFetchers;\n }\n\n function abortStaleFetchLoads(landedId: number): boolean {\n let yeetedKeys = [];\n for (let [key, id] of fetchReloadIds) {\n if (id < landedId) {\n let fetcher = state.fetchers.get(key);\n invariant(fetcher, `Expected fetcher: ${key}`);\n if (fetcher.state === \"loading\") {\n abortFetcher(key);\n fetchReloadIds.delete(key);\n yeetedKeys.push(key);\n }\n }\n }\n markFetchersDone(yeetedKeys);\n return yeetedKeys.length > 0;\n }\n\n function getBlocker(key: string, fn: BlockerFunction) {\n let blocker: Blocker = state.blockers.get(key) || IDLE_BLOCKER;\n\n if (blockerFunctions.get(key) !== fn) {\n blockerFunctions.set(key, fn);\n }\n\n return blocker;\n }\n\n function deleteBlocker(key: string) {\n state.blockers.delete(key);\n blockerFunctions.delete(key);\n }\n\n // Utility function to update blockers, ensuring valid state transitions\n function updateBlocker(key: string, newBlocker: Blocker) {\n let blocker = state.blockers.get(key) || IDLE_BLOCKER;\n\n // Poor mans state machine :)\n // https://mermaid.live/edit#pako:eNqVkc9OwzAMxl8l8nnjAYrEtDIOHEBIgwvKJTReGy3_lDpIqO27k6awMG0XcrLlnz87nwdonESogKXXBuE79rq75XZO3-yHds0RJVuv70YrPlUrCEe2HfrORS3rubqZfuhtpg5C9wk5tZ4VKcRUq88q9Z8RS0-48cE1iHJkL0ugbHuFLus9L6spZy8nX9MP2CNdomVaposqu3fGayT8T8-jJQwhepo_UtpgBQaDEUom04dZhAN1aJBDlUKJBxE1ceB2Smj0Mln-IBW5AFU2dwUiktt_2Qaq2dBfaKdEup85UV7Yd-dKjlnkabl2Pvr0DTkTreM\n invariant(\n (blocker.state === \"unblocked\" && newBlocker.state === \"blocked\") ||\n (blocker.state === \"blocked\" && newBlocker.state === \"blocked\") ||\n (blocker.state === \"blocked\" && newBlocker.state === \"proceeding\") ||\n (blocker.state === \"blocked\" && newBlocker.state === \"unblocked\") ||\n (blocker.state === \"proceeding\" && newBlocker.state === \"unblocked\"),\n `Invalid blocker state transition: ${blocker.state} -> ${newBlocker.state}`\n );\n\n let blockers = new Map(state.blockers);\n blockers.set(key, newBlocker);\n updateState({ blockers });\n }\n\n function shouldBlockNavigation({\n currentLocation,\n nextLocation,\n historyAction,\n }: {\n currentLocation: Location;\n nextLocation: Location;\n historyAction: HistoryAction;\n }): string | undefined {\n if (blockerFunctions.size === 0) {\n return;\n }\n\n // We ony support a single active blocker at the moment since we don't have\n // any compelling use cases for multi-blocker yet\n if (blockerFunctions.size > 1) {\n warning(false, \"A router only supports one blocker at a time\");\n }\n\n let entries = Array.from(blockerFunctions.entries());\n let [blockerKey, blockerFunction] = entries[entries.length - 1];\n let blocker = state.blockers.get(blockerKey);\n\n if (blocker && blocker.state === \"proceeding\") {\n // If the blocker is currently proceeding, we don't need to re-check\n // it and can let this navigation continue\n return;\n }\n\n // At this point, we know we're unblocked/blocked so we need to check the\n // user-provided blocker function\n if (blockerFunction({ currentLocation, nextLocation, historyAction })) {\n return blockerKey;\n }\n }\n\n function cancelActiveDeferreds(\n predicate?: (routeId: string) => boolean\n ): string[] {\n let cancelledRouteIds: string[] = [];\n activeDeferreds.forEach((dfd, routeId) => {\n if (!predicate || predicate(routeId)) {\n // Cancel the deferred - but do not remove from activeDeferreds here -\n // we rely on the subscribers to do that so our tests can assert proper\n // cleanup via _internalActiveDeferreds\n dfd.cancel();\n cancelledRouteIds.push(routeId);\n activeDeferreds.delete(routeId);\n }\n });\n return cancelledRouteIds;\n }\n\n // Opt in to capturing and reporting scroll positions during navigations,\n // used by the component\n function enableScrollRestoration(\n positions: Record,\n getPosition: GetScrollPositionFunction,\n getKey?: GetScrollRestorationKeyFunction\n ) {\n savedScrollPositions = positions;\n getScrollPosition = getPosition;\n getScrollRestorationKey = getKey || null;\n\n // Perform initial hydration scroll restoration, since we miss the boat on\n // the initial updateState() because we've not yet rendered \n // and therefore have no savedScrollPositions available\n if (!initialScrollRestored && state.navigation === IDLE_NAVIGATION) {\n initialScrollRestored = true;\n let y = getSavedScrollPosition(state.location, state.matches);\n if (y != null) {\n updateState({ restoreScrollPosition: y });\n }\n }\n\n return () => {\n savedScrollPositions = null;\n getScrollPosition = null;\n getScrollRestorationKey = null;\n };\n }\n\n function getScrollKey(location: Location, matches: AgnosticDataRouteMatch[]) {\n if (getScrollRestorationKey) {\n let key = getScrollRestorationKey(\n location,\n matches.map((m) => convertRouteMatchToUiMatch(m, state.loaderData))\n );\n return key || location.key;\n }\n return location.key;\n }\n\n function saveScrollPosition(\n location: Location,\n matches: AgnosticDataRouteMatch[]\n ): void {\n if (savedScrollPositions && getScrollPosition) {\n let key = getScrollKey(location, matches);\n savedScrollPositions[key] = getScrollPosition();\n }\n }\n\n function getSavedScrollPosition(\n location: Location,\n matches: AgnosticDataRouteMatch[]\n ): number | null {\n if (savedScrollPositions) {\n let key = getScrollKey(location, matches);\n let y = savedScrollPositions[key];\n if (typeof y === \"number\") {\n return y;\n }\n }\n return null;\n }\n\n function _internalSetRoutes(newRoutes: AgnosticDataRouteObject[]) {\n manifest = {};\n inFlightDataRoutes = convertRoutesToDataRoutes(\n newRoutes,\n mapRouteProperties,\n undefined,\n manifest\n );\n }\n\n router = {\n get basename() {\n return basename;\n },\n get state() {\n return state;\n },\n get routes() {\n return dataRoutes;\n },\n get window() {\n return routerWindow;\n },\n initialize,\n subscribe,\n enableScrollRestoration,\n navigate,\n fetch,\n revalidate,\n // Passthrough to history-aware createHref used by useHref so we get proper\n // hash-aware URLs in DOM paths\n createHref: (to: To) => init.history.createHref(to),\n encodeLocation: (to: To) => init.history.encodeLocation(to),\n getFetcher,\n deleteFetcher: deleteFetcherAndUpdateState,\n dispose,\n getBlocker,\n deleteBlocker,\n _internalFetchControllers: fetchControllers,\n _internalActiveDeferreds: activeDeferreds,\n // TODO: Remove setRoutes, it's temporary to avoid dealing with\n // updating the tree while validating the update algorithm.\n _internalSetRoutes,\n };\n\n return router;\n}\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region createStaticHandler\n////////////////////////////////////////////////////////////////////////////////\n\nexport const UNSAFE_DEFERRED_SYMBOL = Symbol(\"deferred\");\n\nexport interface CreateStaticHandlerOptions {\n basename?: string;\n /**\n * @deprecated Use `mapRouteProperties` instead\n */\n detectErrorBoundary?: DetectErrorBoundaryFunction;\n mapRouteProperties?: MapRoutePropertiesFunction;\n}\n\nexport function createStaticHandler(\n routes: AgnosticRouteObject[],\n opts?: CreateStaticHandlerOptions\n): StaticHandler {\n invariant(\n routes.length > 0,\n \"You must provide a non-empty routes array to createStaticHandler\"\n );\n\n let manifest: RouteManifest = {};\n let basename = (opts ? opts.basename : null) || \"/\";\n let mapRouteProperties: MapRoutePropertiesFunction;\n if (opts?.mapRouteProperties) {\n mapRouteProperties = opts.mapRouteProperties;\n } else if (opts?.detectErrorBoundary) {\n // If they are still using the deprecated version, wrap it with the new API\n let detectErrorBoundary = opts.detectErrorBoundary;\n mapRouteProperties = (route) => ({\n hasErrorBoundary: detectErrorBoundary(route),\n });\n } else {\n mapRouteProperties = defaultMapRouteProperties;\n }\n\n let dataRoutes = convertRoutesToDataRoutes(\n routes,\n mapRouteProperties,\n undefined,\n manifest\n );\n\n /**\n * The query() method is intended for document requests, in which we want to\n * call an optional action and potentially multiple loaders for all nested\n * routes. It returns a StaticHandlerContext object, which is very similar\n * to the router state (location, loaderData, actionData, errors, etc.) and\n * also adds SSR-specific information such as the statusCode and headers\n * from action/loaders Responses.\n *\n * It _should_ never throw and should report all errors through the\n * returned context.errors object, properly associating errors to their error\n * boundary. Additionally, it tracks _deepestRenderedBoundaryId which can be\n * used to emulate React error boundaries during SSr by performing a second\n * pass only down to the boundaryId.\n *\n * The one exception where we do not return a StaticHandlerContext is when a\n * redirect response is returned or thrown from any action/loader. We\n * propagate that out and return the raw Response so the HTTP server can\n * return it directly.\n */\n async function query(\n request: Request,\n { requestContext }: { requestContext?: unknown } = {}\n ): Promise {\n let url = new URL(request.url);\n let method = request.method;\n let location = createLocation(\"\", createPath(url), null, \"default\");\n let matches = matchRoutes(dataRoutes, location, basename);\n\n // SSR supports HEAD requests while SPA doesn't\n if (!isValidMethod(method) && method !== \"HEAD\") {\n let error = getInternalRouterError(405, { method });\n let { matches: methodNotAllowedMatches, route } =\n getShortCircuitMatches(dataRoutes);\n return {\n basename,\n location,\n matches: methodNotAllowedMatches,\n loaderData: {},\n actionData: null,\n errors: {\n [route.id]: error,\n },\n statusCode: error.status,\n loaderHeaders: {},\n actionHeaders: {},\n activeDeferreds: null,\n };\n } else if (!matches) {\n let error = getInternalRouterError(404, { pathname: location.pathname });\n let { matches: notFoundMatches, route } =\n getShortCircuitMatches(dataRoutes);\n return {\n basename,\n location,\n matches: notFoundMatches,\n loaderData: {},\n actionData: null,\n errors: {\n [route.id]: error,\n },\n statusCode: error.status,\n loaderHeaders: {},\n actionHeaders: {},\n activeDeferreds: null,\n };\n }\n\n let result = await queryImpl(request, location, matches, requestContext);\n if (isResponse(result)) {\n return result;\n }\n\n // When returning StaticHandlerContext, we patch back in the location here\n // since we need it for React Context. But this helps keep our submit and\n // loadRouteData operating on a Request instead of a Location\n return { location, basename, ...result };\n }\n\n /**\n * The queryRoute() method is intended for targeted route requests, either\n * for fetch ?_data requests or resource route requests. In this case, we\n * are only ever calling a single action or loader, and we are returning the\n * returned value directly. In most cases, this will be a Response returned\n * from the action/loader, but it may be a primitive or other value as well -\n * and in such cases the calling context should handle that accordingly.\n *\n * We do respect the throw/return differentiation, so if an action/loader\n * throws, then this method will throw the value. This is important so we\n * can do proper boundary identification in Remix where a thrown Response\n * must go to the Catch Boundary but a returned Response is happy-path.\n *\n * One thing to note is that any Router-initiated Errors that make sense\n * to associate with a status code will be thrown as an ErrorResponse\n * instance which include the raw Error, such that the calling context can\n * serialize the error as they see fit while including the proper response\n * code. Examples here are 404 and 405 errors that occur prior to reaching\n * any user-defined loaders.\n */\n async function queryRoute(\n request: Request,\n {\n routeId,\n requestContext,\n }: { requestContext?: unknown; routeId?: string } = {}\n ): Promise {\n let url = new URL(request.url);\n let method = request.method;\n let location = createLocation(\"\", createPath(url), null, \"default\");\n let matches = matchRoutes(dataRoutes, location, basename);\n\n // SSR supports HEAD requests while SPA doesn't\n if (!isValidMethod(method) && method !== \"HEAD\" && method !== \"OPTIONS\") {\n throw getInternalRouterError(405, { method });\n } else if (!matches) {\n throw getInternalRouterError(404, { pathname: location.pathname });\n }\n\n let match = routeId\n ? matches.find((m) => m.route.id === routeId)\n : getTargetMatch(matches, location);\n\n if (routeId && !match) {\n throw getInternalRouterError(403, {\n pathname: location.pathname,\n routeId,\n });\n } else if (!match) {\n // This should never hit I don't think?\n throw getInternalRouterError(404, { pathname: location.pathname });\n }\n\n let result = await queryImpl(\n request,\n location,\n matches,\n requestContext,\n match\n );\n if (isResponse(result)) {\n return result;\n }\n\n let error = result.errors ? Object.values(result.errors)[0] : undefined;\n if (error !== undefined) {\n // If we got back result.errors, that means the loader/action threw\n // _something_ that wasn't a Response, but it's not guaranteed/required\n // to be an `instanceof Error` either, so we have to use throw here to\n // preserve the \"error\" state outside of queryImpl.\n throw error;\n }\n\n // Pick off the right state value to return\n if (result.actionData) {\n return Object.values(result.actionData)[0];\n }\n\n if (result.loaderData) {\n let data = Object.values(result.loaderData)[0];\n if (result.activeDeferreds?.[match.route.id]) {\n data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];\n }\n return data;\n }\n\n return undefined;\n }\n\n async function queryImpl(\n request: Request,\n location: Location,\n matches: AgnosticDataRouteMatch[],\n requestContext: unknown,\n routeMatch?: AgnosticDataRouteMatch\n ): Promise | Response> {\n invariant(\n request.signal,\n \"query()/queryRoute() requests must contain an AbortController signal\"\n );\n\n try {\n if (isMutationMethod(request.method.toLowerCase())) {\n let result = await submit(\n request,\n matches,\n routeMatch || getTargetMatch(matches, location),\n requestContext,\n routeMatch != null\n );\n return result;\n }\n\n let result = await loadRouteData(\n request,\n matches,\n requestContext,\n routeMatch\n );\n return isResponse(result)\n ? result\n : {\n ...result,\n actionData: null,\n actionHeaders: {},\n };\n } catch (e) {\n // If the user threw/returned a Response in callLoaderOrAction, we throw\n // it to bail out and then return or throw here based on whether the user\n // returned or threw\n if (isQueryRouteResponse(e)) {\n if (e.type === ResultType.error) {\n throw e.response;\n }\n return e.response;\n }\n // Redirects are always returned since they don't propagate to catch\n // boundaries\n if (isRedirectResponse(e)) {\n return e;\n }\n throw e;\n }\n }\n\n async function submit(\n request: Request,\n matches: AgnosticDataRouteMatch[],\n actionMatch: AgnosticDataRouteMatch,\n requestContext: unknown,\n isRouteRequest: boolean\n ): Promise | Response> {\n let result: DataResult;\n\n if (!actionMatch.route.action && !actionMatch.route.lazy) {\n let error = getInternalRouterError(405, {\n method: request.method,\n pathname: new URL(request.url).pathname,\n routeId: actionMatch.route.id,\n });\n if (isRouteRequest) {\n throw error;\n }\n result = {\n type: ResultType.error,\n error,\n };\n } else {\n result = await callLoaderOrAction(\n \"action\",\n request,\n actionMatch,\n matches,\n manifest,\n mapRouteProperties,\n basename,\n { isStaticRequest: true, isRouteRequest, requestContext }\n );\n\n if (request.signal.aborted) {\n let method = isRouteRequest ? \"queryRoute\" : \"query\";\n throw new Error(\n `${method}() call aborted: ${request.method} ${request.url}`\n );\n }\n }\n\n if (isRedirectResult(result)) {\n // Uhhhh - this should never happen, we should always throw these from\n // callLoaderOrAction, but the type narrowing here keeps TS happy and we\n // can get back on the \"throw all redirect responses\" train here should\n // this ever happen :/\n throw new Response(null, {\n status: result.status,\n headers: {\n Location: result.location,\n },\n });\n }\n\n if (isDeferredResult(result)) {\n let error = getInternalRouterError(400, { type: \"defer-action\" });\n if (isRouteRequest) {\n throw error;\n }\n result = {\n type: ResultType.error,\n error,\n };\n }\n\n if (isRouteRequest) {\n // Note: This should only be non-Response values if we get here, since\n // isRouteRequest should throw any Response received in callLoaderOrAction\n if (isErrorResult(result)) {\n throw result.error;\n }\n\n return {\n matches: [actionMatch],\n loaderData: {},\n actionData: { [actionMatch.route.id]: result.data },\n errors: null,\n // Note: statusCode + headers are unused here since queryRoute will\n // return the raw Response or value\n statusCode: 200,\n loaderHeaders: {},\n actionHeaders: {},\n activeDeferreds: null,\n };\n }\n\n if (isErrorResult(result)) {\n // Store off the pending error - we use it to determine which loaders\n // to call and will commit it when we complete the navigation\n let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);\n let context = await loadRouteData(\n request,\n matches,\n requestContext,\n undefined,\n {\n [boundaryMatch.route.id]: result.error,\n }\n );\n\n // action status codes take precedence over loader status codes\n return {\n ...context,\n statusCode: isRouteErrorResponse(result.error)\n ? result.error.status\n : 500,\n actionData: null,\n actionHeaders: {\n ...(result.headers ? { [actionMatch.route.id]: result.headers } : {}),\n },\n };\n }\n\n // Create a GET request for the loaders\n let loaderRequest = new Request(request.url, {\n headers: request.headers,\n redirect: request.redirect,\n signal: request.signal,\n });\n let context = await loadRouteData(loaderRequest, matches, requestContext);\n\n return {\n ...context,\n // action status codes take precedence over loader status codes\n ...(result.statusCode ? { statusCode: result.statusCode } : {}),\n actionData: {\n [actionMatch.route.id]: result.data,\n },\n actionHeaders: {\n ...(result.headers ? { [actionMatch.route.id]: result.headers } : {}),\n },\n };\n }\n\n async function loadRouteData(\n request: Request,\n matches: AgnosticDataRouteMatch[],\n requestContext: unknown,\n routeMatch?: AgnosticDataRouteMatch,\n pendingActionError?: RouteData\n ): Promise<\n | Omit<\n StaticHandlerContext,\n \"location\" | \"basename\" | \"actionData\" | \"actionHeaders\"\n >\n | Response\n > {\n let isRouteRequest = routeMatch != null;\n\n // Short circuit if we have no loaders to run (queryRoute())\n if (\n isRouteRequest &&\n !routeMatch?.route.loader &&\n !routeMatch?.route.lazy\n ) {\n throw getInternalRouterError(400, {\n method: request.method,\n pathname: new URL(request.url).pathname,\n routeId: routeMatch?.route.id,\n });\n }\n\n let requestMatches = routeMatch\n ? [routeMatch]\n : getLoaderMatchesUntilBoundary(\n matches,\n Object.keys(pendingActionError || {})[0]\n );\n let matchesToLoad = requestMatches.filter(\n (m) => m.route.loader || m.route.lazy\n );\n\n // Short circuit if we have no loaders to run (query())\n if (matchesToLoad.length === 0) {\n return {\n matches,\n // Add a null for all matched routes for proper revalidation on the client\n loaderData: matches.reduce(\n (acc, m) => Object.assign(acc, { [m.route.id]: null }),\n {}\n ),\n errors: pendingActionError || null,\n statusCode: 200,\n loaderHeaders: {},\n activeDeferreds: null,\n };\n }\n\n let results = await Promise.all([\n ...matchesToLoad.map((match) =>\n callLoaderOrAction(\n \"loader\",\n request,\n match,\n matches,\n manifest,\n mapRouteProperties,\n basename,\n { isStaticRequest: true, isRouteRequest, requestContext }\n )\n ),\n ]);\n\n if (request.signal.aborted) {\n let method = isRouteRequest ? \"queryRoute\" : \"query\";\n throw new Error(\n `${method}() call aborted: ${request.method} ${request.url}`\n );\n }\n\n // Process and commit output from loaders\n let activeDeferreds = new Map();\n let context = processRouteLoaderData(\n matches,\n matchesToLoad,\n results,\n pendingActionError,\n activeDeferreds\n );\n\n // Add a null for any non-loader matches for proper revalidation on the client\n let executedLoaders = new Set(\n matchesToLoad.map((match) => match.route.id)\n );\n matches.forEach((match) => {\n if (!executedLoaders.has(match.route.id)) {\n context.loaderData[match.route.id] = null;\n }\n });\n\n return {\n ...context,\n matches,\n activeDeferreds:\n activeDeferreds.size > 0\n ? Object.fromEntries(activeDeferreds.entries())\n : null,\n };\n }\n\n return {\n dataRoutes,\n query,\n queryRoute,\n };\n}\n\n//#endregion\n\n////////////////////////////////////////////////////////////////////////////////\n//#region Helpers\n////////////////////////////////////////////////////////////////////////////////\n\n/**\n * Given an existing StaticHandlerContext and an error thrown at render time,\n * provide an updated StaticHandlerContext suitable for a second SSR render\n */\nexport function getStaticContextFromError(\n routes: AgnosticDataRouteObject[],\n context: StaticHandlerContext,\n error: any\n) {\n let newContext: StaticHandlerContext = {\n ...context,\n statusCode: 500,\n errors: {\n [context._deepestRenderedBoundaryId || routes[0].id]: error,\n },\n };\n return newContext;\n}\n\nfunction isSubmissionNavigation(\n opts: BaseNavigateOrFetchOptions\n): opts is SubmissionNavigateOptions {\n return (\n opts != null &&\n ((\"formData\" in opts && opts.formData != null) ||\n (\"body\" in opts && opts.body !== undefined))\n );\n}\n\nfunction normalizeTo(\n location: Path,\n matches: AgnosticDataRouteMatch[],\n basename: string,\n prependBasename: boolean,\n to: To | null,\n fromRouteId?: string,\n relative?: RelativeRoutingType\n) {\n let contextualMatches: AgnosticDataRouteMatch[];\n let activeRouteMatch: AgnosticDataRouteMatch | undefined;\n if (fromRouteId != null && relative !== \"path\") {\n // Grab matches up to the calling route so our route-relative logic is\n // relative to the correct source route. When using relative:path,\n // fromRouteId is ignored since that is always relative to the current\n // location path\n contextualMatches = [];\n for (let match of matches) {\n contextualMatches.push(match);\n if (match.route.id === fromRouteId) {\n activeRouteMatch = match;\n break;\n }\n }\n } else {\n contextualMatches = matches;\n activeRouteMatch = matches[matches.length - 1];\n }\n\n // Resolve the relative path\n let path = resolveTo(\n to ? to : \".\",\n getPathContributingMatches(contextualMatches).map((m) => m.pathnameBase),\n stripBasename(location.pathname, basename) || location.pathname,\n relative === \"path\"\n );\n\n // When `to` is not specified we inherit search/hash from the current\n // location, unlike when to=\".\" and we just inherit the path.\n // See https://github.com/remix-run/remix/issues/927\n if (to == null) {\n path.search = location.search;\n path.hash = location.hash;\n }\n\n // Add an ?index param for matched index routes if we don't already have one\n if (\n (to == null || to === \"\" || to === \".\") &&\n activeRouteMatch &&\n activeRouteMatch.route.index &&\n !hasNakedIndexQuery(path.search)\n ) {\n path.search = path.search\n ? path.search.replace(/^\\?/, \"?index&\")\n : \"?index\";\n }\n\n // If we're operating within a basename, prepend it to the pathname. If\n // this is a root navigation, then just use the raw basename which allows\n // the basename to have full control over the presence of a trailing slash\n // on root actions\n if (prependBasename && basename !== \"/\") {\n path.pathname =\n path.pathname === \"/\" ? basename : joinPaths([basename, path.pathname]);\n }\n\n return createPath(path);\n}\n\n// Normalize navigation options by converting formMethod=GET formData objects to\n// URLSearchParams so they behave identically to links with query params\nfunction normalizeNavigateOptions(\n normalizeFormMethod: boolean,\n isFetcher: boolean,\n path: string,\n opts?: BaseNavigateOrFetchOptions\n): {\n path: string;\n submission?: Submission;\n error?: ErrorResponseImpl;\n} {\n // Return location verbatim on non-submission navigations\n if (!opts || !isSubmissionNavigation(opts)) {\n return { path };\n }\n\n if (opts.formMethod && !isValidMethod(opts.formMethod)) {\n return {\n path,\n error: getInternalRouterError(405, { method: opts.formMethod }),\n };\n }\n\n let getInvalidBodyError = () => ({\n path,\n error: getInternalRouterError(400, { type: \"invalid-body\" }),\n });\n\n // Create a Submission on non-GET navigations\n let rawFormMethod = opts.formMethod || \"get\";\n let formMethod = normalizeFormMethod\n ? (rawFormMethod.toUpperCase() as V7_FormMethod)\n : (rawFormMethod.toLowerCase() as FormMethod);\n let formAction = stripHashFromPath(path);\n\n if (opts.body !== undefined) {\n if (opts.formEncType === \"text/plain\") {\n // text only support POST/PUT/PATCH/DELETE submissions\n if (!isMutationMethod(formMethod)) {\n return getInvalidBodyError();\n }\n\n let text =\n typeof opts.body === \"string\"\n ? opts.body\n : opts.body instanceof FormData ||\n opts.body instanceof URLSearchParams\n ? // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data\n Array.from(opts.body.entries()).reduce(\n (acc, [name, value]) => `${acc}${name}=${value}\\n`,\n \"\"\n )\n : String(opts.body);\n\n return {\n path,\n submission: {\n formMethod,\n formAction,\n formEncType: opts.formEncType,\n formData: undefined,\n json: undefined,\n text,\n },\n };\n } else if (opts.formEncType === \"application/json\") {\n // json only supports POST/PUT/PATCH/DELETE submissions\n if (!isMutationMethod(formMethod)) {\n return getInvalidBodyError();\n }\n\n try {\n let json =\n typeof opts.body === \"string\" ? JSON.parse(opts.body) : opts.body;\n\n return {\n path,\n submission: {\n formMethod,\n formAction,\n formEncType: opts.formEncType,\n formData: undefined,\n json,\n text: undefined,\n },\n };\n } catch (e) {\n return getInvalidBodyError();\n }\n }\n }\n\n invariant(\n typeof FormData === \"function\",\n \"FormData is not available in this environment\"\n );\n\n let searchParams: URLSearchParams;\n let formData: FormData;\n\n if (opts.formData) {\n searchParams = convertFormDataToSearchParams(opts.formData);\n formData = opts.formData;\n } else if (opts.body instanceof FormData) {\n searchParams = convertFormDataToSearchParams(opts.body);\n formData = opts.body;\n } else if (opts.body instanceof URLSearchParams) {\n searchParams = opts.body;\n formData = convertSearchParamsToFormData(searchParams);\n } else if (opts.body == null) {\n searchParams = new URLSearchParams();\n formData = new FormData();\n } else {\n try {\n searchParams = new URLSearchParams(opts.body);\n formData = convertSearchParamsToFormData(searchParams);\n } catch (e) {\n return getInvalidBodyError();\n }\n }\n\n let submission: Submission = {\n formMethod,\n formAction,\n formEncType:\n (opts && opts.formEncType) || \"application/x-www-form-urlencoded\",\n formData,\n json: undefined,\n text: undefined,\n };\n\n if (isMutationMethod(submission.formMethod)) {\n return { path, submission };\n }\n\n // Flatten submission onto URLSearchParams for GET submissions\n let parsedPath = parsePath(path);\n // On GET navigation submissions we can drop the ?index param from the\n // resulting location since all loaders will run. But fetcher GET submissions\n // only run a single loader so we need to preserve any incoming ?index params\n if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {\n searchParams.append(\"index\", \"\");\n }\n parsedPath.search = `?${searchParams}`;\n\n return { path: createPath(parsedPath), submission };\n}\n\n// Filter out all routes below any caught error as they aren't going to\n// render so we don't need to load them\nfunction getLoaderMatchesUntilBoundary(\n matches: AgnosticDataRouteMatch[],\n boundaryId?: string\n) {\n let boundaryMatches = matches;\n if (boundaryId) {\n let index = matches.findIndex((m) => m.route.id === boundaryId);\n if (index >= 0) {\n boundaryMatches = matches.slice(0, index);\n }\n }\n return boundaryMatches;\n}\n\nfunction getMatchesToLoad(\n history: History,\n state: RouterState,\n matches: AgnosticDataRouteMatch[],\n submission: Submission | undefined,\n location: Location,\n isRevalidationRequired: boolean,\n cancelledDeferredRoutes: string[],\n cancelledFetcherLoads: string[],\n fetchLoadMatches: Map,\n fetchRedirectIds: Set,\n routesToUse: AgnosticDataRouteObject[],\n basename: string | undefined,\n pendingActionData?: RouteData,\n pendingError?: RouteData\n): [AgnosticDataRouteMatch[], RevalidatingFetcher[]] {\n let actionResult = pendingError\n ? Object.values(pendingError)[0]\n : pendingActionData\n ? Object.values(pendingActionData)[0]\n : undefined;\n\n let currentUrl = history.createURL(state.location);\n let nextUrl = history.createURL(location);\n\n // Pick navigation matches that are net-new or qualify for revalidation\n let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;\n let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);\n\n let navigationMatches = boundaryMatches.filter((match, index) => {\n if (match.route.lazy) {\n // We haven't loaded this route yet so we don't know if it's got a loader!\n return true;\n }\n if (match.route.loader == null) {\n return false;\n }\n\n // Always call the loader on new route instances and pending defer cancellations\n if (\n isNewLoader(state.loaderData, state.matches[index], match) ||\n cancelledDeferredRoutes.some((id) => id === match.route.id)\n ) {\n return true;\n }\n\n // This is the default implementation for when we revalidate. If the route\n // provides it's own implementation, then we give them full control but\n // provide this value so they can leverage it if needed after they check\n // their own specific use cases\n let currentRouteMatch = state.matches[index];\n let nextRouteMatch = match;\n\n return shouldRevalidateLoader(match, {\n currentUrl,\n currentParams: currentRouteMatch.params,\n nextUrl,\n nextParams: nextRouteMatch.params,\n ...submission,\n actionResult,\n defaultShouldRevalidate:\n // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate\n isRevalidationRequired ||\n // Clicked the same link, resubmitted a GET form\n currentUrl.pathname + currentUrl.search ===\n nextUrl.pathname + nextUrl.search ||\n // Search params affect all loaders\n currentUrl.search !== nextUrl.search ||\n isNewRouteInstance(currentRouteMatch, nextRouteMatch),\n });\n });\n\n // Pick fetcher.loads that need to be revalidated\n let revalidatingFetchers: RevalidatingFetcher[] = [];\n fetchLoadMatches.forEach((f, key) => {\n // Don't revalidate if fetcher won't be present in the subsequent render\n if (!matches.some((m) => m.route.id === f.routeId)) {\n return;\n }\n\n let fetcherMatches = matchRoutes(routesToUse, f.path, basename);\n\n // If the fetcher path no longer matches, push it in with null matches so\n // we can trigger a 404 in callLoadersAndMaybeResolveData. Note this is\n // currently only a use-case for Remix HMR where the route tree can change\n // at runtime and remove a route previously loaded via a fetcher\n if (!fetcherMatches) {\n revalidatingFetchers.push({\n key,\n routeId: f.routeId,\n path: f.path,\n matches: null,\n match: null,\n controller: null,\n });\n return;\n }\n\n // Revalidating fetchers are decoupled from the route matches since they\n // load from a static href. They revalidate based on explicit revalidation\n // (submission, useRevalidator, or X-Remix-Revalidate)\n let fetcher = state.fetchers.get(key);\n let fetcherMatch = getTargetMatch(fetcherMatches, f.path);\n\n let shouldRevalidate = false;\n if (fetchRedirectIds.has(key)) {\n // Never trigger a revalidation of an actively redirecting fetcher\n shouldRevalidate = false;\n } else if (cancelledFetcherLoads.includes(key)) {\n // Always revalidate if the fetcher was cancelled\n shouldRevalidate = true;\n } else if (\n fetcher &&\n fetcher.state !== \"idle\" &&\n fetcher.data === undefined\n ) {\n // If the fetcher hasn't ever completed loading yet, then this isn't a\n // revalidation, it would just be a brand new load if an explicit\n // revalidation is required\n shouldRevalidate = isRevalidationRequired;\n } else {\n // Otherwise fall back on any user-defined shouldRevalidate, defaulting\n // to explicit revalidations only\n shouldRevalidate = shouldRevalidateLoader(fetcherMatch, {\n currentUrl,\n currentParams: state.matches[state.matches.length - 1].params,\n nextUrl,\n nextParams: matches[matches.length - 1].params,\n ...submission,\n actionResult,\n defaultShouldRevalidate: isRevalidationRequired,\n });\n }\n\n if (shouldRevalidate) {\n revalidatingFetchers.push({\n key,\n routeId: f.routeId,\n path: f.path,\n matches: fetcherMatches,\n match: fetcherMatch,\n controller: new AbortController(),\n });\n }\n });\n\n return [navigationMatches, revalidatingFetchers];\n}\n\nfunction isNewLoader(\n currentLoaderData: RouteData,\n currentMatch: AgnosticDataRouteMatch,\n match: AgnosticDataRouteMatch\n) {\n let isNew =\n // [a] -> [a, b]\n !currentMatch ||\n // [a, b] -> [a, c]\n match.route.id !== currentMatch.route.id;\n\n // Handle the case that we don't have data for a re-used route, potentially\n // from a prior error or from a cancelled pending deferred\n let isMissingData = currentLoaderData[match.route.id] === undefined;\n\n // Always load if this is a net-new route or we don't yet have data\n return isNew || isMissingData;\n}\n\nfunction isNewRouteInstance(\n currentMatch: AgnosticDataRouteMatch,\n match: AgnosticDataRouteMatch\n) {\n let currentPath = currentMatch.route.path;\n return (\n // param change for this match, /users/123 -> /users/456\n currentMatch.pathname !== match.pathname ||\n // splat param changed, which is not present in match.path\n // e.g. /files/images/avatar.jpg -> files/finances.xls\n (currentPath != null &&\n currentPath.endsWith(\"*\") &&\n currentMatch.params[\"*\"] !== match.params[\"*\"])\n );\n}\n\nfunction shouldRevalidateLoader(\n loaderMatch: AgnosticDataRouteMatch,\n arg: ShouldRevalidateFunctionArgs\n) {\n if (loaderMatch.route.shouldRevalidate) {\n let routeChoice = loaderMatch.route.shouldRevalidate(arg);\n if (typeof routeChoice === \"boolean\") {\n return routeChoice;\n }\n }\n\n return arg.defaultShouldRevalidate;\n}\n\n/**\n * Execute route.lazy() methods to lazily load route modules (loader, action,\n * shouldRevalidate) and update the routeManifest in place which shares objects\n * with dataRoutes so those get updated as well.\n */\nasync function loadLazyRouteModule(\n route: AgnosticDataRouteObject,\n mapRouteProperties: MapRoutePropertiesFunction,\n manifest: RouteManifest\n) {\n if (!route.lazy) {\n return;\n }\n\n let lazyRoute = await route.lazy();\n\n // If the lazy route function was executed and removed by another parallel\n // call then we can return - first lazy() to finish wins because the return\n // value of lazy is expected to be static\n if (!route.lazy) {\n return;\n }\n\n let routeToUpdate = manifest[route.id];\n invariant(routeToUpdate, \"No route found in manifest\");\n\n // Update the route in place. This should be safe because there's no way\n // we could yet be sitting on this route as we can't get there without\n // resolving lazy() first.\n //\n // This is different than the HMR \"update\" use-case where we may actively be\n // on the route being updated. The main concern boils down to \"does this\n // mutation affect any ongoing navigations or any current state.matches\n // values?\". If not, it should be safe to update in place.\n let routeUpdates: Record = {};\n for (let lazyRouteProperty in lazyRoute) {\n let staticRouteValue =\n routeToUpdate[lazyRouteProperty as keyof typeof routeToUpdate];\n\n let isPropertyStaticallyDefined =\n staticRouteValue !== undefined &&\n // This property isn't static since it should always be updated based\n // on the route updates\n lazyRouteProperty !== \"hasErrorBoundary\";\n\n warning(\n !isPropertyStaticallyDefined,\n `Route \"${routeToUpdate.id}\" has a static property \"${lazyRouteProperty}\" ` +\n `defined but its lazy function is also returning a value for this property. ` +\n `The lazy route property \"${lazyRouteProperty}\" will be ignored.`\n );\n\n if (\n !isPropertyStaticallyDefined &&\n !immutableRouteKeys.has(lazyRouteProperty as ImmutableRouteKey)\n ) {\n routeUpdates[lazyRouteProperty] =\n lazyRoute[lazyRouteProperty as keyof typeof lazyRoute];\n }\n }\n\n // Mutate the route with the provided updates. Do this first so we pass\n // the updated version to mapRouteProperties\n Object.assign(routeToUpdate, routeUpdates);\n\n // Mutate the `hasErrorBoundary` property on the route based on the route\n // updates and remove the `lazy` function so we don't resolve the lazy\n // route again.\n Object.assign(routeToUpdate, {\n // To keep things framework agnostic, we use the provided\n // `mapRouteProperties` (or wrapped `detectErrorBoundary`) function to\n // set the framework-aware properties (`element`/`hasErrorBoundary`) since\n // the logic will differ between frameworks.\n ...mapRouteProperties(routeToUpdate),\n lazy: undefined,\n });\n}\n\nasync function callLoaderOrAction(\n type: \"loader\" | \"action\",\n request: Request,\n match: AgnosticDataRouteMatch,\n matches: AgnosticDataRouteMatch[],\n manifest: RouteManifest,\n mapRouteProperties: MapRoutePropertiesFunction,\n basename: string,\n opts: {\n isStaticRequest?: boolean;\n isRouteRequest?: boolean;\n requestContext?: unknown;\n } = {}\n): Promise {\n let resultType;\n let result;\n let onReject: (() => void) | undefined;\n\n let runHandler = (handler: ActionFunction | LoaderFunction) => {\n // Setup a promise we can race against so that abort signals short circuit\n let reject: () => void;\n let abortPromise = new Promise((_, r) => (reject = r));\n onReject = () => reject();\n request.signal.addEventListener(\"abort\", onReject);\n return Promise.race([\n handler({\n request,\n params: match.params,\n context: opts.requestContext,\n }),\n abortPromise,\n ]);\n };\n\n try {\n let handler = match.route[type];\n\n if (match.route.lazy) {\n if (handler) {\n // Run statically defined handler in parallel with lazy()\n let handlerError;\n let values = await Promise.all([\n // If the handler throws, don't let it immediately bubble out,\n // since we need to let the lazy() execution finish so we know if this\n // route has a boundary that can handle the error\n runHandler(handler).catch((e) => {\n handlerError = e;\n }),\n loadLazyRouteModule(match.route, mapRouteProperties, manifest),\n ]);\n if (handlerError) {\n throw handlerError;\n }\n result = values[0];\n } else {\n // Load lazy route module, then run any returned handler\n await loadLazyRouteModule(match.route, mapRouteProperties, manifest);\n\n handler = match.route[type];\n if (handler) {\n // Handler still run even if we got interrupted to maintain consistency\n // with un-abortable behavior of handler execution on non-lazy or\n // previously-lazy-loaded routes\n result = await runHandler(handler);\n } else if (type === \"action\") {\n let url = new URL(request.url);\n let pathname = url.pathname + url.search;\n throw getInternalRouterError(405, {\n method: request.method,\n pathname,\n routeId: match.route.id,\n });\n } else {\n // lazy() route has no loader to run. Short circuit here so we don't\n // hit the invariant below that errors on returning undefined.\n return { type: ResultType.data, data: undefined };\n }\n }\n } else if (!handler) {\n let url = new URL(request.url);\n let pathname = url.pathname + url.search;\n throw getInternalRouterError(404, {\n pathname,\n });\n } else {\n result = await runHandler(handler);\n }\n\n invariant(\n result !== undefined,\n `You defined ${type === \"action\" ? \"an action\" : \"a loader\"} for route ` +\n `\"${match.route.id}\" but didn't return anything from your \\`${type}\\` ` +\n `function. Please return a value or \\`null\\`.`\n );\n } catch (e) {\n resultType = ResultType.error;\n result = e;\n } finally {\n if (onReject) {\n request.signal.removeEventListener(\"abort\", onReject);\n }\n }\n\n if (isResponse(result)) {\n let status = result.status;\n\n // Process redirects\n if (redirectStatusCodes.has(status)) {\n let location = result.headers.get(\"Location\");\n invariant(\n location,\n \"Redirects returned/thrown from loaders/actions must have a Location header\"\n );\n\n // Support relative routing in internal redirects\n if (!ABSOLUTE_URL_REGEX.test(location)) {\n location = normalizeTo(\n new URL(request.url),\n matches.slice(0, matches.indexOf(match) + 1),\n basename,\n true,\n location\n );\n } else if (!opts.isStaticRequest) {\n // Strip off the protocol+origin for same-origin + same-basename absolute\n // redirects. If this is a static request, we can let it go back to the\n // browser as-is\n let currentUrl = new URL(request.url);\n let url = location.startsWith(\"//\")\n ? new URL(currentUrl.protocol + location)\n : new URL(location);\n let isSameBasename = stripBasename(url.pathname, basename) != null;\n if (url.origin === currentUrl.origin && isSameBasename) {\n location = url.pathname + url.search + url.hash;\n }\n }\n\n // Don't process redirects in the router during static requests requests.\n // Instead, throw the Response and let the server handle it with an HTTP\n // redirect. We also update the Location header in place in this flow so\n // basename and relative routing is taken into account\n if (opts.isStaticRequest) {\n result.headers.set(\"Location\", location);\n throw result;\n }\n\n return {\n type: ResultType.redirect,\n status,\n location,\n revalidate: result.headers.get(\"X-Remix-Revalidate\") !== null,\n reloadDocument: result.headers.get(\"X-Remix-Reload-Document\") !== null,\n };\n }\n\n // For SSR single-route requests, we want to hand Responses back directly\n // without unwrapping. We do this with the QueryRouteResponse wrapper\n // interface so we can know whether it was returned or thrown\n if (opts.isRouteRequest) {\n let queryRouteResponse: QueryRouteResponse = {\n type:\n resultType === ResultType.error ? ResultType.error : ResultType.data,\n response: result,\n };\n throw queryRouteResponse;\n }\n\n let data: any;\n let contentType = result.headers.get(\"Content-Type\");\n // Check between word boundaries instead of startsWith() due to the last\n // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type\n if (contentType && /\\bapplication\\/json\\b/.test(contentType)) {\n data = await result.json();\n } else {\n data = await result.text();\n }\n\n if (resultType === ResultType.error) {\n return {\n type: resultType,\n error: new ErrorResponseImpl(status, result.statusText, data),\n headers: result.headers,\n };\n }\n\n return {\n type: ResultType.data,\n data,\n statusCode: result.status,\n headers: result.headers,\n };\n }\n\n if (resultType === ResultType.error) {\n return { type: resultType, error: result };\n }\n\n if (isDeferredData(result)) {\n return {\n type: ResultType.deferred,\n deferredData: result,\n statusCode: result.init?.status,\n headers: result.init?.headers && new Headers(result.init.headers),\n };\n }\n\n return { type: ResultType.data, data: result };\n}\n\n// Utility method for creating the Request instances for loaders/actions during\n// client-side navigations and fetches. During SSR we will always have a\n// Request instance from the static handler (query/queryRoute)\nfunction createClientSideRequest(\n history: History,\n location: string | Location,\n signal: AbortSignal,\n submission?: Submission\n): Request {\n let url = history.createURL(stripHashFromPath(location)).toString();\n let init: RequestInit = { signal };\n\n if (submission && isMutationMethod(submission.formMethod)) {\n let { formMethod, formEncType } = submission;\n // Didn't think we needed this but it turns out unlike other methods, patch\n // won't be properly normalized to uppercase and results in a 405 error.\n // See: https://fetch.spec.whatwg.org/#concept-method\n init.method = formMethod.toUpperCase();\n\n if (formEncType === \"application/json\") {\n init.headers = new Headers({ \"Content-Type\": formEncType });\n init.body = JSON.stringify(submission.json);\n } else if (formEncType === \"text/plain\") {\n // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)\n init.body = submission.text;\n } else if (\n formEncType === \"application/x-www-form-urlencoded\" &&\n submission.formData\n ) {\n // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)\n init.body = convertFormDataToSearchParams(submission.formData);\n } else {\n // Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)\n init.body = submission.formData;\n }\n }\n\n return new Request(url, init);\n}\n\nfunction convertFormDataToSearchParams(formData: FormData): URLSearchParams {\n let searchParams = new URLSearchParams();\n\n for (let [key, value] of formData.entries()) {\n // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs\n searchParams.append(key, typeof value === \"string\" ? value : value.name);\n }\n\n return searchParams;\n}\n\nfunction convertSearchParamsToFormData(\n searchParams: URLSearchParams\n): FormData {\n let formData = new FormData();\n for (let [key, value] of searchParams.entries()) {\n formData.append(key, value);\n }\n return formData;\n}\n\nfunction processRouteLoaderData(\n matches: AgnosticDataRouteMatch[],\n matchesToLoad: AgnosticDataRouteMatch[],\n results: DataResult[],\n pendingError: RouteData | undefined,\n activeDeferreds: Map\n): {\n loaderData: RouterState[\"loaderData\"];\n errors: RouterState[\"errors\"] | null;\n statusCode: number;\n loaderHeaders: Record;\n} {\n // Fill in loaderData/errors from our loaders\n let loaderData: RouterState[\"loaderData\"] = {};\n let errors: RouterState[\"errors\"] | null = null;\n let statusCode: number | undefined;\n let foundError = false;\n let loaderHeaders: Record = {};\n\n // Process loader results into state.loaderData/state.errors\n results.forEach((result, index) => {\n let id = matchesToLoad[index].route.id;\n invariant(\n !isRedirectResult(result),\n \"Cannot handle redirect results in processLoaderData\"\n );\n if (isErrorResult(result)) {\n // Look upwards from the matched route for the closest ancestor\n // error boundary, defaulting to the root match\n let boundaryMatch = findNearestBoundary(matches, id);\n let error = result.error;\n // If we have a pending action error, we report it at the highest-route\n // that throws a loader error, and then clear it out to indicate that\n // it was consumed\n if (pendingError) {\n error = Object.values(pendingError)[0];\n pendingError = undefined;\n }\n\n errors = errors || {};\n\n // Prefer higher error values if lower errors bubble to the same boundary\n if (errors[boundaryMatch.route.id] == null) {\n errors[boundaryMatch.route.id] = error;\n }\n\n // Clear our any prior loaderData for the throwing route\n loaderData[id] = undefined;\n\n // Once we find our first (highest) error, we set the status code and\n // prevent deeper status codes from overriding\n if (!foundError) {\n foundError = true;\n statusCode = isRouteErrorResponse(result.error)\n ? result.error.status\n : 500;\n }\n if (result.headers) {\n loaderHeaders[id] = result.headers;\n }\n } else {\n if (isDeferredResult(result)) {\n activeDeferreds.set(id, result.deferredData);\n loaderData[id] = result.deferredData.data;\n } else {\n loaderData[id] = result.data;\n }\n\n // Error status codes always override success status codes, but if all\n // loaders are successful we take the deepest status code.\n if (\n result.statusCode != null &&\n result.statusCode !== 200 &&\n !foundError\n ) {\n statusCode = result.statusCode;\n }\n if (result.headers) {\n loaderHeaders[id] = result.headers;\n }\n }\n });\n\n // If we didn't consume the pending action error (i.e., all loaders\n // resolved), then consume it here. Also clear out any loaderData for the\n // throwing route\n if (pendingError) {\n errors = pendingError;\n loaderData[Object.keys(pendingError)[0]] = undefined;\n }\n\n return {\n loaderData,\n errors,\n statusCode: statusCode || 200,\n loaderHeaders,\n };\n}\n\nfunction processLoaderData(\n state: RouterState,\n matches: AgnosticDataRouteMatch[],\n matchesToLoad: AgnosticDataRouteMatch[],\n results: DataResult[],\n pendingError: RouteData | undefined,\n revalidatingFetchers: RevalidatingFetcher[],\n fetcherResults: DataResult[],\n activeDeferreds: Map\n): {\n loaderData: RouterState[\"loaderData\"];\n errors?: RouterState[\"errors\"];\n} {\n let { loaderData, errors } = processRouteLoaderData(\n matches,\n matchesToLoad,\n results,\n pendingError,\n activeDeferreds\n );\n\n // Process results from our revalidating fetchers\n for (let index = 0; index < revalidatingFetchers.length; index++) {\n let { key, match, controller } = revalidatingFetchers[index];\n invariant(\n fetcherResults !== undefined && fetcherResults[index] !== undefined,\n \"Did not find corresponding fetcher result\"\n );\n let result = fetcherResults[index];\n\n // Process fetcher non-redirect errors\n if (controller && controller.signal.aborted) {\n // Nothing to do for aborted fetchers\n continue;\n } else if (isErrorResult(result)) {\n let boundaryMatch = findNearestBoundary(state.matches, match?.route.id);\n if (!(errors && errors[boundaryMatch.route.id])) {\n errors = {\n ...errors,\n [boundaryMatch.route.id]: result.error,\n };\n }\n state.fetchers.delete(key);\n } else if (isRedirectResult(result)) {\n // Should never get here, redirects should get processed above, but we\n // keep this to type narrow to a success result in the else\n invariant(false, \"Unhandled fetcher revalidation redirect\");\n } else if (isDeferredResult(result)) {\n // Should never get here, deferred data should be awaited for fetchers\n // in resolveDeferredResults\n invariant(false, \"Unhandled fetcher deferred data\");\n } else {\n let doneFetcher = getDoneFetcher(result.data);\n state.fetchers.set(key, doneFetcher);\n }\n }\n\n return { loaderData, errors };\n}\n\nfunction mergeLoaderData(\n loaderData: RouteData,\n newLoaderData: RouteData,\n matches: AgnosticDataRouteMatch[],\n errors: RouteData | null | undefined\n): RouteData {\n let mergedLoaderData = { ...newLoaderData };\n for (let match of matches) {\n let id = match.route.id;\n if (newLoaderData.hasOwnProperty(id)) {\n if (newLoaderData[id] !== undefined) {\n mergedLoaderData[id] = newLoaderData[id];\n } else {\n // No-op - this is so we ignore existing data if we have a key in the\n // incoming object with an undefined value, which is how we unset a prior\n // loaderData if we encounter a loader error\n }\n } else if (loaderData[id] !== undefined && match.route.loader) {\n // Preserve existing keys not included in newLoaderData and where a loader\n // wasn't removed by HMR\n mergedLoaderData[id] = loaderData[id];\n }\n\n if (errors && errors.hasOwnProperty(id)) {\n // Don't keep any loader data below the boundary\n break;\n }\n }\n return mergedLoaderData;\n}\n\n// Find the nearest error boundary, looking upwards from the leaf route (or the\n// route specified by routeId) for the closest ancestor error boundary,\n// defaulting to the root match\nfunction findNearestBoundary(\n matches: AgnosticDataRouteMatch[],\n routeId?: string\n): AgnosticDataRouteMatch {\n let eligibleMatches = routeId\n ? matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1)\n : [...matches];\n return (\n eligibleMatches.reverse().find((m) => m.route.hasErrorBoundary === true) ||\n matches[0]\n );\n}\n\nfunction getShortCircuitMatches(routes: AgnosticDataRouteObject[]): {\n matches: AgnosticDataRouteMatch[];\n route: AgnosticDataRouteObject;\n} {\n // Prefer a root layout route if present, otherwise shim in a route object\n let route =\n routes.length === 1\n ? routes[0]\n : routes.find((r) => r.index || !r.path || r.path === \"/\") || {\n id: `__shim-error-route__`,\n };\n\n return {\n matches: [\n {\n params: {},\n pathname: \"\",\n pathnameBase: \"\",\n route,\n },\n ],\n route,\n };\n}\n\nfunction getInternalRouterError(\n status: number,\n {\n pathname,\n routeId,\n method,\n type,\n }: {\n pathname?: string;\n routeId?: string;\n method?: string;\n type?: \"defer-action\" | \"invalid-body\";\n } = {}\n) {\n let statusText = \"Unknown Server Error\";\n let errorMessage = \"Unknown @remix-run/router error\";\n\n if (status === 400) {\n statusText = \"Bad Request\";\n if (method && pathname && routeId) {\n errorMessage =\n `You made a ${method} request to \"${pathname}\" but ` +\n `did not provide a \\`loader\\` for route \"${routeId}\", ` +\n `so there is no way to handle the request.`;\n } else if (type === \"defer-action\") {\n errorMessage = \"defer() is not supported in actions\";\n } else if (type === \"invalid-body\") {\n errorMessage = \"Unable to encode submission body\";\n }\n } else if (status === 403) {\n statusText = \"Forbidden\";\n errorMessage = `Route \"${routeId}\" does not match URL \"${pathname}\"`;\n } else if (status === 404) {\n statusText = \"Not Found\";\n errorMessage = `No route matches URL \"${pathname}\"`;\n } else if (status === 405) {\n statusText = \"Method Not Allowed\";\n if (method && pathname && routeId) {\n errorMessage =\n `You made a ${method.toUpperCase()} request to \"${pathname}\" but ` +\n `did not provide an \\`action\\` for route \"${routeId}\", ` +\n `so there is no way to handle the request.`;\n } else if (method) {\n errorMessage = `Invalid request method \"${method.toUpperCase()}\"`;\n }\n }\n\n return new ErrorResponseImpl(\n status || 500,\n statusText,\n new Error(errorMessage),\n true\n );\n}\n\n// Find any returned redirect errors, starting from the lowest match\nfunction findRedirect(\n results: DataResult[]\n): { result: RedirectResult; idx: number } | undefined {\n for (let i = results.length - 1; i >= 0; i--) {\n let result = results[i];\n if (isRedirectResult(result)) {\n return { result, idx: i };\n }\n }\n}\n\nfunction stripHashFromPath(path: To) {\n let parsedPath = typeof path === \"string\" ? parsePath(path) : path;\n return createPath({ ...parsedPath, hash: \"\" });\n}\n\nfunction isHashChangeOnly(a: Location, b: Location): boolean {\n if (a.pathname !== b.pathname || a.search !== b.search) {\n return false;\n }\n\n if (a.hash === \"\") {\n // /page -> /page#hash\n return b.hash !== \"\";\n } else if (a.hash === b.hash) {\n // /page#hash -> /page#hash\n return true;\n } else if (b.hash !== \"\") {\n // /page#hash -> /page#other\n return true;\n }\n\n // If the hash is removed the browser will re-perform a request to the server\n // /page#hash -> /page\n return false;\n}\n\nfunction isDeferredResult(result: DataResult): result is DeferredResult {\n return result.type === ResultType.deferred;\n}\n\nfunction isErrorResult(result: DataResult): result is ErrorResult {\n return result.type === ResultType.error;\n}\n\nfunction isRedirectResult(result?: DataResult): result is RedirectResult {\n return (result && result.type) === ResultType.redirect;\n}\n\nexport function isDeferredData(value: any): value is DeferredData {\n let deferred: DeferredData = value;\n return (\n deferred &&\n typeof deferred === \"object\" &&\n typeof deferred.data === \"object\" &&\n typeof deferred.subscribe === \"function\" &&\n typeof deferred.cancel === \"function\" &&\n typeof deferred.resolveData === \"function\"\n );\n}\n\nfunction isResponse(value: any): value is Response {\n return (\n value != null &&\n typeof value.status === \"number\" &&\n typeof value.statusText === \"string\" &&\n typeof value.headers === \"object\" &&\n typeof value.body !== \"undefined\"\n );\n}\n\nfunction isRedirectResponse(result: any): result is Response {\n if (!isResponse(result)) {\n return false;\n }\n\n let status = result.status;\n let location = result.headers.get(\"Location\");\n return status >= 300 && status <= 399 && location != null;\n}\n\nfunction isQueryRouteResponse(obj: any): obj is QueryRouteResponse {\n return (\n obj &&\n isResponse(obj.response) &&\n (obj.type === ResultType.data || obj.type === ResultType.error)\n );\n}\n\nfunction isValidMethod(method: string): method is FormMethod | V7_FormMethod {\n return validRequestMethods.has(method.toLowerCase() as FormMethod);\n}\n\nfunction isMutationMethod(\n method: string\n): method is MutationFormMethod | V7_MutationFormMethod {\n return validMutationMethods.has(method.toLowerCase() as MutationFormMethod);\n}\n\nasync function resolveDeferredResults(\n currentMatches: AgnosticDataRouteMatch[],\n matchesToLoad: (AgnosticDataRouteMatch | null)[],\n results: DataResult[],\n signals: (AbortSignal | null)[],\n isFetcher: boolean,\n currentLoaderData?: RouteData\n) {\n for (let index = 0; index < results.length; index++) {\n let result = results[index];\n let match = matchesToLoad[index];\n // If we don't have a match, then we can have a deferred result to do\n // anything with. This is for revalidating fetchers where the route was\n // removed during HMR\n if (!match) {\n continue;\n }\n\n let currentMatch = currentMatches.find(\n (m) => m.route.id === match!.route.id\n );\n let isRevalidatingLoader =\n currentMatch != null &&\n !isNewRouteInstance(currentMatch, match) &&\n (currentLoaderData && currentLoaderData[match.route.id]) !== undefined;\n\n if (isDeferredResult(result) && (isFetcher || isRevalidatingLoader)) {\n // Note: we do not have to touch activeDeferreds here since we race them\n // against the signal in resolveDeferredData and they'll get aborted\n // there if needed\n let signal = signals[index];\n invariant(\n signal,\n \"Expected an AbortSignal for revalidating fetcher deferred result\"\n );\n await resolveDeferredData(result, signal, isFetcher).then((result) => {\n if (result) {\n results[index] = result || results[index];\n }\n });\n }\n }\n}\n\nasync function resolveDeferredData(\n result: DeferredResult,\n signal: AbortSignal,\n unwrap = false\n): Promise {\n let aborted = await result.deferredData.resolveData(signal);\n if (aborted) {\n return;\n }\n\n if (unwrap) {\n try {\n return {\n type: ResultType.data,\n data: result.deferredData.unwrappedData,\n };\n } catch (e) {\n // Handle any TrackedPromise._error values encountered while unwrapping\n return {\n type: ResultType.error,\n error: e,\n };\n }\n }\n\n return {\n type: ResultType.data,\n data: result.deferredData.data,\n };\n}\n\nfunction hasNakedIndexQuery(search: string): boolean {\n return new URLSearchParams(search).getAll(\"index\").some((v) => v === \"\");\n}\n\nfunction getTargetMatch(\n matches: AgnosticDataRouteMatch[],\n location: Location | string\n) {\n let search =\n typeof location === \"string\" ? parsePath(location).search : location.search;\n if (\n matches[matches.length - 1].route.index &&\n hasNakedIndexQuery(search || \"\")\n ) {\n // Return the leaf index route when index is present\n return matches[matches.length - 1];\n }\n // Otherwise grab the deepest \"path contributing\" match (ignoring index and\n // pathless layout routes)\n let pathMatches = getPathContributingMatches(matches);\n return pathMatches[pathMatches.length - 1];\n}\n\nfunction getSubmissionFromNavigation(\n navigation: Navigation\n): Submission | undefined {\n let { formMethod, formAction, formEncType, text, formData, json } =\n navigation;\n if (!formMethod || !formAction || !formEncType) {\n return;\n }\n\n if (text != null) {\n return {\n formMethod,\n formAction,\n formEncType,\n formData: undefined,\n json: undefined,\n text,\n };\n } else if (formData != null) {\n return {\n formMethod,\n formAction,\n formEncType,\n formData,\n json: undefined,\n text: undefined,\n };\n } else if (json !== undefined) {\n return {\n formMethod,\n formAction,\n formEncType,\n formData: undefined,\n json,\n text: undefined,\n };\n }\n}\n\nfunction getLoadingNavigation(\n location: Location,\n submission?: Submission\n): NavigationStates[\"Loading\"] {\n if (submission) {\n let navigation: NavigationStates[\"Loading\"] = {\n state: \"loading\",\n location,\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n };\n return navigation;\n } else {\n let navigation: NavigationStates[\"Loading\"] = {\n state: \"loading\",\n location,\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n };\n return navigation;\n }\n}\n\nfunction getSubmittingNavigation(\n location: Location,\n submission: Submission\n): NavigationStates[\"Submitting\"] {\n let navigation: NavigationStates[\"Submitting\"] = {\n state: \"submitting\",\n location,\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n };\n return navigation;\n}\n\nfunction getLoadingFetcher(\n submission?: Submission,\n data?: Fetcher[\"data\"]\n): FetcherStates[\"Loading\"] {\n if (submission) {\n let fetcher: FetcherStates[\"Loading\"] = {\n state: \"loading\",\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n data,\n };\n return fetcher;\n } else {\n let fetcher: FetcherStates[\"Loading\"] = {\n state: \"loading\",\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n data,\n };\n return fetcher;\n }\n}\n\nfunction getSubmittingFetcher(\n submission: Submission,\n existingFetcher?: Fetcher\n): FetcherStates[\"Submitting\"] {\n let fetcher: FetcherStates[\"Submitting\"] = {\n state: \"submitting\",\n formMethod: submission.formMethod,\n formAction: submission.formAction,\n formEncType: submission.formEncType,\n formData: submission.formData,\n json: submission.json,\n text: submission.text,\n data: existingFetcher ? existingFetcher.data : undefined,\n };\n return fetcher;\n}\n\nfunction getDoneFetcher(data: Fetcher[\"data\"]): FetcherStates[\"Idle\"] {\n let fetcher: FetcherStates[\"Idle\"] = {\n state: \"idle\",\n formMethod: undefined,\n formAction: undefined,\n formEncType: undefined,\n formData: undefined,\n json: undefined,\n text: undefined,\n data,\n };\n return fetcher;\n}\n\nfunction restoreAppliedTransitions(\n _window: Window,\n transitions: Map>\n) {\n try {\n let sessionPositions = _window.sessionStorage.getItem(\n TRANSITIONS_STORAGE_KEY\n );\n if (sessionPositions) {\n let json = JSON.parse(sessionPositions);\n for (let [k, v] of Object.entries(json || {})) {\n if (v && Array.isArray(v)) {\n transitions.set(k, new Set(v || []));\n }\n }\n }\n } catch (e) {\n // no-op, use default empty object\n }\n}\n\nfunction persistAppliedTransitions(\n _window: Window,\n transitions: Map>\n) {\n if (transitions.size > 0) {\n let json: Record = {};\n for (let [k, v] of transitions) {\n json[k] = [...v];\n }\n try {\n _window.sessionStorage.setItem(\n TRANSITIONS_STORAGE_KEY,\n JSON.stringify(json)\n );\n } catch (error) {\n warning(\n false,\n `Failed to save applied view transitions in sessionStorage (${error}).`\n );\n }\n }\n}\n\n//#endregion\n","import * as React from \"react\";\nimport type {\n AgnosticIndexRouteObject,\n AgnosticNonIndexRouteObject,\n AgnosticRouteMatch,\n History,\n LazyRouteFunction,\n Location,\n Action as NavigationType,\n RelativeRoutingType,\n Router,\n StaticHandlerContext,\n To,\n TrackedPromise,\n} from \"@remix-run/router\";\n\n// Create react-specific types from the agnostic types in @remix-run/router to\n// export from react-router\nexport interface IndexRouteObject {\n caseSensitive?: AgnosticIndexRouteObject[\"caseSensitive\"];\n path?: AgnosticIndexRouteObject[\"path\"];\n id?: AgnosticIndexRouteObject[\"id\"];\n loader?: AgnosticIndexRouteObject[\"loader\"];\n action?: AgnosticIndexRouteObject[\"action\"];\n hasErrorBoundary?: AgnosticIndexRouteObject[\"hasErrorBoundary\"];\n shouldRevalidate?: AgnosticIndexRouteObject[\"shouldRevalidate\"];\n handle?: AgnosticIndexRouteObject[\"handle\"];\n index: true;\n children?: undefined;\n element?: React.ReactNode | null;\n errorElement?: React.ReactNode | null;\n Component?: React.ComponentType | null;\n ErrorBoundary?: React.ComponentType | null;\n lazy?: LazyRouteFunction;\n}\n\nexport interface NonIndexRouteObject {\n caseSensitive?: AgnosticNonIndexRouteObject[\"caseSensitive\"];\n path?: AgnosticNonIndexRouteObject[\"path\"];\n id?: AgnosticNonIndexRouteObject[\"id\"];\n loader?: AgnosticNonIndexRouteObject[\"loader\"];\n action?: AgnosticNonIndexRouteObject[\"action\"];\n hasErrorBoundary?: AgnosticNonIndexRouteObject[\"hasErrorBoundary\"];\n shouldRevalidate?: AgnosticNonIndexRouteObject[\"shouldRevalidate\"];\n handle?: AgnosticNonIndexRouteObject[\"handle\"];\n index?: false;\n children?: RouteObject[];\n element?: React.ReactNode | null;\n errorElement?: React.ReactNode | null;\n Component?: React.ComponentType | null;\n ErrorBoundary?: React.ComponentType | null;\n lazy?: LazyRouteFunction;\n}\n\nexport type RouteObject = IndexRouteObject | NonIndexRouteObject;\n\nexport type DataRouteObject = RouteObject & {\n children?: DataRouteObject[];\n id: string;\n};\n\nexport interface RouteMatch<\n ParamKey extends string = string,\n RouteObjectType extends RouteObject = RouteObject\n> extends AgnosticRouteMatch {}\n\nexport interface DataRouteMatch extends RouteMatch {}\n\nexport interface DataRouterContextObject extends NavigationContextObject {\n router: Router;\n staticContext?: StaticHandlerContext;\n}\n\nexport const DataRouterContext =\n React.createContext(null);\nif (__DEV__) {\n DataRouterContext.displayName = \"DataRouter\";\n}\n\nexport const DataRouterStateContext = React.createContext<\n Router[\"state\"] | null\n>(null);\nif (__DEV__) {\n DataRouterStateContext.displayName = \"DataRouterState\";\n}\n\nexport const AwaitContext = React.createContext(null);\nif (__DEV__) {\n AwaitContext.displayName = \"Await\";\n}\n\nexport interface NavigateOptions {\n replace?: boolean;\n state?: any;\n preventScrollReset?: boolean;\n relative?: RelativeRoutingType;\n unstable_viewTransition?: boolean;\n}\n\n/**\n * A Navigator is a \"location changer\"; it's how you get to different locations.\n *\n * Every history instance conforms to the Navigator interface, but the\n * distinction is useful primarily when it comes to the low-level `` API\n * where both the location and a navigator must be provided separately in order\n * to avoid \"tearing\" that may occur in a suspense-enabled app if the action\n * and/or location were to be read directly from the history instance.\n */\nexport interface Navigator {\n createHref: History[\"createHref\"];\n // Optional for backwards-compat with Router/HistoryRouter usage (edge case)\n encodeLocation?: History[\"encodeLocation\"];\n go: History[\"go\"];\n push(to: To, state?: any, opts?: NavigateOptions): void;\n replace(to: To, state?: any, opts?: NavigateOptions): void;\n}\n\ninterface NavigationContextObject {\n basename: string;\n navigator: Navigator;\n static: boolean;\n}\n\nexport const NavigationContext = React.createContext(\n null!\n);\n\nif (__DEV__) {\n NavigationContext.displayName = \"Navigation\";\n}\n\ninterface LocationContextObject {\n location: Location;\n navigationType: NavigationType;\n}\n\nexport const LocationContext = React.createContext(\n null!\n);\n\nif (__DEV__) {\n LocationContext.displayName = \"Location\";\n}\n\nexport interface RouteContextObject {\n outlet: React.ReactElement | null;\n matches: RouteMatch[];\n isDataRoute: boolean;\n}\n\nexport const RouteContext = React.createContext({\n outlet: null,\n matches: [],\n isDataRoute: false,\n});\n\nif (__DEV__) {\n RouteContext.displayName = \"Route\";\n}\n\nexport const RouteErrorContext = React.createContext(null);\n\nif (__DEV__) {\n RouteErrorContext.displayName = \"RouteError\";\n}\n","import * as React from \"react\";\nimport type {\n Blocker,\n BlockerFunction,\n Location,\n ParamParseKey,\n Params,\n Path,\n PathMatch,\n PathPattern,\n RelativeRoutingType,\n Router as RemixRouter,\n RevalidationState,\n To,\n UIMatch,\n} from \"@remix-run/router\";\nimport {\n IDLE_BLOCKER,\n Action as NavigationType,\n UNSAFE_convertRouteMatchToUiMatch as convertRouteMatchToUiMatch,\n UNSAFE_getPathContributingMatches as getPathContributingMatches,\n UNSAFE_invariant as invariant,\n isRouteErrorResponse,\n joinPaths,\n matchPath,\n matchRoutes,\n parsePath,\n resolveTo,\n stripBasename,\n UNSAFE_warning as warning,\n} from \"@remix-run/router\";\n\nimport type {\n DataRouteMatch,\n NavigateOptions,\n RouteContextObject,\n RouteMatch,\n RouteObject,\n} from \"./context\";\nimport {\n AwaitContext,\n DataRouterContext,\n DataRouterStateContext,\n LocationContext,\n NavigationContext,\n RouteContext,\n RouteErrorContext,\n} from \"./context\";\n\n/**\n * Returns the full href for the given \"to\" value. This is useful for building\n * custom links that are also accessible and preserve right-click behavior.\n *\n * @see https://reactrouter.com/hooks/use-href\n */\nexport function useHref(\n to: To,\n { relative }: { relative?: RelativeRoutingType } = {}\n): string {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useHref() may be used only in the context of a component.`\n );\n\n let { basename, navigator } = React.useContext(NavigationContext);\n let { hash, pathname, search } = useResolvedPath(to, { relative });\n\n let joinedPathname = pathname;\n\n // If we're operating within a basename, prepend it to the pathname prior\n // to creating the href. If this is a root navigation, then just use the raw\n // basename which allows the basename to have full control over the presence\n // of a trailing slash on root links\n if (basename !== \"/\") {\n joinedPathname =\n pathname === \"/\" ? basename : joinPaths([basename, pathname]);\n }\n\n return navigator.createHref({ pathname: joinedPathname, search, hash });\n}\n\n/**\n * Returns true if this component is a descendant of a ``.\n *\n * @see https://reactrouter.com/hooks/use-in-router-context\n */\nexport function useInRouterContext(): boolean {\n return React.useContext(LocationContext) != null;\n}\n\n/**\n * Returns the current location object, which represents the current URL in web\n * browsers.\n *\n * Note: If you're using this it may mean you're doing some of your own\n * \"routing\" in your app, and we'd like to know what your use case is. We may\n * be able to provide something higher-level to better suit your needs.\n *\n * @see https://reactrouter.com/hooks/use-location\n */\nexport function useLocation(): Location {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useLocation() may be used only in the context of a component.`\n );\n\n return React.useContext(LocationContext).location;\n}\n\n/**\n * Returns the current navigation action which describes how the router came to\n * the current location, either by a pop, push, or replace on the history stack.\n *\n * @see https://reactrouter.com/hooks/use-navigation-type\n */\nexport function useNavigationType(): NavigationType {\n return React.useContext(LocationContext).navigationType;\n}\n\n/**\n * Returns a PathMatch object if the given pattern matches the current URL.\n * This is useful for components that need to know \"active\" state, e.g.\n * ``.\n *\n * @see https://reactrouter.com/hooks/use-match\n */\nexport function useMatch<\n ParamKey extends ParamParseKey,\n Path extends string\n>(pattern: PathPattern | Path): PathMatch | null {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useMatch() may be used only in the context of a component.`\n );\n\n let { pathname } = useLocation();\n return React.useMemo(\n () => matchPath(pattern, pathname),\n [pathname, pattern]\n );\n}\n\n/**\n * The interface for the navigate() function returned from useNavigate().\n */\nexport interface NavigateFunction {\n (to: To, options?: NavigateOptions): void;\n (delta: number): void;\n}\n\nconst navigateEffectWarning =\n `You should call navigate() in a React.useEffect(), not when ` +\n `your component is first rendered.`;\n\n// Mute warnings for calls to useNavigate in SSR environments\nfunction useIsomorphicLayoutEffect(\n cb: Parameters[0]\n) {\n let isStatic = React.useContext(NavigationContext).static;\n if (!isStatic) {\n // We should be able to get rid of this once react 18.3 is released\n // See: https://github.com/facebook/react/pull/26395\n // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useLayoutEffect(cb);\n }\n}\n\n/**\n * Returns an imperative method for changing the location. Used by ``s, but\n * may also be used by other elements to change the location.\n *\n * @see https://reactrouter.com/hooks/use-navigate\n */\nexport function useNavigate(): NavigateFunction {\n let { isDataRoute } = React.useContext(RouteContext);\n // Conditional usage is OK here because the usage of a data router is static\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return isDataRoute ? useNavigateStable() : useNavigateUnstable();\n}\n\nfunction useNavigateUnstable(): NavigateFunction {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useNavigate() may be used only in the context of a component.`\n );\n\n let dataRouterContext = React.useContext(DataRouterContext);\n let { basename, navigator } = React.useContext(NavigationContext);\n let { matches } = React.useContext(RouteContext);\n let { pathname: locationPathname } = useLocation();\n\n let routePathnamesJson = JSON.stringify(\n getPathContributingMatches(matches).map((match) => match.pathnameBase)\n );\n\n let activeRef = React.useRef(false);\n useIsomorphicLayoutEffect(() => {\n activeRef.current = true;\n });\n\n let navigate: NavigateFunction = React.useCallback(\n (to: To | number, options: NavigateOptions = {}) => {\n warning(activeRef.current, navigateEffectWarning);\n\n // Short circuit here since if this happens on first render the navigate\n // is useless because we haven't wired up our history listener yet\n if (!activeRef.current) return;\n\n if (typeof to === \"number\") {\n navigator.go(to);\n return;\n }\n\n let path = resolveTo(\n to,\n JSON.parse(routePathnamesJson),\n locationPathname,\n options.relative === \"path\"\n );\n\n // If we're operating within a basename, prepend it to the pathname prior\n // to handing off to history (but only if we're not in a data router,\n // otherwise it'll prepend the basename inside of the router).\n // If this is a root navigation, then we navigate to the raw basename\n // which allows the basename to have full control over the presence of a\n // trailing slash on root links\n if (dataRouterContext == null && basename !== \"/\") {\n path.pathname =\n path.pathname === \"/\"\n ? basename\n : joinPaths([basename, path.pathname]);\n }\n\n (!!options.replace ? navigator.replace : navigator.push)(\n path,\n options.state,\n options\n );\n },\n [\n basename,\n navigator,\n routePathnamesJson,\n locationPathname,\n dataRouterContext,\n ]\n );\n\n return navigate;\n}\n\nconst OutletContext = React.createContext(null);\n\n/**\n * Returns the context (if provided) for the child route at this level of the route\n * hierarchy.\n * @see https://reactrouter.com/hooks/use-outlet-context\n */\nexport function useOutletContext(): Context {\n return React.useContext(OutletContext) as Context;\n}\n\n/**\n * Returns the element for the child route at this level of the route\n * hierarchy. Used internally by `` to render child routes.\n *\n * @see https://reactrouter.com/hooks/use-outlet\n */\nexport function useOutlet(context?: unknown): React.ReactElement | null {\n let outlet = React.useContext(RouteContext).outlet;\n if (outlet) {\n return (\n {outlet}\n );\n }\n return outlet;\n}\n\n/**\n * Returns an object of key/value pairs of the dynamic params from the current\n * URL that were matched by the route path.\n *\n * @see https://reactrouter.com/hooks/use-params\n */\nexport function useParams<\n ParamsOrKey extends string | Record = string\n>(): Readonly<\n [ParamsOrKey] extends [string] ? Params : Partial\n> {\n let { matches } = React.useContext(RouteContext);\n let routeMatch = matches[matches.length - 1];\n return routeMatch ? (routeMatch.params as any) : {};\n}\n\n/**\n * Resolves the pathname of the given `to` value against the current location.\n *\n * @see https://reactrouter.com/hooks/use-resolved-path\n */\nexport function useResolvedPath(\n to: To,\n { relative }: { relative?: RelativeRoutingType } = {}\n): Path {\n let { matches } = React.useContext(RouteContext);\n let { pathname: locationPathname } = useLocation();\n\n let routePathnamesJson = JSON.stringify(\n getPathContributingMatches(matches).map((match) => match.pathnameBase)\n );\n\n return React.useMemo(\n () =>\n resolveTo(\n to,\n JSON.parse(routePathnamesJson),\n locationPathname,\n relative === \"path\"\n ),\n [to, routePathnamesJson, locationPathname, relative]\n );\n}\n\n/**\n * Returns the element of the route that matched the current location, prepared\n * with the correct context to render the remainder of the route tree. Route\n * elements in the tree must render an `` to render their child route's\n * element.\n *\n * @see https://reactrouter.com/hooks/use-routes\n */\nexport function useRoutes(\n routes: RouteObject[],\n locationArg?: Partial | string\n): React.ReactElement | null {\n return useRoutesImpl(routes, locationArg);\n}\n\n// Internal implementation with accept optional param for RouterProvider usage\nexport function useRoutesImpl(\n routes: RouteObject[],\n locationArg?: Partial | string,\n dataRouterState?: RemixRouter[\"state\"]\n): React.ReactElement | null {\n invariant(\n useInRouterContext(),\n // TODO: This error is probably because they somehow have 2 versions of the\n // router loaded. We can help them understand how to avoid that.\n `useRoutes() may be used only in the context of a component.`\n );\n\n let { navigator } = React.useContext(NavigationContext);\n let { matches: parentMatches } = React.useContext(RouteContext);\n let routeMatch = parentMatches[parentMatches.length - 1];\n let parentParams = routeMatch ? routeMatch.params : {};\n let parentPathname = routeMatch ? routeMatch.pathname : \"/\";\n let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : \"/\";\n let parentRoute = routeMatch && routeMatch.route;\n\n if (__DEV__) {\n // You won't get a warning about 2 different under a \n // without a trailing *, but this is a best-effort warning anyway since we\n // cannot even give the warning unless they land at the parent route.\n //\n // Example:\n //\n // \n // {/* This route path MUST end with /* because otherwise\n // it will never match /blog/post/123 */}\n // } />\n // } />\n // \n //\n // function Blog() {\n // return (\n // \n // } />\n // \n // );\n // }\n let parentPath = (parentRoute && parentRoute.path) || \"\";\n warningOnce(\n parentPathname,\n !parentRoute || parentPath.endsWith(\"*\"),\n `You rendered descendant (or called \\`useRoutes()\\`) at ` +\n `\"${parentPathname}\" (under ) but the ` +\n `parent route path has no trailing \"*\". This means if you navigate ` +\n `deeper, the parent won't match anymore and therefore the child ` +\n `routes will never render.\\n\\n` +\n `Please change the parent to .`\n );\n }\n\n let locationFromContext = useLocation();\n\n let location;\n if (locationArg) {\n let parsedLocationArg =\n typeof locationArg === \"string\" ? parsePath(locationArg) : locationArg;\n\n invariant(\n parentPathnameBase === \"/\" ||\n parsedLocationArg.pathname?.startsWith(parentPathnameBase),\n `When overriding the location using \\`\\` or \\`useRoutes(routes, location)\\`, ` +\n `the location pathname must begin with the portion of the URL pathname that was ` +\n `matched by all parent routes. The current pathname base is \"${parentPathnameBase}\" ` +\n `but pathname \"${parsedLocationArg.pathname}\" was given in the \\`location\\` prop.`\n );\n\n location = parsedLocationArg;\n } else {\n location = locationFromContext;\n }\n\n let pathname = location.pathname || \"/\";\n let remainingPathname =\n parentPathnameBase === \"/\"\n ? pathname\n : pathname.slice(parentPathnameBase.length) || \"/\";\n\n let matches = matchRoutes(routes, { pathname: remainingPathname });\n\n if (__DEV__) {\n warning(\n parentRoute || matches != null,\n `No routes matched location \"${location.pathname}${location.search}${location.hash}\" `\n );\n\n warning(\n matches == null ||\n matches[matches.length - 1].route.element !== undefined ||\n matches[matches.length - 1].route.Component !== undefined,\n `Matched leaf route at location \"${location.pathname}${location.search}${location.hash}\" ` +\n `does not have an element or Component. This means it will render an with a ` +\n `null value by default resulting in an \"empty\" page.`\n );\n }\n\n let renderedMatches = _renderMatches(\n matches &&\n matches.map((match) =>\n Object.assign({}, match, {\n params: Object.assign({}, parentParams, match.params),\n pathname: joinPaths([\n parentPathnameBase,\n // Re-encode pathnames that were decoded inside matchRoutes\n navigator.encodeLocation\n ? navigator.encodeLocation(match.pathname).pathname\n : match.pathname,\n ]),\n pathnameBase:\n match.pathnameBase === \"/\"\n ? parentPathnameBase\n : joinPaths([\n parentPathnameBase,\n // Re-encode pathnames that were decoded inside matchRoutes\n navigator.encodeLocation\n ? navigator.encodeLocation(match.pathnameBase).pathname\n : match.pathnameBase,\n ]),\n })\n ),\n parentMatches,\n dataRouterState\n );\n\n // When a user passes in a `locationArg`, the associated routes need to\n // be wrapped in a new `LocationContext.Provider` in order for `useLocation`\n // to use the scoped location instead of the global location.\n if (locationArg && renderedMatches) {\n return (\n \n {renderedMatches}\n \n );\n }\n\n return renderedMatches;\n}\n\nfunction DefaultErrorComponent() {\n let error = useRouteError();\n let message = isRouteErrorResponse(error)\n ? `${error.status} ${error.statusText}`\n : error instanceof Error\n ? error.message\n : JSON.stringify(error);\n let stack = error instanceof Error ? error.stack : null;\n let lightgrey = \"rgba(200,200,200, 0.5)\";\n let preStyles = { padding: \"0.5rem\", backgroundColor: lightgrey };\n let codeStyles = { padding: \"2px 4px\", backgroundColor: lightgrey };\n\n let devInfo = null;\n if (__DEV__) {\n console.error(\n \"Error handled by React Router default ErrorBoundary:\",\n error\n );\n\n devInfo = (\n <>\n

💿 Hey developer 👋

\n

\n You can provide a way better UX than this when your app throws errors\n by providing your own ErrorBoundary or{\" \"}\n errorElement prop on your route.\n

\n \n );\n }\n\n return (\n <>\n

Unexpected Application Error!

\n

{message}

\n {stack ?
{stack}
: null}\n {devInfo}\n \n );\n}\n\nconst defaultErrorElement = ;\n\ntype RenderErrorBoundaryProps = React.PropsWithChildren<{\n location: Location;\n revalidation: RevalidationState;\n error: any;\n component: React.ReactNode;\n routeContext: RouteContextObject;\n}>;\n\ntype RenderErrorBoundaryState = {\n location: Location;\n revalidation: RevalidationState;\n error: any;\n};\n\nexport class RenderErrorBoundary extends React.Component<\n RenderErrorBoundaryProps,\n RenderErrorBoundaryState\n> {\n constructor(props: RenderErrorBoundaryProps) {\n super(props);\n this.state = {\n location: props.location,\n revalidation: props.revalidation,\n error: props.error,\n };\n }\n\n static getDerivedStateFromError(error: any) {\n return { error: error };\n }\n\n static getDerivedStateFromProps(\n props: RenderErrorBoundaryProps,\n state: RenderErrorBoundaryState\n ) {\n // When we get into an error state, the user will likely click \"back\" to the\n // previous page that didn't have an error. Because this wraps the entire\n // application, that will have no effect--the error page continues to display.\n // This gives us a mechanism to recover from the error when the location changes.\n //\n // Whether we're in an error state or not, we update the location in state\n // so that when we are in an error state, it gets reset when a new location\n // comes in and the user recovers from the error.\n if (\n state.location !== props.location ||\n (state.revalidation !== \"idle\" && props.revalidation === \"idle\")\n ) {\n return {\n error: props.error,\n location: props.location,\n revalidation: props.revalidation,\n };\n }\n\n // If we're not changing locations, preserve the location but still surface\n // any new errors that may come through. We retain the existing error, we do\n // this because the error provided from the app state may be cleared without\n // the location changing.\n return {\n error: props.error || state.error,\n location: state.location,\n revalidation: props.revalidation || state.revalidation,\n };\n }\n\n componentDidCatch(error: any, errorInfo: any) {\n console.error(\n \"React Router caught the following error during render\",\n error,\n errorInfo\n );\n }\n\n render() {\n return this.state.error ? (\n \n \n \n ) : (\n this.props.children\n );\n }\n}\n\ninterface RenderedRouteProps {\n routeContext: RouteContextObject;\n match: RouteMatch;\n children: React.ReactNode | null;\n}\n\nfunction RenderedRoute({ routeContext, match, children }: RenderedRouteProps) {\n let dataRouterContext = React.useContext(DataRouterContext);\n\n // Track how deep we got in our render pass to emulate SSR componentDidCatch\n // in a DataStaticRouter\n if (\n dataRouterContext &&\n dataRouterContext.static &&\n dataRouterContext.staticContext &&\n (match.route.errorElement || match.route.ErrorBoundary)\n ) {\n dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;\n }\n\n return (\n \n {children}\n \n );\n}\n\nexport function _renderMatches(\n matches: RouteMatch[] | null,\n parentMatches: RouteMatch[] = [],\n dataRouterState: RemixRouter[\"state\"] | null = null\n): React.ReactElement | null {\n if (matches == null) {\n if (dataRouterState?.errors) {\n // Don't bail if we have data router errors so we can render them in the\n // boundary. Use the pre-matched (or shimmed) matches\n matches = dataRouterState.matches as DataRouteMatch[];\n } else {\n return null;\n }\n }\n\n let renderedMatches = matches;\n\n // If we have data errors, trim matches to the highest error boundary\n let errors = dataRouterState?.errors;\n if (errors != null) {\n let errorIndex = renderedMatches.findIndex(\n (m) => m.route.id && errors?.[m.route.id]\n );\n invariant(\n errorIndex >= 0,\n `Could not find a matching route for errors on route IDs: ${Object.keys(\n errors\n ).join(\",\")}`\n );\n renderedMatches = renderedMatches.slice(\n 0,\n Math.min(renderedMatches.length, errorIndex + 1)\n );\n }\n\n return renderedMatches.reduceRight((outlet, match, index) => {\n let error = match.route.id ? errors?.[match.route.id] : null;\n // Only data routers handle errors\n let errorElement: React.ReactNode | null = null;\n if (dataRouterState) {\n errorElement = match.route.errorElement || defaultErrorElement;\n }\n let matches = parentMatches.concat(renderedMatches.slice(0, index + 1));\n let getChildren = () => {\n let children: React.ReactNode;\n if (error) {\n children = errorElement;\n } else if (match.route.Component) {\n // Note: This is a de-optimized path since React won't re-use the\n // ReactElement since it's identity changes with each new\n // React.createElement call. We keep this so folks can use\n // `` in `` but generally `Component`\n // usage is only advised in `RouterProvider` when we can convert it to\n // `element` ahead of time.\n children = ;\n } else if (match.route.element) {\n children = match.route.element;\n } else {\n children = outlet;\n }\n return (\n \n );\n };\n // Only wrap in an error boundary within data router usages when we have an\n // ErrorBoundary/errorElement on this route. Otherwise let it bubble up to\n // an ancestor ErrorBoundary/errorElement\n return dataRouterState &&\n (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? (\n \n ) : (\n getChildren()\n );\n }, null as React.ReactElement | null);\n}\n\nenum DataRouterHook {\n UseBlocker = \"useBlocker\",\n UseRevalidator = \"useRevalidator\",\n UseNavigateStable = \"useNavigate\",\n}\n\nenum DataRouterStateHook {\n UseBlocker = \"useBlocker\",\n UseLoaderData = \"useLoaderData\",\n UseActionData = \"useActionData\",\n UseRouteError = \"useRouteError\",\n UseNavigation = \"useNavigation\",\n UseRouteLoaderData = \"useRouteLoaderData\",\n UseMatches = \"useMatches\",\n UseRevalidator = \"useRevalidator\",\n UseNavigateStable = \"useNavigate\",\n UseRouteId = \"useRouteId\",\n}\n\nfunction getDataRouterConsoleError(\n hookName: DataRouterHook | DataRouterStateHook\n) {\n return `${hookName} must be used within a data router. See https://reactrouter.com/routers/picking-a-router.`;\n}\n\nfunction useDataRouterContext(hookName: DataRouterHook) {\n let ctx = React.useContext(DataRouterContext);\n invariant(ctx, getDataRouterConsoleError(hookName));\n return ctx;\n}\n\nfunction useDataRouterState(hookName: DataRouterStateHook) {\n let state = React.useContext(DataRouterStateContext);\n invariant(state, getDataRouterConsoleError(hookName));\n return state;\n}\n\nfunction useRouteContext(hookName: DataRouterStateHook) {\n let route = React.useContext(RouteContext);\n invariant(route, getDataRouterConsoleError(hookName));\n return route;\n}\n\n// Internal version with hookName-aware debugging\nfunction useCurrentRouteId(hookName: DataRouterStateHook) {\n let route = useRouteContext(hookName);\n let thisRoute = route.matches[route.matches.length - 1];\n invariant(\n thisRoute.route.id,\n `${hookName} can only be used on routes that contain a unique \"id\"`\n );\n return thisRoute.route.id;\n}\n\n/**\n * Returns the ID for the nearest contextual route\n */\nexport function useRouteId() {\n return useCurrentRouteId(DataRouterStateHook.UseRouteId);\n}\n\n/**\n * Returns the current navigation, defaulting to an \"idle\" navigation when\n * no navigation is in progress\n */\nexport function useNavigation() {\n let state = useDataRouterState(DataRouterStateHook.UseNavigation);\n return state.navigation;\n}\n\n/**\n * Returns a revalidate function for manually triggering revalidation, as well\n * as the current state of any manual revalidations\n */\nexport function useRevalidator() {\n let dataRouterContext = useDataRouterContext(DataRouterHook.UseRevalidator);\n let state = useDataRouterState(DataRouterStateHook.UseRevalidator);\n return React.useMemo(\n () => ({\n revalidate: dataRouterContext.router.revalidate,\n state: state.revalidation,\n }),\n [dataRouterContext.router.revalidate, state.revalidation]\n );\n}\n\n/**\n * Returns the active route matches, useful for accessing loaderData for\n * parent/child routes or the route \"handle\" property\n */\nexport function useMatches(): UIMatch[] {\n let { matches, loaderData } = useDataRouterState(\n DataRouterStateHook.UseMatches\n );\n return React.useMemo(\n () => matches.map((m) => convertRouteMatchToUiMatch(m, loaderData)),\n [matches, loaderData]\n );\n}\n\n/**\n * Returns the loader data for the nearest ancestor Route loader\n */\nexport function useLoaderData(): unknown {\n let state = useDataRouterState(DataRouterStateHook.UseLoaderData);\n let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);\n\n if (state.errors && state.errors[routeId] != null) {\n console.error(\n `You cannot \\`useLoaderData\\` in an errorElement (routeId: ${routeId})`\n );\n return undefined;\n }\n return state.loaderData[routeId];\n}\n\n/**\n * Returns the loaderData for the given routeId\n */\nexport function useRouteLoaderData(routeId: string): unknown {\n let state = useDataRouterState(DataRouterStateHook.UseRouteLoaderData);\n return state.loaderData[routeId];\n}\n\n/**\n * Returns the action data for the nearest ancestor Route action\n */\nexport function useActionData(): unknown {\n let state = useDataRouterState(DataRouterStateHook.UseActionData);\n\n let route = React.useContext(RouteContext);\n invariant(route, `useActionData must be used inside a RouteContext`);\n\n return Object.values(state?.actionData || {})[0];\n}\n\n/**\n * Returns the nearest ancestor Route error, which could be a loader/action\n * error or a render error. This is intended to be called from your\n * ErrorBoundary/errorElement to display a proper error message.\n */\nexport function useRouteError(): unknown {\n let error = React.useContext(RouteErrorContext);\n let state = useDataRouterState(DataRouterStateHook.UseRouteError);\n let routeId = useCurrentRouteId(DataRouterStateHook.UseRouteError);\n\n // If this was a render error, we put it in a RouteError context inside\n // of RenderErrorBoundary\n if (error) {\n return error;\n }\n\n // Otherwise look for errors from our data router state\n return state.errors?.[routeId];\n}\n\n/**\n * Returns the happy-path data from the nearest ancestor `` value\n */\nexport function useAsyncValue(): unknown {\n let value = React.useContext(AwaitContext);\n return value?._data;\n}\n\n/**\n * Returns the error from the nearest ancestor `` value\n */\nexport function useAsyncError(): unknown {\n let value = React.useContext(AwaitContext);\n return value?._error;\n}\n\nlet blockerId = 0;\n\n/**\n * Allow the application to block navigations within the SPA and present the\n * user a confirmation dialog to confirm the navigation. Mostly used to avoid\n * using half-filled form data. This does not handle hard-reloads or\n * cross-origin navigations.\n */\nexport function useBlocker(shouldBlock: boolean | BlockerFunction): Blocker {\n let { router, basename } = useDataRouterContext(DataRouterHook.UseBlocker);\n let state = useDataRouterState(DataRouterStateHook.UseBlocker);\n\n let [blockerKey, setBlockerKey] = React.useState(\"\");\n let blockerFunction = React.useCallback(\n (arg) => {\n if (typeof shouldBlock !== \"function\") {\n return !!shouldBlock;\n }\n if (basename === \"/\") {\n return shouldBlock(arg);\n }\n\n // If they provided us a function and we've got an active basename, strip\n // it from the locations we expose to the user to match the behavior of\n // useLocation\n let { currentLocation, nextLocation, historyAction } = arg;\n return shouldBlock({\n currentLocation: {\n ...currentLocation,\n pathname:\n stripBasename(currentLocation.pathname, basename) ||\n currentLocation.pathname,\n },\n nextLocation: {\n ...nextLocation,\n pathname:\n stripBasename(nextLocation.pathname, basename) ||\n nextLocation.pathname,\n },\n historyAction,\n });\n },\n [basename, shouldBlock]\n );\n\n // This effect is in charge of blocker key assignment and deletion (which is\n // tightly coupled to the key)\n React.useEffect(() => {\n let key = String(++blockerId);\n setBlockerKey(key);\n return () => router.deleteBlocker(key);\n }, [router]);\n\n // This effect handles assigning the blockerFunction. This is to handle\n // unstable blocker function identities, and happens only after the prior\n // effect so we don't get an orphaned blockerFunction in the router with a\n // key of \"\". Until then we just have the IDLE_BLOCKER.\n React.useEffect(() => {\n if (blockerKey !== \"\") {\n router.getBlocker(blockerKey, blockerFunction);\n }\n }, [router, blockerKey, blockerFunction]);\n\n // Prefer the blocker from `state` not `router.state` since DataRouterContext\n // is memoized so this ensures we update on blocker state updates\n return blockerKey && state.blockers.has(blockerKey)\n ? state.blockers.get(blockerKey)!\n : IDLE_BLOCKER;\n}\n\n/**\n * Stable version of useNavigate that is used when we are in the context of\n * a RouterProvider.\n */\nfunction useNavigateStable(): NavigateFunction {\n let { router } = useDataRouterContext(DataRouterHook.UseNavigateStable);\n let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);\n\n let activeRef = React.useRef(false);\n useIsomorphicLayoutEffect(() => {\n activeRef.current = true;\n });\n\n let navigate: NavigateFunction = React.useCallback(\n (to: To | number, options: NavigateOptions = {}) => {\n warning(activeRef.current, navigateEffectWarning);\n\n // Short circuit here since if this happens on first render the navigate\n // is useless because we haven't wired up our router subscriber yet\n if (!activeRef.current) return;\n\n if (typeof to === \"number\") {\n router.navigate(to);\n } else {\n router.navigate(to, { fromRouteId: id, ...options });\n }\n },\n [router, id]\n );\n\n return navigate;\n}\n\nconst alreadyWarned: Record = {};\n\nfunction warningOnce(key: string, cond: boolean, message: string) {\n if (!cond && !alreadyWarned[key]) {\n alreadyWarned[key] = true;\n warning(false, message);\n }\n}\n","import type {\n InitialEntry,\n LazyRouteFunction,\n Location,\n MemoryHistory,\n RelativeRoutingType,\n Router as RemixRouter,\n RouterState,\n RouterSubscriber,\n To,\n TrackedPromise,\n} from \"@remix-run/router\";\nimport {\n AbortedDeferredError,\n Action as NavigationType,\n createMemoryHistory,\n UNSAFE_getPathContributingMatches as getPathContributingMatches,\n UNSAFE_invariant as invariant,\n parsePath,\n resolveTo,\n stripBasename,\n UNSAFE_warning as warning,\n} from \"@remix-run/router\";\nimport * as React from \"react\";\n\nimport type {\n DataRouteObject,\n IndexRouteObject,\n Navigator,\n NonIndexRouteObject,\n RouteMatch,\n RouteObject,\n} from \"./context\";\nimport {\n AwaitContext,\n DataRouterContext,\n DataRouterStateContext,\n LocationContext,\n NavigationContext,\n RouteContext,\n} from \"./context\";\nimport {\n _renderMatches,\n useAsyncValue,\n useInRouterContext,\n useLocation,\n useNavigate,\n useOutlet,\n useRoutes,\n useRoutesImpl,\n} from \"./hooks\";\n\nexport interface FutureConfig {\n v7_startTransition: boolean;\n}\n\nexport interface RouterProviderProps {\n fallbackElement?: React.ReactNode;\n router: RemixRouter;\n future?: Partial;\n}\n\n/**\n Webpack + React 17 fails to compile on any of the following because webpack\n complains that `startTransition` doesn't exist in `React`:\n * import { startTransition } from \"react\"\n * import * as React from from \"react\";\n \"startTransition\" in React ? React.startTransition(() => setState()) : setState()\n * import * as React from from \"react\";\n \"startTransition\" in React ? React[\"startTransition\"](() => setState()) : setState()\n\n Moving it to a constant such as the following solves the Webpack/React 17 issue:\n * import * as React from from \"react\";\n const START_TRANSITION = \"startTransition\";\n START_TRANSITION in React ? React[START_TRANSITION](() => setState()) : setState()\n\n However, that introduces webpack/terser minification issues in production builds\n in React 18 where minification/obfuscation ends up removing the call of\n React.startTransition entirely from the first half of the ternary. Grabbing\n this exported reference once up front resolves that issue.\n\n See https://github.com/remix-run/react-router/issues/10579\n*/\nconst START_TRANSITION = \"startTransition\";\nconst startTransitionImpl = React[START_TRANSITION];\n\n/**\n * Given a Remix Router instance, render the appropriate UI\n */\nexport function RouterProvider({\n fallbackElement,\n router,\n future,\n}: RouterProviderProps): React.ReactElement {\n let [state, setStateImpl] = React.useState(router.state);\n let { v7_startTransition } = future || {};\n\n let setState = React.useCallback(\n (newState: RouterState) => {\n if (v7_startTransition && startTransitionImpl) {\n startTransitionImpl(() => setStateImpl(newState));\n } else {\n setStateImpl(newState);\n }\n },\n [setStateImpl, v7_startTransition]\n );\n\n // Need to use a layout effect here so we are subscribed early enough to\n // pick up on any render-driven redirects/navigations (useEffect/)\n React.useLayoutEffect(() => router.subscribe(setState), [router, setState]);\n\n let navigator = React.useMemo((): Navigator => {\n return {\n createHref: router.createHref,\n encodeLocation: router.encodeLocation,\n go: (n) => router.navigate(n),\n push: (to, state, opts) =>\n router.navigate(to, {\n state,\n preventScrollReset: opts?.preventScrollReset,\n }),\n replace: (to, state, opts) =>\n router.navigate(to, {\n replace: true,\n state,\n preventScrollReset: opts?.preventScrollReset,\n }),\n };\n }, [router]);\n\n let basename = router.basename || \"/\";\n\n let dataRouterContext = React.useMemo(\n () => ({\n router,\n navigator,\n static: false,\n basename,\n }),\n [router, navigator, basename]\n );\n\n // The fragment and {null} here are important! We need them to keep React 18's\n // useId happy when we are server-rendering since we may have a