From c625e1cc890c71a3f57b16303ec26de591e1f452 Mon Sep 17 00:00:00 2001 From: Timur Suleymanov Date: Tue, 21 May 2024 20:00:11 +0500 Subject: [PATCH] add spree module --- lib/spree/README-assets/screenshots.png | Bin 0 -> 117099 bytes lib/spree/README.md | 33 + lib/spree/api/endpoints/cart/index.ts | 1 + lib/spree/api/endpoints/catalog/index.ts | 1 + lib/spree/api/endpoints/catalog/products.ts | 1 + .../api/endpoints/checkout/get-checkout.ts | 44 + lib/spree/api/endpoints/checkout/index.ts | 19 + lib/spree/api/endpoints/customer/address.ts | 1 + lib/spree/api/endpoints/customer/card.ts | 1 + lib/spree/api/endpoints/customer/index.ts | 1 + lib/spree/api/endpoints/login/index.ts | 1 + lib/spree/api/endpoints/logout/index.ts | 1 + lib/spree/api/endpoints/signup/index.ts | 1 + lib/spree/api/endpoints/wishlist/index.tsx | 1 + lib/spree/api/index.ts | 48 + lib/spree/api/operations/get-all-pages.ts | 72 + .../api/operations/get-all-product-paths.ts | 91 + lib/spree/api/operations/get-all-products.ts | 84 + lib/spree/api/operations/get-all-taxons.ts | 63 + .../api/operations/get-customer-wishlist.ts | 6 + lib/spree/api/operations/get-page.ts | 73 + lib/spree/api/operations/get-product.ts | 81 + lib/spree/api/operations/get-products.js | 37 + lib/spree/api/operations/get-site-info.ts | 120 + lib/spree/api/operations/index.ts | 8 + lib/spree/api/utils/create-api-fetch.ts | 74 + lib/spree/api/utils/fetch.ts | 3 + lib/spree/auth/index.ts | 3 + lib/spree/auth/use-login.tsx | 81 + lib/spree/auth/use-logout.tsx | 79 + lib/spree/auth/use-signup.tsx | 94 + lib/spree/cart/index.ts | 4 + lib/spree/cart/use-add-item.tsx | 109 + lib/spree/cart/use-cart.tsx | 108 + lib/spree/cart/use-remove-item.tsx | 107 + lib/spree/cart/use-update-item.tsx | 134 + lib/spree/checkout/use-checkout.tsx | 17 + lib/spree/commerce.config.json | 10 + lib/spree/customer/address/use-add-item.tsx | 18 + lib/spree/customer/card/use-add-item.tsx | 19 + lib/spree/customer/index.ts | 1 + lib/spree/customer/use-customer.tsx | 75 + lib/spree/errors/AccessTokenError.ts | 1 + lib/spree/errors/MisconfigurationError.ts | 1 + .../errors/MissingConfigurationValueError.ts | 1 + .../errors/MissingLineItemVariantError.ts | 1 + lib/spree/errors/MissingOptionValueError.ts | 1 + .../errors/MissingPrimaryVariantError.ts | 1 + lib/spree/errors/MissingProductError.ts | 1 + lib/spree/errors/MissingSlugVariableError.ts | 1 + lib/spree/errors/MissingVariantError.ts | 1 + lib/spree/errors/RefreshTokenError.ts | 1 + lib/spree/errors/SpreeResponseContentError.ts | 1 + .../SpreeSdkMethodFromEndpointPathError.ts | 1 + lib/spree/errors/TokensNotRejectedError.ts | 1 + .../errors/UserTokenResponseParseError.ts | 1 + lib/spree/index.tsx | 9 + lib/spree/next.config.js | 16 + lib/spree/product/index.ts | 2 + lib/spree/product/use-price.tsx | 2 + lib/spree/product/use-search.tsx | 96 + lib/spree/provider.ts | 35 + lib/spree/types/index.ts | 166 + .../convert-spree-error-to-graph-ql-error.ts | 50 + .../utils/create-customized-fetch-fetcher.ts | 96 + lib/spree/utils/create-empty-cart.ts | 22 + .../utils/create-get-absolute-image-url.ts | 22 + lib/spree/utils/expand-options.ts | 102 + .../utils/force-isomorphic-config-values.ts | 42 + lib/spree/utils/get-image-url.ts | 38 + lib/spree/utils/get-media-gallery.ts | 21 + lib/spree/utils/get-product-path.ts | 7 + ...get-spree-sdk-method-from-endpoint-path.ts | 50 + lib/spree/utils/handle-token-errors.ts | 14 + lib/spree/utils/is-json-content-type.ts | 4 + lib/spree/utils/is-server.ts | 1 + lib/spree/utils/login.ts | 53 + .../utils/normalizations/normalize-cart.ts | 191 + .../utils/normalizations/normalize-page.ts | 42 + .../utils/normalizations/normalize-product.ts | 196 + .../utils/normalizations/normalize-user.ts | 16 + .../normalizations/normalize-wishlist.ts | 60 + lib/spree/utils/require-config.ts | 14 + lib/spree/utils/sort-option-types.ts | 9 + lib/spree/utils/tokens/cart-token.ts | 16 + .../tokens/ensure-fresh-user-access-token.ts | 49 + lib/spree/utils/tokens/ensure-itoken.ts | 25 + lib/spree/utils/tokens/is-logged-in.ts | 9 + lib/spree/utils/tokens/revoke-user-tokens.ts | 45 + lib/spree/utils/tokens/user-token-response.ts | 50 + .../validate-all-products-taxonomy-id.ts | 13 + .../validations/validate-cookie-expire.ts | 19 + .../validate-images-option-filter.ts | 13 + .../validations/validate-images-quality.ts | 19 + .../utils/validations/validate-images-size.ts | 13 + .../validate-placeholder-image-url.ts | 13 + .../validate-products-prerender-count.ts | 19 + lib/spree/wishlist/index.ts | 3 + lib/spree/wishlist/use-add-item.tsx | 86 + lib/spree/wishlist/use-remove-item.tsx | 75 + lib/spree/wishlist/use-wishlist.tsx | 91 + next.config.js | 6 +- package.json | 5 +- tsconfig.json | 3 + yarn.lock | 3465 +++++++++++++++++ 105 files changed, 7150 insertions(+), 2 deletions(-) create mode 100644 lib/spree/README-assets/screenshots.png create mode 100644 lib/spree/README.md create mode 100644 lib/spree/api/endpoints/cart/index.ts create mode 100644 lib/spree/api/endpoints/catalog/index.ts create mode 100644 lib/spree/api/endpoints/catalog/products.ts create mode 100644 lib/spree/api/endpoints/checkout/get-checkout.ts create mode 100644 lib/spree/api/endpoints/checkout/index.ts create mode 100644 lib/spree/api/endpoints/customer/address.ts create mode 100644 lib/spree/api/endpoints/customer/card.ts create mode 100644 lib/spree/api/endpoints/customer/index.ts create mode 100644 lib/spree/api/endpoints/login/index.ts create mode 100644 lib/spree/api/endpoints/logout/index.ts create mode 100644 lib/spree/api/endpoints/signup/index.ts create mode 100644 lib/spree/api/endpoints/wishlist/index.tsx create mode 100644 lib/spree/api/index.ts create mode 100644 lib/spree/api/operations/get-all-pages.ts create mode 100644 lib/spree/api/operations/get-all-product-paths.ts create mode 100644 lib/spree/api/operations/get-all-products.ts create mode 100644 lib/spree/api/operations/get-all-taxons.ts create mode 100644 lib/spree/api/operations/get-customer-wishlist.ts create mode 100644 lib/spree/api/operations/get-page.ts create mode 100644 lib/spree/api/operations/get-product.ts create mode 100644 lib/spree/api/operations/get-products.js create mode 100644 lib/spree/api/operations/get-site-info.ts create mode 100644 lib/spree/api/operations/index.ts create mode 100644 lib/spree/api/utils/create-api-fetch.ts create mode 100644 lib/spree/api/utils/fetch.ts create mode 100644 lib/spree/auth/index.ts create mode 100644 lib/spree/auth/use-login.tsx create mode 100644 lib/spree/auth/use-logout.tsx create mode 100644 lib/spree/auth/use-signup.tsx create mode 100644 lib/spree/cart/index.ts create mode 100644 lib/spree/cart/use-add-item.tsx create mode 100644 lib/spree/cart/use-cart.tsx create mode 100644 lib/spree/cart/use-remove-item.tsx create mode 100644 lib/spree/cart/use-update-item.tsx create mode 100644 lib/spree/checkout/use-checkout.tsx create mode 100644 lib/spree/commerce.config.json create mode 100644 lib/spree/customer/address/use-add-item.tsx create mode 100644 lib/spree/customer/card/use-add-item.tsx create mode 100644 lib/spree/customer/index.ts create mode 100644 lib/spree/customer/use-customer.tsx create mode 100644 lib/spree/errors/AccessTokenError.ts create mode 100644 lib/spree/errors/MisconfigurationError.ts create mode 100644 lib/spree/errors/MissingConfigurationValueError.ts create mode 100644 lib/spree/errors/MissingLineItemVariantError.ts create mode 100644 lib/spree/errors/MissingOptionValueError.ts create mode 100644 lib/spree/errors/MissingPrimaryVariantError.ts create mode 100644 lib/spree/errors/MissingProductError.ts create mode 100644 lib/spree/errors/MissingSlugVariableError.ts create mode 100644 lib/spree/errors/MissingVariantError.ts create mode 100644 lib/spree/errors/RefreshTokenError.ts create mode 100644 lib/spree/errors/SpreeResponseContentError.ts create mode 100644 lib/spree/errors/SpreeSdkMethodFromEndpointPathError.ts create mode 100644 lib/spree/errors/TokensNotRejectedError.ts create mode 100644 lib/spree/errors/UserTokenResponseParseError.ts create mode 100644 lib/spree/index.tsx create mode 100644 lib/spree/next.config.js create mode 100644 lib/spree/product/index.ts create mode 100644 lib/spree/product/use-price.tsx create mode 100644 lib/spree/product/use-search.tsx create mode 100644 lib/spree/provider.ts create mode 100644 lib/spree/types/index.ts create mode 100644 lib/spree/utils/convert-spree-error-to-graph-ql-error.ts create mode 100644 lib/spree/utils/create-customized-fetch-fetcher.ts create mode 100644 lib/spree/utils/create-empty-cart.ts create mode 100644 lib/spree/utils/create-get-absolute-image-url.ts create mode 100644 lib/spree/utils/expand-options.ts create mode 100644 lib/spree/utils/force-isomorphic-config-values.ts create mode 100644 lib/spree/utils/get-image-url.ts create mode 100644 lib/spree/utils/get-media-gallery.ts create mode 100644 lib/spree/utils/get-product-path.ts create mode 100644 lib/spree/utils/get-spree-sdk-method-from-endpoint-path.ts create mode 100644 lib/spree/utils/handle-token-errors.ts create mode 100644 lib/spree/utils/is-json-content-type.ts create mode 100644 lib/spree/utils/is-server.ts create mode 100644 lib/spree/utils/login.ts create mode 100644 lib/spree/utils/normalizations/normalize-cart.ts create mode 100644 lib/spree/utils/normalizations/normalize-page.ts create mode 100644 lib/spree/utils/normalizations/normalize-product.ts create mode 100644 lib/spree/utils/normalizations/normalize-user.ts create mode 100644 lib/spree/utils/normalizations/normalize-wishlist.ts create mode 100644 lib/spree/utils/require-config.ts create mode 100644 lib/spree/utils/sort-option-types.ts create mode 100644 lib/spree/utils/tokens/cart-token.ts create mode 100644 lib/spree/utils/tokens/ensure-fresh-user-access-token.ts create mode 100644 lib/spree/utils/tokens/ensure-itoken.ts create mode 100644 lib/spree/utils/tokens/is-logged-in.ts create mode 100644 lib/spree/utils/tokens/revoke-user-tokens.ts create mode 100644 lib/spree/utils/tokens/user-token-response.ts create mode 100644 lib/spree/utils/validations/validate-all-products-taxonomy-id.ts create mode 100644 lib/spree/utils/validations/validate-cookie-expire.ts create mode 100644 lib/spree/utils/validations/validate-images-option-filter.ts create mode 100644 lib/spree/utils/validations/validate-images-quality.ts create mode 100644 lib/spree/utils/validations/validate-images-size.ts create mode 100644 lib/spree/utils/validations/validate-placeholder-image-url.ts create mode 100644 lib/spree/utils/validations/validate-products-prerender-count.ts create mode 100644 lib/spree/wishlist/index.ts create mode 100644 lib/spree/wishlist/use-add-item.tsx create mode 100644 lib/spree/wishlist/use-remove-item.tsx create mode 100644 lib/spree/wishlist/use-wishlist.tsx create mode 100644 yarn.lock diff --git a/lib/spree/README-assets/screenshots.png b/lib/spree/README-assets/screenshots.png new file mode 100644 index 0000000000000000000000000000000000000000..93c133e06d4038d15d9a42ff0667328338085684 GIT binary patch literal 117099 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

6OhHIR@}zzq{xTSt z1sLS|dfK0JakvHc%b&b&>;A$;Fp+Vf>JEAxk6!9_FSj zdXxqWB2zM7P_X=`78=8Squl^MTmbA|Tu(-_v`CBY5s(X`TD(RqWAAR+bZYVTBUY=) zJ;d*xbOgJy`TfEfGl~i^0W)}V{#B7qz65dF1QIRwT$>qvD_`^guM`A37eknW zyd);i+%$i3V4$-zA#K7m1SUqB{V@Dk2D39Q)dzW+2j+Q#C2y0iA-g{mOfJ5F*l%OV zdt3JJ-@g6e;)A64_sE5<2e%(PS>612+x#^}g_wYuEcD-~Ks^5#1Y%z}kacu^o(47x zp!?^Qa)}j6zi{h~V-|Mg^H;}1f7QlS91nfZZZYX5c2TRN95bX-NLDY*S{P?ITUZ1z z;kDRZFS>k#r2a=am~5Cr&eU&mnfjYsd{!(|CbYNI_8;25efzI=lSIH+TU|CkKQVt- zQ6VNM+2E{DVEBN39~B{ipX2Px0hFZk)=F47=}bi~F+j=2fwzv$@%N98hkhuVV^RGh z5=wK#aSxZY^rIW?`vs^TBWf*j0f9RY)%TB`dpdJ7h`kFe%d|k{LX$0CVzE0J@7~hh zbkK5-v|554IZCL-B9~)|T;c;jE`qK6xt!c|ob3h(wiQG{Mi^8}s%o)#p=9H&>!JVS zv!h%#ZrljS1?+PHYkAXQ8jZJl(Q!Z($sj>mJCHl4O9OG}jI&V8u;fCsE#98SW0$n=)@tYX6LKNgaQJAqTK`2ZkJm3!T_^|0MI@pIp|DMzc}SUl({bdI zixUy^bjzRGJ73#ExvAwr?O&&Q$dgNQ!y!qS+b6D_4!wk2Ncv`i8i5W^Z-n^wbm(QQwg#M~ktIia|hQ)+U z!@Msv!+qNn`%J*lF&87bAC*APCdhM^@TD5(hBKC8CFZU#eXA&4pnFaW-cwW64s#pQeY4@sbjH zB()@y<@X_w=w-pZ-Jr0UA^EBDoQscJ#!kF=vu(99ZePB9_ue6rY&lFeQ8pgG_|+r7 zdiM5`rcy4kftOs6$70Cvk5to5f*?^g68l{5QugA?@cSSQ6|K}jmr5OT_g!jAxx@k< za(VjXfrngP7Afuna_I|{OV0E>t$A(6^MO(VIVaEqEn@Bv30TSq*&=^vL^9x7wx&a} z*vJ5tH;j@C<4ioc)wzD|{LOo9LN4cfopT3?nakm;1jOd}S77Yu?Rib5Tw(*4Tnzu9 z?Pmte56m0>CIWLt>Z%NFWeUuqDiP!~uCuWKq{3qHK*`3mY13wo9{uDM1vy?u@x(_i z1Agn45yG%oDE~;4Ze=825T5c$6jUAtt|VGdW$7LK3nZEEyxL0?)D*ptfO~J;D^PNA zMa$Z2z0RFG7th_jetru{xa_UmA%-rE!&jd@d$z|iy(c;S$0z2^P|77XDA~{j+8T*e zI}Yrhis9!I!PcvY{PB!nJq^lij1V#Dgd&&!9wi$QTJHD##Vm~3UL=5V3Ssz$VH(pA z6sMUC0_6ZH8P73XQwToA^#M1y9FucbY9_B*KwhCu!v&OFD7TF3bnaZcv$u8adZ%-* zwtM&a6$>k+BMqWj&UOiia;ZP8zI(lQM!BdE69ktc50W>QL|TZd8%-8u);O6-gNmgr z(mZP?4Z%{*ep#hl;(+Mn!b#|x!DA9hyQ#A03>5^spsO|%<^&i_HyJQT3&~+ZM$CHI z4fn~pg)`25C3tFwk_$B^p498@ZS5sk*J<6kY-RMDGZtQJJSMWGTdnRS3H|!RhdW=- zTQTEHQ6VO9$whOjVRWu-aDjQ>;MDD#;`9lIb3@y1pQr3wqeijCsfw znSjQ6Ii`l+E6ZqMLe{;CZZGO|KiPm9oK(nCWZUz8(YTA(?_49~vTjACRbG41BA42h z-K#HkyOwTwSg-CR_;9_qV)p!5MTMB4WFzF>-8|T~5*pZ@7WH~P zLN4XXx|M79Rw}(V;g;H#+Ls00?#{Y}Dq)vL>pPtpidYLXB9JL}`@}6cq5c8iEw&nC{rVO4%4M8} zoKj8QG_#s!X3O{U>GYj<zH`+6PP`tE+|5 zDMLl(XG2clxSIuQLRb$YlCdDb>6jD!fPP=0cXA;?m(gt7fR9#Iyfm=!Lr>`atphuB zV3v5p3m(Eh0@aKkLZrxLy@l0JOPTCF$0_cJsba0*DQcKNzFVvxKq~Yx zrZ_6}r%al%fnX!oEhcm}M)0K(Z23lAlR$@fqDbQJ5G0`hsG74|Y?#>_hC?7YkdIL7 z*Pyz~!sBT~duY)050cBAS}9%3X$4i&v`xC1Q+3lYvgKEqS9fX;8vdxkH(_Q zmigq;Hz4E^}|%f2dVEDKOQQV1%EF+-Gq17Ms#l zZ!u!Ckbj66!|l#s@LGs#VMwjZGVl-&7|hsM+3%F;F0C-KX)yx%NdX#(DD^^?Is#@A z9b=-lII2R?1)re={~AVgQlcDYLUyE4Lhb^ji^KJ zf!kQ27P)M;u%eQ$6kgq{S5-|@O+$;TT1vNUmpk__Up|PF#U36%f3q5k#iG$zY-z+t zpMWA4D(WIJv_YhJhA5T5l4H5skRm)jCTOc3R8!d}m;L}DmuF3KdGqhin#b%B4mVy3wR28LCQXwljS2deOaGuLsaNeY^gq9C zouQvhCgCy1Biqh7=8_2V(o|(|5QYM~NY)o!UX;9~t_{bx%Vc=enngku9|_!iw4q(I zt2_ePwjT6y+vI|~>|@i#yjLoynrRw2Bef}&N^Q~&{c^pK%U#0ca&GJ1Rm-sDveYM+ zJ_5HwKNx5R;U#wuv)mqr4A?@9tm{fktwu166|Ystu%&;*$A1lQhW?Tz9|*ZTz?KUn z7aDXxKLBJ1wPbp@g90R$WFlZ-urZ`dkr&#laTJOj2Dte480+O5KbWn&r%e-bnLekO zuh;VB`}gkDG*!(RS@Ys|a!IM1)cXBwZuzBKR}ODofXQX)qNS^Sw^;vxkV}|jkig3b zNOVwg*Oj55yQ{l@OXM<)3|EM(`2)V?^4|lH%coDDKM`_CBwlt)E)WP>F%sp+6+{M0 z@DwKqY9IqV$6MGMDWHHMSt>a+;Ho?ln1yjl87?9SvNv}Vh^{M5a+yAT`ixpWQ!7<2 z-!D}RT{qQS)`;sCys?b5C5r*E!ag$E+mdMa9=w`?eO8up_&%h>^r=@x( zfB(+qS9j_;RW~%VK`xf%vM5!-QJ1r~Zg0K23>z+(TreVkKORrQ*l;c471zFNZsJiwc^N?CvO)S^YzO2OFk@bI=9OB>`8^F}U>ve=FL;cJtA;pQvZm|=&< zJ>ib#$}le__eXpXm4zELT0=&8%8wb`ewOM0hXjl6Ix&WCI|<-i2`74em}7}>VB?>C zpg-C0H?8Kcf`eR6I*KUYPfFOIo~z|Dh_+lL%d4dbozqQ5Ij%tg6+y-q>_vv$j3InQ z0oyO;Nyjohl|W4dm1M9h)!4b!0h%v{gDMu}k`RCdSFcX$mJKht(ruE@sQbV?xp&*CIgIy7vVIUYyKyDf?IutG_JD1lpx$KzKjtzfs(*alWIO5}{ zcSRn-^a7Jt2X+~SL|lspb*On!Y;F@fs?$Jf{*dhp3q${N#}$jGjrqbFFZGd{K0Dbali7CN+`x$>fsUVIj$~ zmoPjG_=LR2rWfCMp~wYzt`IHjB5VjF5^4yvx1)eSz-A%cUZ`P_-5NvWwSGkdB{FiP z7wnh>vGF&$O!=!h67kXNF~@^w%Vjtz3TAZ$6Wq2x;!mn_5g6VkdtwAhMnqlJ;1GR< zQ~_$p_?!u=OQ|0TxlEm2FV^zb`7N1r9`lNsy`QzpT&zD@JgODn>1(%L*n&-#czn^K zm`8GfI@vq9KzAF%asijw+=6}CKD%^KS&6ciq1;Ih0hI(I`e-Q2H#;=I+bBtF|1R0m z5$1w^V#(IR;gKGYoaBZLkw1fk>uP-ay7x2mX#i)D6CxExp#pq??&2^abt5x*MQ&=7 z0GS2mZHmrX%MmtBj6;x{1Tq4(XY+Do*WleHfy~v|mjA+5{B$tF&&D+26Z+edWHE_3FB=-g2v+V>lvpX(MI54Ssk zuIuuV?E0idqfwV-TLMF*g9=*-Xr&w&WabTsuBXZeC4Z${dvP^~{yB zY?8~GHEY%_o;h=-^*tG5@w#>E@V5C9q>|M)_ z^E4DjNt&iN+7Ul@5WK(?Wy69efQN{bMWpZmet>NA9&GX)uz_tNu>*+}LI|+}mds4& zYkmAVcHGkbzksutnbgj)-8sjf&&Bo;O}eMY5}LgKZxg`9E#MH;7}D;wHP)0B_CoN= zSjO#?IF^393vZ%Srrfp^KfEE8aMc>NcK(0bye6ridWeqP*T98o=8$ErD9&D+@5VMy zrgv^2l9>Te2d1}{GBFIlcX)Oi`oggtd5$Fa2lhYo922-cfXgT0v=5;B6BV}tmvHLg z@pvWXkynSvEw)Ce&rMr#fvO{^K41e&e9=i7`*3Pa5$N(Ud$yTA!*@;7jFmZxI`YXC zb`kB|eL<9U_G^BF6;m0N7(wLoBUGjR;kavSP=LseaTTp7=?RyTI*(25TJ z^ZOpQV3Qf0TOH7F;ooX{YjCMLC%AMFuiJwQmW3_NBR%!esksd+a=4C%YaDkj$vv#tFu_9)7W)yF?Qzi2X4zL5;p_P_rV0qMN!m9qw-TOjs7SK<|FQa7I zjA8}}CLK}X0iDcIww>n4T8uTu02%88jYa}Nr2cqXy&{$iV)_g&wMD!JL!RqXW`FBV z_J`(M_eb{KSjc5WnOXY_bNN^sbBq#-9H8SMYECf004rDLc#AoqaERsNr}swEUGAiW za@;f~nYU7k7s z^hu^c$tqwAOg2ZOcr{u-w!YItC~<&|aR-xyhWbK4n*(FkqN&V`9KD+<^ zXVACzWeX|^T*Q4Y$cJ~*)|BLpCdyd~!4}m~O3ZzVvf~1q{-i6y0&8MII@L=TSv505 zyOjABo4$(Zrr-i97+ioYj4qWvfwr2)1cFPG^Db)-xcIlhC|x&5&tz-UbsX3-+8ljs z9bapm0eOhwmdomB561^lid}*!{S5N}l|X90u!IzBt`DZU5$j1V-{(>{)4(NftP|`Y zM2PADI?_>6jBdbKm*%5Bi=Uet8ERxOlEjEu3#I+Mhv%SO)mO1ro>Kdk&#BNkLkf%0O@_ z$9Zr8lR~$>G>neEA00a+l(C3mhm)(Xb}F)j7jwC@krK-^!%q+KK^Fc%NJO8&9;dX( zyVKi?MEHr(>fz6nn_~FcXiLBdhL?DMdqmasW8DlTT5@!BV{pM*ToJf5xmCQRW31Dh zVl3Ip2`&wo_DZ!7^Ck#flvM>LgG(8vAab#E$yKMt$co9}f)>G} zt0fPuqwt{O@z`1`y8W2X1txgRg@{)AXe!Ux>wBsVMy=MwP}=o5=suStxcvIdFMj}B zzOKjbb9wU^&|e6%H;r|HTN^ng(I_^cHs1#sfrt1g)r^nG8lRb6X4=eIpH^t|z&#^C z;>-QADSf~jbAZd|;k5S?MW7*bjSem(Uai$EC}|&xJr&uR)>De@k!m8iNG}z%Ut>{f zii0Tzk0{H7bR0aFEVbZZGjYtt;Fc!?Z!w zJE}pQ;i%)~ry{fYqGaTxH%$P%Q9KZ32Vg~2=(PtSY<&>8v@$@M>$P=L0qpUJniV=C zyvbyd;Hjo~sB7${9J}uB&he%-MKfGdzr$r=zx@8^U%2M@Cso%4fr}Z@pWvV3Bkf}@ zPcSvF57zn``0>xu0{Gy(YbN!L=_>4>%gJ)9B;u=58?!C=76^Y~qzmM{+Nu z{ycCggyXdj0he093Dh$eKp>}>yb*<+uH$>3jyH_3Z2pw0D2iI^+#qL}&U|yPw9bHn zV=i|{a*W2~Co!Z=9)`4@B@w9s$?`&c45yUU=JRYY#^P|3@(jy&NjRk41c3J_t>>y=9iJDVPjoA5hz}SrapC0Jt>h3`v39#Kk><{+WOCBk+);rr?>|$3CD%t#(!R zh1iwq5z+8F^uPGx1TM-3F31yu`GO@1%*yg1*)j5=&g6QfL9g-OF4+>*J$lGjq1 z7rmBf5KuFJ{JBgms<#_a(%7}NZJXH=9BvOT+G?uPw22RJY8}Z~_5K2Ixo_$6VjsBh zs#B&PlRA*rS-_=n>bPXjJlTW;8f%@a%3c{fIX^o@WyM_+=^7{IxlE8)=JWgGCTpq9 zDXqX*l4EARy*QxH)U=g|+0$}Bn717nA3B&6An1iAUMLbWG4{7Yy&J~TJNj>wo2LcyK?;38g6@HnNk&LCmsf@8? z=yb?!{R=g|5ONF~XWs0z7(YS@{NH$LZFNg<5zb_Qi|!LJ#H*zYOMDg#E}iBx?~8N5 zMc{zeX95>IGPwA4oWTWO37Vi)s01mDrRfZ31^AfL;dGUqn>SDFG;85Ka!aLnh$BPB z=lH?K_k3omYC=I#j|Vz-XxIKCf>;9e#i|JKK@)7{zKjL6M~YMcxYQ$OY^v*kOXEn3 z#9Q1sUyd7Vdbp(i@FN2HfBkjJ7VEl>1Ns0JkYn#*6o)uw=eviKDmJhe{Ci8dNiNu8 zud#MjA2DM7DemkWr!DHGvFI$beKFP$5A-g%CAbK85@ukBc$FMdt(tIf;l$p&EkeNs zszlmy9dO|sFPmRtewB zw+u0B5{p89U{%v7al~p!31j%h1z*O;#jV|9B6cwWTq>5odVeOkbQF|53taM-1}^N6 zV1LUbaFH(ufJ@>CnPjdhf3+G5tL%8uMz=!<;F)D4^#O;C?=L5jMEehcOYx6_OZ%S( zmmeSK%lqHH0sVZhz6RC)%fdjEc)W4T-R1-cA3Fq*xs%n8X#3liS5u)n4w}ig_%5>* zex{-#Ez1bY;&D|=URpq(d|a4;TL-vEyQ4V+T%Z?~F;91AfJ^ls2A9={)esvine1F| zbRx~|J6(ff5_u;rFN?YG@xCCDMC)^lp$w%CaH-A&7j>UkRaMrvw_Lh&z@@w{xP+fA z_PRX(1=6RTVG@48apFn5=f9St+&*$=M$g&I0md7w>9LGKiL5 zjDpfHh#SfLZXZmTC0VR0TR^|yfPTsUrrIDqjo2unY%#~F$Q0y(99}7)pWD04V;5|h zTI`6CG*HDW-J$;`TP`VNGjfF>R^}AH@!Y=^%Zq}SRv1bXNG_V*dI8J6$8zmGGBfcF zD*_D7nR$8&<-7u?A_Ec#T$EkB3d<>5>O644M-2DzOjH0a}!ZB(_V1?QQIx|*+Dc1yMCQhx-vRv3E|M``BSjR}s{WDgB%6%m>bg4WKVU-UAfl@`A>u(is5naxIRyJKh%QFK zpTvteAi@raIv^}_G6yeSJbBWCcoEH@Cp~x&5fKlf9_>lyW$N`;UDcgUbe;6K>`c?^aiY10Fgwl#v|Ox_NRd%P$&lYwE9N(H z&QQ*gD9F+@8gFj5m@1}dJ`7ULecVXcGgbB)##m075M@`QjBtFKeTp&7=gT1%645aX z*+i@nJEOBpA6YgrZPB4+kqdK;Dbi-JS#(?xHm5XjHB~0@Ox#9-qAxXWxthMq^Er~e zuCcEGVNiW%P0f4xFXtB1I9VgMMG#iOV;r=Hdr$H#MUIXzOzpS^-!E5|Q6Cc^jX|rI zLoUd-@d(HTXD#mG8|f(X5d00r$tAsFxK3YZVM1vSw+l-QzRG*A%&D){s|x6MV3lHD zvwf=1eUM|AV4;8n3D^MTiO$_EP(xp}e)=OOy}f0T3z5Q1p2qYv24d}LXgFQ)HKGRu zEP-6kp1oeNU$ny1m^g^c28d@k?(n(Vp&x)slRk-?Z4rCHME_3i4QpzhV!p2MvJ0n} zvkvG_U!N+d!-n(kkPB=b#^j1zybe44VS0-1WASn{%!lJ%FHVsQ+BhRExeSao^aqe( zg?d~DxnQaG0Zke}E;wt^Sh-TueAEGUDMT*bL~b26wF~>=e>)uE7*<@OM%F0VtH{eZ zt>PH7g!@Wj#h693c8BV>2qst(d{)XW>cdW9`aT+i%?;IMSQa_fI#lyy$IBoWM!fOK zE88HGTq3m^-e~r;jFX4cqIaCki%V+90!A)pvR8|FD7bdx{ajE@3!;llO(0;d?=vV| zXM*6N8VTMV)tvzo?K~VYK)*{m{4dA_qs$Q@`)u3~c09>vl zZidM&a;>J3dY!>;vU>}V-I_@^a~2CD^n1I#{_IOikUPCy)`k--olkwy`7|FZJyA(3 zWS72j*0iQIX8uY*jWn2rlZ)|b^v~W`2FC|J>YOyuz;*1hEVmf07DMU7-~}9^UBCbj zMf<$+iX`TDo>APTs%U~ktM_I7NE2(?ejUyZ74={RRN1>udc4Y?ODCI%sQ&Mg3!%@* z#UNg+vN64c^KM8PfJ0)e{?dt)PDc@uQf6#tqAY|MCWaHW9xj7i=nMWyMsO7wSvalG zczUyOQyZ|$g326Yutb>DVgab=NT~`lLP5&~g#r;XnSeH&V95$c#KvMQ$aRQ;p*3C# zxsd)L25=P&4hBBRz0G&|HS`hUp{(W+xnbTC}7z+u-x`61w zOfKlTLeVy;KKk6ShozB=epZX%Dxhl|_~7dDHlgL>V6t#(G3bM0jfE5GBq z|D0TAez3?aUNN5yd)dZ>8hRMm)4!ls7nOxV6*w`Fax9ZvkX<@4zltHwe!Rg#${gF= z!uI%wJt>*5y%to!4#CHG>-0XY0>G3nth5`SYX|VRg$Y()9Hui+X>6<)J?sDnLx}p& z`x428%FhwTBjdBj`oUrTj9%12U*;M_?O2WEq|aJvU4fW1RH0KqFuflB5YwZAsqueLE^LPYNgnFVkcI5QF{T!C zB!;51P3d1ybwOD`0g!vBZ8_wEtk8q2U~r)3Fyp{OYfLVK-w5uXIIIyCXIxt4@iX*{F}7PBi;XZ^t_E3toP92wFx_i->xkFfVXU+jMz zdxPW@d}954k@c+May~gM%h`C`9qZm5K>iH0DCmbI0*4E>g2_$fJFBP$!W1 zG5@8m%}*ELVLt4n2j9V=ICNTwY~ixINlk-v6@^A}d3*n$JNeMvZ*y!NwA%(oTPFC-&tH5Ct zCzx)PLUNh5AC8K27HQ8OMtB>`oPfOA*th=wdv@p%KQN2a`E-oZ`f`p*xQ+s&C}F!@KW;a zspob!fm{}eQ4|%=Dl{4Od1P@h=T!>kU z?~TOmDTxM9cN`T{#aCOp3fuA4f`H^w;#vTeIi`9pNtNT@|2QU>QM?-`zkpnL1{ko4 zg+oHCcx3}hjZz3~Nbnmf?pSGXddEgW>)uUSfT!P4Itq-lrn}p!ft-Cik6D1a7 zxk&4q3*y$IAsPG1&I)~iHVdlB!<6K5ijl6N|7!vY=#K_*cFcvWms|2nsHfHvlHi~M z1hZWyV)Aj#st)!1Z&vQKtBRmbz2tI|P;-i72?axlU6PyR{Xo# z!s2!PM*cuIaD$dQ@C^=xx-6Hq$v>qAIse;;dH1>eZ^$KXl~`2F#eph93qp_>=o|D_ zL^oQikeSa^S>~{W@I0whqAbbflw$6s$Y&^`pITDY$c%xwv-hTud2}230`7>aRjAc^ zF%`HDdgFJ+u?V#KWnQfo?6uIXB~R^XUjI%zxs+?g7Dz56Id;e*5zJdjMIrShUGD-J z!8T3Eu~#iEmsNwZL;qoAhyKs7L*HD964&Z_S&Mmn_T2(IdE5aFIRo~d8n>^Y5^gZA zY1oI9Dzl93q_OMTT4R+}AeWL`7ECS`&^MC~Vlq8D8Y#jM;C*&{&5Z@CkQ}Btr;+rs zcybv=6O39Vt_2j&Ek-`Ev&VsbHd{+|hLy%@+xgeFc<@nJ%o*%gz?T4=a}W`gSuq{g zF%7iIyk1p@j3-R0%x@%5H@S3rgHr1kOD-^L=T#*s=6ab6NWY=MpXx>}AtTR3Z;Y8* zB~CTwBA2sjL>~it5?3~QsfCV0bvL<1%$J5rB2Fr2S7vnI15+uBQyMjFbOVzDy7a^_ zih%dx80Lag?G|fA(c!QpmPL~b!Xr&QXIy5CxD$0y9I01e@G-dVv_ZWzL|=u>D)v;8 z%W22lS&_*(c1A1YqDW0f+C1rJFpWpQB<%?y`1xzGV5Ht*ngZ=6hMVbdov|5dt}qQs ztRT6RSTebw@H!bSj@G2Wq~Zb3tA_}R<)ek21oe_!PCE*d%h`0DqDgB-QnOU^c?G1AyzIvVMfrmCd7>nj5?4bmPQJG|`z9D9k}$IpOkTLO zM_3(a=@wfR%uz$1@6kVNm}74>zFSq{NZl||`xXw6*wmO=^yf_*Ik5{=%L+V$aRsIa zhw|;qsg&eWB0sqZ`yTnGPJ=?I_f6s-v3o8NcOuIY2-8ym{@Y>b^k3wWyFp_^CW5u(e`&d_3a+-y@$F|Nat4+h_O7dF z8|%|XY!a~5T@~N+?4lb_rCuAtFOLll~@rFxfs^l>$N1%Gr>6}C@Atfac{nEeu&a?Sp^g)7p&)k zbP%#UECH)Fgy(NqH|V>pb2p1Ra&MZqa?rXm3hB|9`SwU>@+n<;&ujX=GH74rAynSH zs0_RpKy>eDj=;sNNlcxkclrew?x zD7B(e0XFIL(G(#UvRQ~$X1KDwy>&z`?|xm9%L;+Wn45ni7BjuOydKj>3s6)lDu3Gs{Kj1=mH}+)WOXr1`V= zc#$RZ8+?zKKptsiD~JSN7hVp)=!rdpO=#vt_uSEQHf#!xYyz z6+EU3Hp&2OZb!XVK(lE=cZF(WG#yY5KrKV{Pzn74?}r|ei^*=e@4ippdEv#6FI{^7 z-A}&y_M29T6#(%#|6^8( zvNt$vA-Qm9_kIXAwaZLdMiP=0lx#c12D=js$e05OS;RA@q`b+ss;6hk*onJ6eVyg< z04)zALYa^X;pG?K-akml<&(s4DJ_?k0g=m0+$&N|NqKYt_+Tv+5%JAddV@$ox+K)1 zSSEANR?bzF%RlWW+g#rKqI8R`5QtnXkhTarH3sy< z0dX%X@Ktz^H0Y2l$>o$I?H2p>p+A0~)zBXd20yk8#lj|e#wfgZ6#ifYA&oOPG6gnL z@>O3;Ekc>6U1fVp)zkK*C$}5*J8|U6)uG<@*l=>bs_|fvD6|xr5ewj>%ddQT@XkB0 zB|-i7zG#(L5vb%MJ>g^<$ZK3QMa94z4SjUQXMM`41Ph8^YPm!Rb41fE-C`?(bU;5T zp#Rs*a*5+8lU!zLV5~-f$lBf&Iyz&zsyKJmHH;GN074BHsvrdL1VChRp;K(z7%pVc z^)KLbbc^Y@<^JRUoBJOfY;`YmyWQ=rORW+sf*h8M$hp*B$kavkig_6(c2OLnB$pKd zEk!1`*e}2T{tE^4M{yh{zbr8q9^m$lr^-<4#j07QUpjM&tTd*u@L@jJpM|Kh6)%AG zbe>8n3oDx4a!FCk{S!QJxqD%TZmYzKAWbeH(!Nf*9nBZtH554V(g~Lmh?}VEb6R0; za%VQ>sobEg)HENsCAq8u=Bc620TSlV^G4;E&%bFRu+5WWx4LQT!pRw3%xi-LhTSuD zys4X$P29Aa6Z|Z4VZ<__mFdq1_qX@9y9uv!k4UCfVny%|d*}Y!)>+1J=^S6&@0R;zeJub{jq^*t6zrXYr;Ifav#h_{gG-##Et!S9a`BNvG z6-+yp^_7mt)Kz8>X-Su9Q6LZr<>TJVHmJF~jj*7hgEsggPD|EcYUN+2DO|2 zSkkY|r=BM|RSuVZ9}o(Q9Tb<`H!?~kBP1_fG}5_Kq@CiX%1FDe>XjntNP3BjvZngt z1sSV6+F!#e0Z)}`jnri&S=5P^5nL!|7~D(xIE-+)c(}-xn&omIi3;e;k6^|VP@?(j z^m29f4BYyxp;Bv{FXPmR!Z>7GOqn^QP^K(CLcx zgG;OybGhGyEf;J#FsO^5dSIo}5gL@&rDH3ZDID+XT?kaL*IMDq`&M@ZmxE%$P%Zf( z+@cH$r&m_pqpPk4jojoaq#Kw@uRf>{dNCkuX%(Dx@0aXs@8X|L%09k_bnF^6#<= z)Wcsfs>Og5KX0P;O1u&bd9Q&Kik5`S$IA66;Kl9=#3uW=VE!>)fB#TT_lF2vs?J5G z{lJWl-TQVO4JxWsh7K3IFrdkgn92tz8{tk3Rj}0bj#f2r`GDXNBaig?SZ`3WF*s^K zyb)irv(+VUHC1Y}n`B0dsjQDlQ7_kb9~7BLRS2WZsARd6qXkTtuq!Y*0%Q?%66SVU zJ^RZ=OHKEQ#NkG0=M2@jHK^CHdK2|p&E?G2l{jKljA?@T&rn^fK^}LkxJSN=9H6D9 zceGknge{kYC>8n6r6Y7<=xM$UWo}%J%qUIjB(0@z#J~m&l2*M2Ss8aGmi`UuX=n{{ z8^Lf9!Ywpfh_(Z<5&ucTmXlq_VyjnP*|5}fpQwuAj3xph=FUs+Ye?=SEUAepUr%!Y z@r-<}2A6lds&tEqZ5QFptWk(o>8+Z{=2F%UfAL~{4--jyi(2HA^{Rzx#iEu z_7x-I5xr~ly$9q5g*HfTU!#?POF3BxUhIL`vSa$<;UZj)opi4M?(7*$P4|h44acY} zRTx4oS1;4@o2Wc5+-bDx{$A}~yVX}nIK2NFTai?(!PReURkz7LyN=`AtZQZHx3o2tR( zeo_^1*|$$*wty-!t&M8Up2Z3GIvEez13H=2wQ4(QQann%dPP5$AQ5L>6I-O7nul3W z7l$FwGStIx5s4!UK?_e8hjZSs;~a~{24hgYG8s$$_R247aJg^9H!dwB>)36SbDL?^ z+`QEb_QVLI5gLTOvU24!-m_P1yat#1L}nFL9dkJ(dAY+#G+kZ!(gWIxN9gPD_L#i{ zV}{x+ivcHW)=;4luT>?HmgLVM;Hu_j%fwtnXc4i6(<4vVmYp8|JXA!EFD@os&VX}$ z<9rP+_l+e#^^8m!rT0x$=dm>KE6-VKdI!r_Ia~lLv?_Kpz1yH* zE!0aiPn}5;GK~C%zeXz^)p!rp|Fk-3Z-EJ$ENbz70|pY_EuHY$fC{jwS}s78GO+L( zaP4e|lQ75edfdg;-Cw*um7TQIbYEz$93X57GSZHK2gL8PQob@BT|ID`?f7oO zyJM=&7!U&XkI*il&dt2vY8Y2YKgTHY?1dG!nr4{vX6?Jh5ecRM;eI$F#%RigG= zZxW4~e^JsO&0qgH(U(*PQBuBz<;){Qgi0V`iy!-#`@=+@HYIIs&8)2aa%=0^XScRiW)`xU#Jn?{ zjwcdHr)Q$AB1KBOattFy`oiJu@xstdAwQd4n3>6MJ-afL&Shs8&clvZW@cuFGkN$Z z8;$02+uND#wzf_M9V5FM@pe%1dcE)`R$JRlK9>MAJK;}wNG6@G!G8D$op)G8vWa9b z>9DXP;r~r2i?k1JAZ|hOYM({{S)z-fGIV1!D8~&oa;;5Ya?I*=8U~O5z0(Tbb=17% zuw|yyZyOWg<*C0GBNeF8OE};F4He zTns0Y4h5i0a5pKq6oyM0=Wda%ot?t)Zhj^|o9AefKee@Tem0%kon3&Jpu+Z$z?QXK zdV6msH>}|__!i;!@KoUhYzZ9e?>iie#g;=nR)iao9d1Rugb-X% z=aBOUKPZkz>aZ^vq(u$(fMkUSMy`~df%Kq<^pXd`$fmpK75vhA*bYOj#mZUiY_Tw= z4xI%ml|lB1?k!wGg_Zn5cDu8)y9Spk;c}}4m;e0ppL=lm`F9aqQ2&w2>1tGNLk)XP z&!lt~W)+*emfmG0Z5EA0u8vjg-gA@UYI?k$wtP}q>OC2_JW9-#Cx{4M1W-(lWD<+X zKnzAuo*W!=&CiE(xm+}t4lk!~0$Zk{JC6cZ9((MuPtbrVnJ)unmdgY|OgU;x@5UB<_!{k!lg12ExPl3xM1dm~+>M{Ho{78+P3jSQB4%cv9(tTa@7(1zv&iW@}D{t?095A(a($_Iu zNVG)^7Pyr(x4fL#bd7P@VyU=(zSx$fhDY2N&gjL`&A>0vM3bf@i9`V6D9ov~a>;b?sv~p@?W+=Lr z&F+rFZWnmAM0vIda4A#@7l9|d#LE<2ylsW`v?mY?xQf29z~HfY%h=&TP``sm3$|Tk z++ws?+?p8q_N+zdsb&BPTj3=>qu67ZJ4qSCUS2Fc#(}o9CN6l}h!!L_c+cPh*85O4 zmzyt?;L>vK($Oz}q21hiyuJPO7f!c6J!&3(?$T)cQS+rMI`)+SAh8+u82zv6{V(UT;gNx3k6DRTHv4<5c6+b4 zx5M9VZt)NF+ULyHpl84yG2gLnoOt8UZ@}LPcs%jv6IZ#Vt0!K?$LZ_vyPJa^bI?BE z2->CL^5(T$&%8;dIsWH-2`)eX(wF{#;X(=A%c7p6!3DJN^^C!YNTbDi`d;`}tBK!4fv&Ki8U4HdyfjFzGVQ20~x z^Km#A#(*tJaFDI9udS~yCgS1n+I3({Hs=SZi18v2X3u&-aFO?momp6z%@550TOhKN zNI(ifVl}-QPGo{gU{Q{_5X%MR2n`Rnt)v%twyZ30a9PM^hlZljh4Y|=A!4|IFkEiH zT^cSFUA*K*^QA4nely%@ft+smhjj698CuH-Xlq|VX%sRgoKW2vngq?x1SeURy*MuQep1WPN1U<2ObJ%-D0 zHs=fk=6BkPa5?>)xn=b7=+mPwzkKcVty`mCzHA;HeQxy9%a@KHefgPdmoJT)TL3O! z7`=3@<+8a7S=|%9NN^x%>+souE%ph&*AW^R8HsdES|Srm{_cTLXe8+Mj)dm?c84Fn z=m`!qd&~eASa6s-JeH7q?ybP(^;che?e!a1Uw!Sw)f;czcI)5+v0Y6q~HQE7khhr`P${Ls#3+H!}Ya46PD^t;EHs|1>@-W;e1E%C1lXr_vlDl7<=%gm{*Q!5J_Qws|lYgqsd*h@qC zECgIia2f8T)GZ(e{t#TS)l$3>ycE`M-@F+g?r`*TbO|_}f!N^KNPlV!;KF4}j0Ivb z*JOyM3*4mP@&T1pN{v*upr+Ksi)FP9#JQ}e>~9U_(5+)k;!Tj%am&QVZ~z%9jI4u= zEvr$XMetG!nXppnldLp8jf$MXpgeFd;4(g(UQEWL0GEI>k!}_&m&=!)zI?6q<>r+i#Ou%x+goVcE?0W+H$$|=F7mA5?ns@uYZ&*m#_Z;!-a@+ zBsF6K&Cnv(hP6c~JOF=^I#7wnz^L5j8J#qAOmei@ua`Vn9G*2HUok0?0ryJ9Vz@j} z5@odTv6RnGU+9BzE^#;=CUd*P1vm*0&*ZP4nTl>qMRU<;dH~2m-6+14!^K(x0+#hf z(8|m#Z?`1DSQ>LKuC8%#arMh4j7_Lzi;W9>;pB)64|lHcmJ7gT3m(8y0)u63GrB_H z0;yuamQ0SbTsk@_o^-=a+HxUK5m_%(bbojA=FOX%@k~$8#AF}_9B~0$rc-@^3xeq~ zc$ha}=IvI>FD7TX9Nbq?o<7ci*}EcQi1mxUaG>&9cy)D(mIe7lS8>2b&$2Q(nG~p+ z2>q0EVHkRE+VZq#En0<<`ytFduv}I*k3xt&{#$KySvm0gj-81x6s}K%jTBW zW>|tXPjj!@;r$lwV{naHxIb2J*_RhW(aRUXr-mc+}j-KHMcgyLJPbB zAGGwe2uEOd5A^hy;SFsyMsw4MN`*c<#GJQf#D+>i+Wz!4ThK5&TAmdmYMFPCC2 z|M<&a{!t3(fBoxU|1N?H5QUP8kBX^Rwdh&o{$=EB4BWg$DbE^eJrg5QK3`wfffz+w zn^k&^f;5at=Fsr!rU&IZU>RIWSV1l^K2HD0$c4T@GQ0?UfrO`AZg)GkdVS-}nKRcn zvN=%3{xA`t3yl{Ex7dUXU-Gk4;GTk$eK_F^jKL*7gj{&II9(%ttBUP1LBqu^!i&Hb zc=AQSbeZ8Tml+-|U?Ty)HsfnEBDe@a7l2C}Ww!|TZvF|ug$laxPvj1K8Q;m+g3bb8|7i zwv~?pWqQr;Z1uc~b>m*7BIEueFOBN?x(|%Cuvo7E$8`0>HjRVXLUCeT?UQy zmCc07QtrJ&au&aqkvT)qaG`A$!WDuRkiWlg%ozt$0y4K&AqhFZv2o?hE3cf5M)^zp z$xjfpAj0q)L2yw>M=s>D=VxYyX460uU<>%+R@Vf$jHE_9R+XR&1s6J)Pc*#jAMf_= zg6(pCVP)$SSV@bkoHJq#-kF&JtnqLGx)8VkMhH>5;ZE3sV=hP{(`9@O&Koz^0WQ@xw^KpwU7fZ!8;u;Z&vB8lg-^j@H7)7u zSpmC7-bZUhZ5|Cr(@B4*w4%l+8`*CtP2M6cy%s@G=9e=MD7nFydj^-@)lFw$adkbv zwGvH07_J7F3U%}nQLFh^eq`PmnVo-KpRJ`}SwaCZhJR;pR=^`s%Hm?(@)>f{6b z8;ml9$eEihpTANk>ldazd^f6}#8N$>0S}tdDESb?tDDqfF2$TK6l>YjTL2GSI1|kSRzUDDD}-D)%cTHol`NMM zREQ0O;DW@1rBK*i+}uopYFbH3@6f6g*Fk{T;oE=1FiF(yU}JR-Qf z7n}9Q3bTDRd#zqC0~u5CqN|3K z1$R?jdHN)S#+zvruC^HA5cH*8BMiJB_aiNCxo9V(&T*qGC7KX4RL6GeWZhztMhl71 zf39z=Yb?OgB?%eGi>ukQue|a~HUkQ0mNU;CK_aG%V7^drQO3(IKROfA#Q30hA`xE8 za&Q5^SY|E-7y3R(XQ|L~p%RfxYU2UZy(Q=r7%Tb0LY@;0-O0}Ka7lwQV7YMX0Y}K4 zK!q$~xL~zq*Vn;faS3p_36x1Xr$;71a~@y|4;Ny(2toar+g37N?ED|HT##AcP;r_r zKBF5{zl$r0VHhePR)@SC-$><#MIw3xf^7K0I1zg=C- zL5mDSs(PRXm$y&IashD!8*b*Je~Zrjb#- zj$_I*q%~!hmzFvrJ=&|PSn|)H5OX19d5p4J1pDKo7cO>nfnzKIr$%lZPLKV(KaLTYfq zmP?5&+#McP04xGrz#9hPmj%vd;fCh}T+#wuwj+hY__&wYD#Bg-N5iF4iY?>U*Kc!i zd}o}Cxp28an=aS9BNB1=JYa``M*6r={$UV7%)E_G7{hQO9fL@@PK1#(C>(2GxSOOk zZ&0YWr7lu2pc>*aG)0ItqFUjbLCdO=gP6XdY-E1XF@mz)-d?!W>b%?&Vao-N&}TGc zNF*a|WD_1VBL9=TnsB2dsU_-}$?8b~I`v>7gGPPI=Yi2Pnd|TfN^A`o$N{k!F32H9 zSuL>esO3Wc#jY_Ipd=1{owexH87NnogO}hG%T0atnXesv{K(^v%kc%lMM2ik($2_8 z0D{|4!)!6UxW>Z;V(#gJZ`yYu<(c!jJuoy_#xEv2h*D&=2YPOi#cy(5>;;)W;#^8dDbPb3Gja(>?y#Fq;j6~V?s6q`}F$Ne$ z;&XCw={dNS~;L9V?v z77s*Ub~fKH##IwOMp=VhFXn+>cweXP^CIKo^qRc`Jy5)MWzjz6;8H>h%@)uneth9v ze}7k(E6x>>gw){d#?;gXRA&J>GiRqBdFGiXzx|cRfiEELsoXtQDO|i0R(mKCiufTt zH|9#FS6A1fP-bS0d(Q6qrY-&8Nm_EdeGa!9Sud#k3k?>5E(9-Nx^#1?Vl!ODN+1mE zWGx+z4&`~cq&c|c@`XZSVR(o02+og_Aijt)6kJ3^5iO73zP--D#mOg!%^wD~#9gr9 z=i+^E(- zE?DG7rtDX$de2m!!1#c~DV@lObC2cnz;yEO8EKLLBd}OfQKJg8UkNUREr={|z@9^3Aw)ma9YP9TctM)*g)>7jvP+^_l~s zR;EXnFp~3~)>k>&s`^6rA1u916GmU^VNxj3Dl~Nywr3bAhdCa911r?2(ZwJQ7XlWF zE`lEU(YN|8o|~J8s0);l%%tI*53`*tL&;)i-+cD$nW@YZPd5v@$l>~hc;&OoU%C{F1cM$K3~}7;Nr}Tm!X9Y=y%d&DVZ)C z1TJys;lO4l4ogWF#Oxudy2BRoFTt#%09wf}>G2vS`XkyIh_GB=gUkP? z6bDf%d&Javfb*`{y;pU}AVF?tya8QV^J_$3Wo08W$muJSOKPCkQm;X))#D#sr(n4d zqlGYqzY{(7!>$O z6bVMGA%`tA5wu&n`n#N&C}ajtO%1`>AI|yBL0F*o$$sTa>|Y~-hS!zIVDg`du48~BnNv?01jaA711S;$;yG|(N1#blw^qXx1(h^!tu z^g&T} z33Lg}a{_-@|JWGM7Jy4)!fv zhI|(<_Kz*6XNS&%xKZ;%3p2Zs>9PLF3zKf2$2Q=BuuLQbNy#1$STM!u!qj6fZ6IQ{ zaEs$B5NpZ4cV+4c`t%E5_)3{LQwF2} z7cUoF2)QS$?ud85VGVjhA;*%>GoA9d3&0kB7(FO7;p^&}Or@3vz;Xe&1bMgw9X|gg zjIErQkP7IdK`vspbO2q3hi72&d@zm9Pb^(ym>^BB9owGSv2EM7wPV}1cWm3XZQHhO zc;nV?%z4(V&(5EZ^S-`U zMB9dpBZ0&RgE7vZ=B{-YhnL~>d4SBVnZdwacJl{Cxq+Y7)$At`JHQ^)C)D`zvwPHUeLa)@6`pP}%GU!B;r%(}B6 z>ztIoahtkG6~KB_w<3&66M>+V$X3j$8Z^!o;L@v+#ME%kOY7%V*pQD51I!YFPY?LO zTD?xlej8$IYu}Do@@9s}bN%%W6Q3hF9)PF!{V6^2^J=ZX=!{#{0|`d?oq|-|x?F7W(Qz?(Wz1y$HgEa-F`&6&EXc?TXAf;|QI))<_2#!DvA?Xpg*`^Db#JYey(EiO|ofFd#wx ztS-}^37VUqO5JW2Z7N$D^UVE)wN!4p&pWtlGLzUWrn6Y^HGz6Ecx{0d{FJEc*SD26 zw@uUf=pj^=IE0zQu;NrxPMDy4$Vt$zK*o4*K?Tb_d$r{!H$xKo%Qoh8ZQP;bHV7e= zBYe!@6)CDrO-7=Z7laxZ4#PZg7f2sX812^F`}2eE{jO!Y>oEZ@^Kg~0cPK54uDF3) z17yN@;eJdGSi6_S<+C-FHi+)t?ykAd_$_GVILwVmubEwtHFN_lT$qp`tY{Sqgq92a z{X+@8geRLs%xFyC@%74O#*b$IW%U?4S=nNp?h0+d2oqg{R{qt}tEILUKv+ZS#DoLc zgkYwDBonZiIsh~wa){kl56Oq&wpd9R&8Q6_Ka8BoD&!jfUJ+UnlN;&H4|tQ!B7rZmS` zlzW(f?HJhm-G;i%Vh!Q+bB9fvQ%s4hVE2zpL>t;%4Hm8KHf7%tp6~lY52SYYM^TPp z>!lF7>3vdrl!f2iK5~;z8CLus=##qI=6ea9m=N9y2|CVluto_`2EkS&E`ZhfgFu+A znV*QCYGM}Ho6rX1$zX|y6fq|hjCqS)udC(l_<{Uss2J{(p(ALh| zv>5;$@;kSUG?1` za3Z6iMKU4yAM1<1fc>+#GQ;;nV%2u}0dRzwU>I5*NlRix|JWJF4e{u@4J<8*Q<2xc zr>XulT9%89JH&SoE8iVV;X{0mfI*2Rk|2sjOIYa_&HX7cGo!=#GXK)^Q)TOYLPiH0 z4XEWtf}F;(ZG*WVl|p687Jog1bMj@-n_|oBj&iFwoHCO#FhrHPMX(R_$AEy2_>Z&b zrp~Y4Ay`Cj*Fi8RNDk63P`!x;>typ(#fkkK=n(wf{X1c7ySbjjT^jTqVg-*%(z zLt$qI)(y!UGEJR)8PiN%?G6Y3U#aP2kK08ao65r1Bm^8k)3YK!z zKPkRYM_0bPpuZ_QT0bkH^LBrHbS$91Iy_n^xJt=p=%G2cXXa|Zx_*`qWm&~Jd-M>* zK}^+g=skbwM;T7&0`^OFaed)$=~%%%yLImHycAG}=7wVJS)04KbzPmb6=9R@w0}DP zdl|>~_wfgrzK4Okib{C4Iya(c)I(ZO? zpuA#6_T`WWf^xmTAbl7aoxrVuAkX=fj>y$m&+gLNR$)R48(jhq=_QeWZ3k0_f2Y@t zw{16DNz7q{#yEnJREl9wT98x|Dy*2lR@>=`++8?mE0Uyb@M7 zYx{WfV*9wKC*tPoEG9f_1V~w#@82I<+&_GGwdT|H8UOTs-_-@BjG(mc#!Gc=LmJwd zJHZWjTxneF*OHXgIhMJa!@S=ZDppdh{88y&W(P}&aG{=oHwIElS^69{|0(=A-z^V2ZELzTRaCdiD0n2}F2lcLSvA@sM(l`Jp+>H?(24nd)Z-5rCQv_ewhVbrxCj zB?L}*{L+y;!x+_;Z4~Q+LDd~X4Oklg{##VKK|oB}vfQ+IP&<3Mf&1$)XhS`0gmeVb z{m#l_Wv0(qDG~(zp&Y*SH^n>3(m63Ys9spzUUP*UikD1mYsnB_g&8Rs^{t52=o*K* z5dFg-50P3oGM`_{KZ$eQf*7n9gj!shoF(haFNp|7jIvxt5|ydNH|JZjdN^r9wr5vD zQ5k-QW=c)TzlV_NE%nVPz*CyoF8OLjSe+6BNSrG0IUaEoGiUYy;5w=kovV#7&ojR* zIAT(|S_6V1V1^Q5Ew zrv%?&8sNSjimh841n4&fYveZ9Ap%C(TJs#ULP= zxK>JZpf&KrJJAqlS`KOz8*Al{efN&n!44sq1nO z(_Ial2Waew@uWFC6y6|kzi?IiVhM1$3Rsh@(I1$-gJLFqRTu@-3x+(u61sE`k&b!m zvU48?_(PVjHN4=+oVMJc!}l0(&mM=RH`G>Iw8Xc=PIKMYHk#jgv$eomzvGf-ytv2F zRaN7}sWeuLDMB)1gdwrv3HN{#TVtXkUcCgz3RzC1vogZIj&uG=E4!j9S&JUy$~OC( zXxV!<7v4Q5F)VeUJ$ez=zgIkqrQaU=vZct_?{Va0X*^Y5jLc@Mz9S^7E?BLG6XIS>kptIPw zzjxTA{nRd@rWO1uytgLZczE%x1Odz;9`m}lnpaiwr=XZsifs0Fc6Z?Na#8k52#RSB z*@NWhN&FDU97L_|`b6;VZ$gZil0v>{%tJoy4&CUbbp^D zLBsw@u^;#s4%29oj3@dLu&LR+vuXO0l$}-GpWX`rL-mnoEQGSDQj58?*2Xbyh{KE> zkgK+xPAC$nYX`kk(lFu`>*v_#;G;2Uh|)a?{#^!Pg>{}l+B4#0=9d=qGZ}ge={7mZ z=cin0=KAe6?3V%~`~B@DlXUe@#o)*xkcW^HUpjP#QPkNo2n`r`LAl=7jHx~Jy*F4Q zz}|!#i1UEaIGBvA>tmN_Lh@sU?kwsY3_}GaRkKeKpE51UPf=MKPfADK(jmUav>e+| zS~4OECe}oCc#V=)=rV)N7Xa}XP>-?8+`v19w~2y+F;>7jS94Lkb?rO)yd=z7wME51uv)NhVb9_A~ z`4`jR2q!Dh2fWeD92W#i@$BkBS=_S!YN&0?q7avKaG1+Hw3A;oA@2bn=2BMpJ$*zl zjz9Qo#+Zr3oNAB;w1+~l!{dmQlsNLp^CH9=WDIQ55+N3nK0t8JsgHw!K+eUhrHo~? z5ht#`LXIYmZ~2&?BZ2(r^zUuN2%SZyOZkKn$p zX@KjC`*o{&{sz=u#ym*qRS7i25McKtt31VePJT2e7hT^8iI{}&&XZ( zlN8DXw4sckS1Pqx{(;)o7@o>Hyup-sk}^#@p7T>%Ooua#3^k#!YCae$TBv{t0!XYW zWZ;-}%;rrI%34QioqK)0zU5NjDG#U+9%Jw77Hv5Z-1va0B#HkWN4fuoMhfSO(<|gB zdI57f*T#r>R%P)wh4`|mwYRRj#tTO_=xedJ{uG%ic6@-9yQ5y zxxTlA+$+~kJAE2;vf^365CTCBeNCTE)HF6-;YRZ={UR<;4uLlGQ13coPZ&*bSGJsN znFJN&-#>o~?2>2Q(g`V&EgA4Cz|2cK6bKSXafahV#2_QcKr#(*KK>qZRTj8@{oUtZ zR$qMh+IAwH>yTIucQ2v9Z4K_#+2dS_DrF(O*)63{6WawL*V0a4wB1EJXQhH4vv$pT%tCA+-o1^PQ+iTN+2PbwncrfKZB85hr(G?}?cGOXB7n%eOo>qdfev4wm-% zIZ!1PC5Ktmg;d1~cVp&HFi{OpxJ`WhSq-4aTJ0;12M;}0YnX-wj&=nXroXpZ9~ET` z&z_V#fQ5z&)m(Lk_0-4$b?0m{YH&0nrafeaL~0DhJn+UVFtD<|F#zShhl%43`w%-{ zyanc+4`0@rvJwFncjWo=9j>NSIxxJH?7729iA`Yb4>SuaFd;1u8Ul$WT+hcBAvYgX z5HPL6oHU@wLFMf&i-4 z3RjQ`%6u}b?+_vTio;^o&I>r@`mwt7TpnA^dhAElR)lCZYl914dYPNLtBbeiGX@Gb zS2a92R{&p(Y9MvrhUE8diw_WTYts?Y&|*n%>~^s=Z`u2N)QJ_s(vR(I1H2Ub?DEK>M7AFAlvFiM8b?wUEz zZb5idA;K@pS3|jivX*gXA?VsF0yF`LNX+opHH5fnKQEFf`T(@HlrI9)EgS#EyPXH3 zIAEAQ8%Pxe(e|3j4e08{di`0$Z^>qz3y$eb(ioDnEp4R-c(%Pr7?pBw5Akqs*9H0g zpXkZx9P8>{vRxOZ#iQZb@*j|sqmOPcTv|D?P2s1=trY4xFUA=n!__d?l@nXgSn&gy zom58dPN-uE)S1F5?P@vqmwgwH~d2!~(QgVMbKN|KmzUKQ{ zYEc$^WlM4YOH8=@ELeBg331jlX*btibm5HSEWf`^QlKw~)`lx{mC)|@;AWA*%Si4j zBv7(^*?y|+(0wD6ry{xa|4kLE3f{P4bY3>KS=Dl!v%lf%qK&!|16KsW*xm30OL=m0w&(c@$en` z`ajsle`qTljsAF){kU9iB#g3{-<A*53~mDl&qer zS+^@b6ftrw5FwgGrxFL&ro=s@YW0c66^RSP9(W%gz;w+$QJuSM8D0jhs9R7fO2Tqk zjJhh2S$2d5L+l7ofK&uqSxY*SDcK*p7Z&83m2hD_hl88aeUsw0!M6ydI@);O_CWW9 zFmW0r@&stNG6Gn$@7R5NWpW*d5UZc}5o3cRvi7cvCIysExDQxJHwLS%c&IM2$V4uz zr8Ee3(2`6^Hau7Jf|a!8IBgit2B#?GJpKk7pQ!R`{SBR?habXn5;ia-9U+_iVsYfRsrSB@JPVAL;=0Yhsgai8Zc2Ko7a8qNfx*;J;e|+xrYnm;S5B0=w z?@T_mXcS#j@kRk7d49jQ&OxIBifC}$%3B$1v4LFH5GFHW#V~KOgf+SVuDOtJRQde; zs{3F$W=LY|D)r*C0+3BH5=;keL7Nwo zg8mlzX&_Ry=M5b8KiPmM35Tv*l$?JCozavNn}kD(YJqM-4o({VByY}$42eU7n{oxM!HZL(LR zRz2k|vGV&3DR$ZiIpzg{*inssN0a?Hcx$w*GP`1~G3gcd1qniJkZ!@>=5Jr2Fdcwr zqNJc88h{jx#7LtS?$4bN(hqRN3e{$9HL4nE0m0z6@DDZ_HCiimjm$lfma!w-s?Yj7 zn$}d0>`6{aV8W)FVGU`4=f4Qd#YQ*oc@4ZF+u3A#VG;nLa1?~>^V==Bb3E{axFd8x ze4UwNrzUn_N!f;Da2__>6V9PAh#w;8jK8=0s}vxBMQfXyK)#y`Egek~5;om$n%3pLXp zK&$O8bqO*Vm;8Tb2z(;FM_D)7-~(ClO`T7CNL!%<_jaWG)U@}m^Z`1i92*G%e1%{^ zPgZE-jZT|{LwjE>0u$#!t_cmMXyh)7kCa6`IUz$>#(0){t#xDbaICIsi7G&UaMS%; zIb*2DhDOo@Dv20L{7MEwo+ zFu`s%Y=72wRCbmgFwdx?NGH?}%qw@M0Fh3; zSBIYK>JH+QO(m%!=pOAMTBHq$RB+>nt4Q49e@f(pI%YmmR0KiqFC~RH^+qTe8<$Op z{GxP`sd0=`O6P7$7ZGC_1H{yDg2(g;ZR6ZdkR37RrxlwaZzvMW!BxB6TM{|?R6qT? zSZo#Z=#&dS`P*#qX0F=h$y1nCru_M#BabHrmwNL2T~AygKCO!wJyyG>0Mnfr11s3v z9ex*W#M19paI*Mn9@6^V@`S=aKAu5w{-pT{d7ECW@Bd4pt zP|!*(eZ^-6`hY0IKDQ(*tEuj_3>|;sjr0x2zg;EoM!h@On7H0MZ-v9QAXz?1)LZEJGV>TKV5B_iA zLL3LR>ghQ)VFp_KrZt+3=oz?n;Vc$X;XVAx9SKW3U$tXVk{M#x_J9Jrb5L|;j7j;- z5---MEXV~`hCr9;*K)n*#_no(d)-R`(z(5VyU(f+S1ok=SK0TMW}}QnfIn@J{huQ|C!!yx@xr_m<27H&}LwDi9^W%+4%VxZ?<&g$s`J|*BbPm z1&|>_{*zCRo0d;re(?En;H54t?b8#CE~!-T%ez`}HW=8xzOVW6u%WS?Q4v_X1S}9! zh_tn`R%5%Dx=8?gco*k2hLJVaAtfg`8bZGmujpjH?e?l+hir=} zE6`bhR$f%0up2WJSQvQ`Iu97yVTF})f!G@x%u&isRq*lCG!2G=_Fb85pkvIb8iu;Z zDbqER5A=i;SrZr8t0fP`4|*)0<`%{M&VRJn)3A}BrMThQnlueAf6B{?cs(JB=5bc< zhrH=|Iy(Nqk^?UkmTT;L@T z2?WtMJqP|;$QX7?b-3pP!?&DT-Q<9EEdv&hUaY%Kn9U?(hO(_*I6DQ6UNG>=z@?3YCk>vyLu!zOBgS;@8W2;}BvC4H+)HnxuJjJ=fb+~qtUOK zu8!bqRgpg?AZ?xcT<8%!J5i7>`0mR+@*t`^&peyI+(6_hF$*v19AO$Pa{~yaj-nr; zA5QkYo}2r{B|;xmKzgib6}ljwasW+YWyjt1Xv+Q^u3=O8(A;rIoo&Wj@Tgja2+WDt zhp~)DnQggT8S|KM447qjW8?ma)gTZ6*Qmui45Bt1?x8s#D5!V{}gfb8CbWI4MS2h;|QoTyih_zgTu_tisvTE-1a zRglek+(=iHZ+Q-b;9IglX)Ju?ldHqZA^3VHf41GP|A{Qw%dDmnvvZ=_AjfcURF(6R z8WzZ5u%jkxfJ04|nz<*46S!63EDhRP8ole31oYNPVclEw|9bV`xg|gfO2&PjWImYA z#egwRJrXe?a*?-5PK_o*VGHHiOmfo1h~iIg)S8Z6JkiXs1*I=r)kb&-apZ5`nTkwg zdR$Q`98MNb#6ZdjzE{ZPpJKb?VjGxkM1ij9?WWP7fhF-J6P!pd^11{dD&dzGsC=fi^yRkBT1>Ztk(oFJa- z0A?~8E2H;@^^#x|3(mAfO%P;A4txQxoS@Ud_FBZpn37+RBM|T6<%?9a>dCUopqsVB zDf!x}*WGHYXZi839DtIKX3^F)acWSkZXMJ*3_TB$?XS!K+4 zs#gp;7A&`Usc)-(i^7;czs?_vTP>JPqcHDdsfaX|+`{vYwi98T6P%NoL5|~FX|C~V zmSie!u)G!$#{!s+Tkx>AYi4;t#GAB;;)27H0;z)K19D&H?Zb@Td#EWgEQltB%SSug zbL#3;PU!8!uX53}^!tRMkEtDXX}=ej+WQ?n`0lbac22EmaT(d1m?0umCKFddCYF53 z8r?#%()wFI#@}$L35~y`fX9lO{Tep^VH76wz<8y900`74|BAvH&2nXY%_B>;r37>ULaa9Gd!@9T{Mob{0(fO&Lng(5Dj@9>+V_7 zG&JGo@h(rA#dkn^LN$0PB;I^^lg5G_ISb-2u_l61nI^8)3&tjWTpk(E^{==5fw#+s z0y~1d*Gl;a+{w@NQbOVHZDb!LoF(z42=#b&$z`peF8Kb#q|4+G;r?y%{c$MHOl;|Z zyb?MKC|665F%;{Y~S7J9sN{ zEexA{T+>f-92+}}^1l3U@O-^*uV+mpDtw6~F6|UICycP}-k*8PO8I@b7sQkg?fW99 z)N>y&)#TkuFV-j386)92Gf-S;@Fpp6aFFh2Y6bdP*t|AFTBCQ1E(4` zZczuY*3iD)ErrnrDG0_#*s`C!LB=Z1V%pnQTm3D|CGJ!?)a5Y=g3r$SJZywU+?yYYNt{pD@)Oz6IADgYuFvhk^bOGO zc*%N_Y%A!*=GAIX*7rl`*ElTN{*%#56?GfGo1zA5n znOstDu~pEtZ>kyLz#`RPFrJek$_pa%V-CI19PU+8sCN%YXpn#)Hbd~uT+E^)*^pOm z=4x)u5@HcfjZFct)k?5}AVS_ZOx`R#se~jO6!%-d2$T61G2s#;u9<5T*I3|II=qY{ z_BzOPqrV^igQ{}o%!&6eD(!O$HR>B>e6KlEu%Cd##({6|29cTyVghQ`<=sg!?elZ> zY!D2`Ww0VT35voeGic{-mWd^|hc&6YE>ti&2}h*9)&_%}Zai*Y4K)k7XbdMnV5W%` zJ6M3aOXKB{XVRl$Jh(F^`d^mRccUbtm`d@)GBmllG^|$#sd;b5WMyM4z;gxYGVd2h zy>M4!&i^7l$di6`eq@{SPaq)M(T_^6URF{;?n;QWzXdGkeE>k%aKF8+HAIo^qG_nP zG-mX~^NPcYA3&XdSt%-sm=2lOLp;AGACiYSCi(_=RGw9LSmI5K)jZ>4F$9zo9AC+k zJ$@R1Ba?4}Sl3V2g%|X3y_Y|OQ@>@Yypo!w8ku>ssez>HWyzfCYQ0Q~zc-!@6OVzE zcbX3A4$QS!yHZ$)dUmgJPIFD?_&?YUT)k^hlY_d(V9<{fu9ZHeq$n%;+dj`66k~Xh zyM3Ox6$sG#ix2djZ1bLlLW_UmmVpH6w$RwDll4QpMZ8L8@1)uzZ1AjA?i*q+MAddX z#U(%ANvNe}Rt38Qgal3e z7bSzAto8#jU^UE>tWtT*9!VF;X8|;4mZkF!-H3b`E|l&TBSh%x7MXtCr1O*01(*tY z2WM7_zAUqrTuvG!IZ9|YXo4qzET7sF(mZcMX;{&vuQ|GlX`;RZ69zXhv<~#0%1WB> zSz0joeDx{Tls9bxNzx|hiG=d5smg%(lLl56$47A-$s6sXY%R+E2l(E$=AY6_D2&yy zOxh?MwS3=6<&zY;X2VFEbka0-CqcP#Jik$s4L@q7z~IkP(%LB6q7Va5;;Kot*vw$*u*PKlA5L-;`M8xWSTyv|tW>`j@u z1g~C{4h`4=VNK6kKIG9^mM1lm{V_^*G)<^~8ufsltV(rPi;cjt8y^rCb7|EcC!h+Q zDS12aJo`f`9zZORHT)JbXc(azcV=05@n5fuu3zwXqE_%pP=u`vIpQ$kZ#6 zw?IzWI$*I&)GO)^J;^Ypn#nfCx)eIw78g;|VJbzO7;N?ws?2?fvazaiaE(WRs6OM( z%4pz&XQD*mdk)Ljv zEB@^$cy0`Kbv%~_Iby7G*i}cedTZ6=FTo|5oDgPS7(EhA2~y`6b}#w9U8HwD2WXiOY# zA|}q&T+vT+{PG79qMsrNY1|Q`Wv5lw3hN^^qms)G!;fWNq~%b82>qj0tTY@FKG?X3 z{VfhwN`z`)V`)A-Lk#T#yg(s;vXZ33Cqm;Y`ECRr~CLM@yysz!*;7BCdW3f1KdEWju(* z?K%2G{C|Q%c>rs~Iw#B5VzdAp-*qe(jdKq=4?f-5IR40ZY#PhCX)MW0ETT@50VRX%$fr?U`xb<+PJj@5g@3&W@k1j5{{T7>Y;mPwRJ*R{|6V8%pRTXpt7aM`{iC!eiaz6k5Fagg;^8f)^P4^ zo|q#>IPe!A)aQXtq;o2uH|3+x93s#X@BEk7;8=Xrw(DlNY=ry@*x1wa0SS>e8>k4V z0v>;;S0vqV395g#;Y&4LRK3B3($VGk_RbM7wi#6*=4z)9?IqXRFW zN=KQQh!lAIG3TqC4BRwss$Wg4M|foO<4?M31^-D{G@xTeM$<92?Az@n%{INt_{Grm zAxN|Ap7*%!wp%^b#YzPfpu@#Y`tlEgvdp?@3yp%Atr}MvSXThxU0*F zNCgOj&?4+3j3&x-YMZW_VO(|@@D5k)#hI;bu--Nm4*7_q-R;} zN|$ew_qa?C1V$#*dAt4`32O27xr$?*=_H{Hy*$WxxumEZ*yW8V|0_g7vUjgS!}MlU za7Vsi;VJ8>w3dprQ{li~>p_`ZGQpdYrZ1OVKkJyj? z*Ls8)mG|0~U;F8sSHdu=UGDF|`^1|5jem~K7k&EfPuNo)iB2>uj&_%l0;WKeGO)Tk zKLiXQB?UvmI6%?_h4bj2Kc8mdW2SdbCl11#SKS3)xWaUZ%VCE-RNWVXn5dStZy|a7 zFajz~;NO?q5-gy*t6UZ{%DqjFTMRDYc@5SYvsXEPo^oDpHLN&cSXuBBL~2G~1njex z@L_;a!2AerDx&^>H)O=FM;vUhp)Vy5#mprrXa$V60^z8nly2`4gKRH(|l&(g;D^_aoMO86Mc}frutCL=vYNDApMAEz(zwn zH}r+=*xPv8dj3Yj5fnQOUP84OS^~rw8Ux5;OcxfAB#H!ww(9)EeF@do)rml)vS%Vw zTCd|+zDJF=4I#NJ8mdiA9y1bMEK!*7gJ*lp>iL^3tf}OjEgu=AI}Y&pbRsq9o09Wd z7~*YLiD2b7Eh^MH zkB@)^gxzcWvw9`FZVf@aXCFX!CQ@W?eD+^`9C+5qA#rUNyj)hCo00Y8eZi@70Tz=V zdpLW&Q`gT>@#k9X2;1ejs_&edm~k-X-~$M}enzDyKailJL5e8C2|aD}s6k9@a%zfp zYu{C^*fG6F9sY++X|C=dW3=IOEsU9x`G2U_@?X6!iGMgViE|vUv>Y%0xd*Ii1}16p z?SXU=yF+0(e5g)X$&je};ZOm-6-~hiz3L3Q*ZD|-H9E0Nb#&C_H0FBZGy|rLgdE!m zIS@D5SX@N+f^!rqM;&Yns+$B-MC*SN|;co?1N57~R%d_fLz+J9O( zwD_Q~k`s|vxK~LQANkw!b8NNH+fhCISstIBS6#*nQszQ;bzL#bA~>xy7HN@>7@76p zNj?W%WJp-HHtL^L7;~=hMY~aaYF(Fh~)bp2xOZY7$qk*v|PC1>805rbu$=2c3%OPd+HBuC>_1vVZe|$&L=BrQa#X>1`S7 z+6*=8O|>o04lUZ`X;tc_b6KJ}YEH)KA+^)SiBD`;-9<95VI$KSbs?|JLbGdTD$&39 z1Z@2IJ8Z@ZP1tyBHlr4LBPKdpwurRfxx>fBDu=E_&ByA-;LoF}LT7wzT6jE;Wx5cX zd#uxM5d(sS1#b#WB^9>QUB8?Ev3Gbe73?^VPWQw?M?SyS=4qTUh~t<7+tRn1UxK|f zS_ZQ>4zMX}LL}d&_QJBftvI7ys*UAmRAU;Z2tD&Ps~>yvFFiSdsUJjwuIx|F)hX{P zzE(jT`?nPwSub@}n*vW@uwD*Bhk1gXCU-~4#K=(5t9>O4oUi{%|H0eUo-+avHv7R6 zlR^mV@Abicr$*1u`T6WoeJwtN8xeGTR2(2ERl~SdXG)%nz-vw~aVXy&!l~3C(V?uo zPkFelX01@Ev!$US+py4xT$?cdLz(jV_m}C=XP7$Ev$s3iQM}q=hwL?6!De@EoCkwA zG}Yx7gTXovwJS^{qVd=NajCo7?S<%_dCSx9#*YVcgC%_`A!>2In^Pi#cEm*?RbxZASqM-$%nAB<6GToK@=Je>xdzU2UO}RoMH6;kI6mAv^DhQB;d8rbPgy; zc=GP5?kKbtvH~;+5i!&PvWP>!BRxN&w9MIJT=cuH~ z2?X5?C0#&AJ)}wjoh->ga(f5^n~06`@uQ=Zl-Vd>7e8hxa<9xYXS6oC9icvu zy~%YdPqJcVe(aj`CMjN^6yBT-FWlPpm5oJC1OqP|w2V(m)}NFIiGOwZ&t+zQc!m<{ zi#`Ay{i1Rz1}?DmW!JZYyhema2fQ-?Ik%n1CvAY&@R(909Xkc1$ef~!b+QG5=3$-7 z;gKTc!;zx*L353QA)O%0g{J#7E#)|Zh=A=jg+*omPbKJ+vf{VOjdW}O_dT9@gbQY= z&cEe0%>3vyxnu;orE9{A8q8VnW0Z5eA+${OXACS+PU@%%B4q5d3mEFUbr*O#m*_K} zN<|PW@4N_6v0Fo+Rn~5kr1=NDg=dQMmDipN^(p@*2do!Y=<{Z@e?w|>c_v=B7__#s zE5qjgf>RPFCTB#xpKS&>{~ueJ?WFON8)7wVf{XC22=R~;Tl?U4U zFXRO@6KBAT@c)={s(P^8>+nfubp7$K%!!GNa;}VRhqXXl2E*^sq~K?MgK4P8sQxdO z8FF_-Ux%v3uO6wS<~vLXKX1a>sv;5(mUd+JDEL&U0|i$q082R3l+zxBMUrmIMXBo# z@ZF}zF8~=j?^80muK!kfe5nMwnjb&3s^>ZbG*V(Y)8bHXg*~TSu9N-&QF7@v)bGvE zpl_jUH=y?rdhcK)`$ul`!JnKueO6!%Z@m8k`1)CDu+K2=XnIq3q8-`Q{tcIxi~+}ddWx0Djyv>CgdYfU7H_R^a7ZTf z8i9|9nLYF9>e#C2(Yz90 z0`SQ3rT0*i(Xvgh$0&I-8wwRoAjB2I5{E{l!`W`8tRT$P;F6k9#M3B(IH=n%dWm<3 zH08BG%kt1D`~MND-|z8TmF#V~V{`Rx{cM=so2z8*la5mcSeHt+WT!eBgjO&dP9!L= z*)~UF$Rh8It!6j?;z>T^oGG0~3i@tlSRV@Al;iyx+d~~7*q(yh;#=mRn_YWmk)ahX zBY{_r_XV11*Wt%g>9V_?DIW(;Z$Rqu9X^^D8E$hfv(zSe=YEN)dB6#=3lgj+GdOYy z+QouLIR82PlD$m{ZhT#_6UjwB$ro*=Mp04s`w8ElSeggW0? zlyV-?q{p(7V)(*{sRRGnznLYYmE=$zbC9(Oxd zvIc9yydXms3t6Qg4zB=Bm&*%Nh6xSP>|5332fp#0f2Y`=UiUFo_4uZ2Dc)SX7(X_|(X{az1Q#do|M@a0$(NYf8TnrszQR>^!**i?imX89x=dWJX`&Kx(XPII;3>u-wY zOHTtWeAJhu(eeueukrjsx3tFY6y9X+G}5NN2*C@h|7HO@^T&ZwwEysslh(A8@p%vK zn~)HIV3nhL=jID5x)kDYaf+syLiIr|?&wWT{}Wv~7^Hdcw0w}x+ye^LGd3AL9+x=E zb&9)eOVZ^o&f8p~YzP%?*)~Q5bK|m{sjo{u6@&6)MP7O93*>Vzar$5 zyx%h*e5|tu2YvMuG&=de0BHo4`#1j(kS$r4*YdroIwMin91b*KAg=XDbnR!;u%=c= zgrn*3-J-Z1BzFujpg_EKoOhf*1?T>1vS}ksy#thd;QyiX|T; z_5$_|M!Hq*>kDmW;NgJp{Ur0$mbq}yNaNqMW^rc*~|s!(n)?i7<)X7e_mxkzBk9;$9%kQa;zfe65=!B zfpl9F*XE9JJ8g%|QO&OaS$pk?X_z0rF}~xxk&0>SftWW=qKBf zvIVnkEfddBH{%HEvR*237>TpGoZKT=*>ip87PZW}DztYjQz7uu)S5pZkeY-`7P z$N6(`o(-jOLSk6c3b#PNU}cofPJH2P@GBJ)u)jJ$f7CH6C+|YA(ZL7yb3t09VBH=8 zi96TP)ND~wmDMRVu2HFyK@rQbUY?6V#kx5E`EOF`^F3jU9M>zaKh!A)^Qy0Cs#9tk z`4#l@%Uni{MM9t6*q-VJd?Zgac5kcKNrsN|j`L^ZJk`9Yks%WriiN5Uax%GScgbUep_b1lwUZ+|#4uZDr^bWsMQGJ+ms{XMFd`}a z^Utzhey3dGkji7i(aGGaNrme0(#<<@sTlyr?%R=MF_DsZ9cV&U!-aMQYjx$`+s7u?x!&MGg8|w~Df@Ta(UdORk~7$4%Mr z&9G1lxWwh6lE-RSEFVvxgCK;~d{G0c4gZX%M*ujUz4rJP!EC5uxTIPE`P_YbpR7z~ zw#J$Mj7dDmC`b7XWzNYao%zM6rAgajcA4K z8ygxlZ(dMhy8H~_STKf@FU3hY%{5D(;B}x<(|!trD*R^=1R|6aPk_Id3HmrZxQ0K$ zl_&A4vJ~`q1R({}4)6T+^ixc|>4E^MycnWd|Iqw#5IfmD3C5LoTT!i+J7nUC^b0m$ zV%vF*8_%SJg4J=G?ZLfsM+X^l%9 { + try { + const html = ` + + + + + + Checkout + + +

+ + + `; + + response.status(200); + response.setHeader('Content-Type', 'text/html'); + response.write(html); + response.end(); + } catch (error) { + console.error(error); + + const message = 'An unexpected error ocurred'; + + response.status(500).json({ data: null, errors: [{ message }] }); + } +}; + +export default getCheckout; diff --git a/lib/spree/api/endpoints/checkout/index.ts b/lib/spree/api/endpoints/checkout/index.ts new file mode 100644 index 000000000..4cd8d054c --- /dev/null +++ b/lib/spree/api/endpoints/checkout/index.ts @@ -0,0 +1,19 @@ +import { createEndpoint } from '@commerce/api'; +import type { GetAPISchema, CommerceAPI } from '@commerce/api'; +import checkoutEndpoint from '@commerce/api/endpoints/checkout'; +import type { CheckoutSchema } from '@commerce/types/checkout'; +import getCheckout from './get-checkout'; +import type { SpreeApiProvider } from '../..'; + +export type CheckoutAPI = GetAPISchema, CheckoutSchema>; + +export type CheckoutEndpoint = CheckoutAPI['endpoint']; + +export const handlers: CheckoutEndpoint['handlers'] = { getCheckout }; + +const checkoutApi = createEndpoint({ + handler: checkoutEndpoint, + handlers +}); + +export default checkoutApi; diff --git a/lib/spree/api/endpoints/customer/address.ts b/lib/spree/api/endpoints/customer/address.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/lib/spree/api/endpoints/customer/address.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/lib/spree/api/endpoints/customer/card.ts b/lib/spree/api/endpoints/customer/card.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/lib/spree/api/endpoints/customer/card.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/lib/spree/api/endpoints/customer/index.ts b/lib/spree/api/endpoints/customer/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/lib/spree/api/endpoints/customer/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/lib/spree/api/endpoints/login/index.ts b/lib/spree/api/endpoints/login/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/lib/spree/api/endpoints/login/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/lib/spree/api/endpoints/logout/index.ts b/lib/spree/api/endpoints/logout/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/lib/spree/api/endpoints/logout/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/lib/spree/api/endpoints/signup/index.ts b/lib/spree/api/endpoints/signup/index.ts new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/lib/spree/api/endpoints/signup/index.ts @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/lib/spree/api/endpoints/wishlist/index.tsx b/lib/spree/api/endpoints/wishlist/index.tsx new file mode 100644 index 000000000..491bf0ac9 --- /dev/null +++ b/lib/spree/api/endpoints/wishlist/index.tsx @@ -0,0 +1 @@ +export default function noopApi(...args: any[]): void {} diff --git a/lib/spree/api/index.ts b/lib/spree/api/index.ts new file mode 100644 index 000000000..f34260992 --- /dev/null +++ b/lib/spree/api/index.ts @@ -0,0 +1,48 @@ +import type { CommerceAPI, CommerceAPIConfig } from '@commerce/api'; +import { getCommerceApi as commerceApi } from '@commerce/api'; +import createApiFetch from './utils/create-api-fetch'; + +import getAllPages from './operations/get-all-pages'; +import getPage from './operations/get-page'; +import getSiteInfo from './operations/get-site-info'; +import getCustomerWishlist from './operations/get-customer-wishlist'; +import getAllProductPaths from './operations/get-all-product-paths'; +import getAllProducts from './operations/get-all-products'; +import getProduct from './operations/get-product'; +import getAllTaxons from './operations/get-all-taxons'; +import getProducts from './operations/get-products'; + +export interface SpreeApiConfig extends CommerceAPIConfig {} + +const config: SpreeApiConfig = { + commerceUrl: '', + apiToken: '', + cartCookie: '', + customerCookie: '', + cartCookieMaxAge: 2592000, + fetch: createApiFetch(() => getCommerceApi().getConfig()) +}; + +const operations = { + getAllPages, + getPage, + getSiteInfo, + getCustomerWishlist, + getAllProductPaths, + getAllProducts, + getProduct, + getAllTaxons, + getProducts +}; + +export const provider = { config, operations }; + +export type SpreeApiProvider = typeof provider; + +export type SpreeApi

= CommerceAPI

; + +export function getCommerceApi

( + customProvider: P = provider as any +): SpreeApi

{ + return commerceApi(customProvider); +} diff --git a/lib/spree/api/operations/get-all-pages.ts b/lib/spree/api/operations/get-all-pages.ts new file mode 100644 index 000000000..2bbaf35e5 --- /dev/null +++ b/lib/spree/api/operations/get-all-pages.ts @@ -0,0 +1,72 @@ +import type { OperationContext, OperationOptions } from '@commerce/api/operations'; +import type { GetAllPagesOperation, Page } from '@commerce/types/page'; +import { requireConfigValue } from '../../isomorphic-config'; +import normalizePage from '../../utils/normalizations/normalize-page'; +import type { IPages } from '@spree/storefront-api-v2-sdk/types/interfaces/Page'; +import type { SpreeSdkVariables } from '../../types'; +import type { SpreeApiConfig, SpreeApiProvider } from '../index'; + +export default function getAllPagesOperation({ commerce }: OperationContext) { + async function getAllPages(options?: { + config?: Partial; + preview?: boolean; + }): Promise; + + async function getAllPages( + opts: { + config?: Partial; + preview?: boolean; + } & OperationOptions + ): Promise; + + async function getAllPages({ + config: userConfig, + preview, + query, + url + }: { + url?: string; + config?: Partial; + preview?: boolean; + query?: string; + } = {}): Promise { + console.info( + 'getAllPages called. Configuration: ', + 'query: ', + query, + 'userConfig: ', + userConfig, + 'preview: ', + preview, + 'url: ', + url + ); + + const config = commerce.getConfig(userConfig); + const { fetch: apiFetch } = config; + + const variables: SpreeSdkVariables = { + methodPath: 'pages.list', + arguments: [ + { + per_page: 500, + filter: { + locale_eq: config.locale || (requireConfigValue('defaultLocale') as string) + } + } + ] + }; + + const { data: spreeSuccessResponse } = await apiFetch('__UNUSED__', { + variables + }); + + const normalizedPages: Page[] = spreeSuccessResponse.data.map((spreePage) => + normalizePage(spreeSuccessResponse, spreePage, config.locales || []) + ); + + return { pages: normalizedPages }; + } + + return getAllPages; +} diff --git a/lib/spree/api/operations/get-all-product-paths.ts b/lib/spree/api/operations/get-all-product-paths.ts new file mode 100644 index 000000000..391724315 --- /dev/null +++ b/lib/spree/api/operations/get-all-product-paths.ts @@ -0,0 +1,91 @@ +import type { OperationContext, OperationOptions } from '@commerce/api/operations'; +import type { Product } from '@commerce/types/product'; +import type { GetAllProductPathsOperation } from '@commerce/types/product'; +import { requireConfigValue } from '../../isomorphic-config'; +import type { IProductsSlugs, SpreeSdkVariables } from '../../types'; +import getProductPath from '../../utils/get-product-path'; +import type { SpreeApiConfig, SpreeApiProvider } from '..'; + +const imagesSize = requireConfigValue('imagesSize') as string; +const imagesQuality = requireConfigValue('imagesQuality') as number; + +export default function getAllProductPathsOperation({ + commerce +}: OperationContext) { + async function getAllProductPaths(opts?: { + variables?: T['variables']; + config?: Partial; + }): Promise; + + async function getAllProductPaths( + opts: { + variables?: T['variables']; + config?: Partial; + } & OperationOptions + ): Promise; + + async function getAllProductPaths({ + query, + variables: getAllProductPathsVariables = {}, + config: userConfig + }: { + query?: string; + variables?: T['variables']; + config?: Partial; + } = {}): Promise { + console.info( + 'getAllProductPaths called. Configuration: ', + 'query: ', + query, + 'getAllProductPathsVariables: ', + getAllProductPathsVariables, + 'config: ', + userConfig + ); + + const productsCount = requireConfigValue('lastUpdatedProductsPrerenderCount'); + + if (productsCount === 0) { + return { + products: [] + }; + } + + const variables: SpreeSdkVariables = { + methodPath: 'products.list', + arguments: [ + {}, + { + fields: { + product: 'slug' + }, + per_page: productsCount, + image_transformation: { + quality: imagesQuality, + size: imagesSize + } + } + ] + }; + + const config = commerce.getConfig(userConfig); + const { fetch: apiFetch } = config; // TODO: Send config.locale to Spree. + + const { data: spreeSuccessResponse } = await apiFetch( + '__UNUSED__', + { + variables + } + ); + + const normalizedProductsPaths: Pick[] = spreeSuccessResponse.data.map( + (spreeProduct) => ({ + path: getProductPath(spreeProduct) + }) + ); + + return { products: normalizedProductsPaths }; + } + + return getAllProductPaths; +} diff --git a/lib/spree/api/operations/get-all-products.ts b/lib/spree/api/operations/get-all-products.ts new file mode 100644 index 000000000..3bdd722e2 --- /dev/null +++ b/lib/spree/api/operations/get-all-products.ts @@ -0,0 +1,84 @@ +import type { Product } from '@commerce/types/product'; +import type { GetAllProductsOperation } from '@commerce/types/product'; +import type { OperationContext, OperationOptions } from '@commerce/api/operations'; +import type { IProducts } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'; +import type { SpreeApiConfig, SpreeApiProvider } from '../index'; +import type { SpreeSdkVariables } from '../../types'; +import normalizeProduct from '../../utils/normalizations/normalize-product'; +import { requireConfigValue } from '../../isomorphic-config'; + +const imagesSize = requireConfigValue('imagesSize') as string; +const imagesQuality = requireConfigValue('imagesQuality') as number; + +export default function getAllProductsOperation({ commerce }: OperationContext) { + async function getAllProducts(opts?: { + variables?: T['variables']; + config?: Partial; + preview?: boolean; + }): Promise; + + async function getAllProducts( + opts: { + variables?: T['variables']; + config?: Partial; + preview?: boolean; + } & OperationOptions + ): Promise; + + async function getAllProducts({ + variables: getAllProductsVariables = {}, + config: userConfig + }: { + variables?: T['variables']; + config?: Partial; + } = {}): Promise<{ products: Product[] }> { + console.info( + 'getAllProducts called. Configuration: ', + 'getAllProductsVariables: ', + getAllProductsVariables, + 'config: ', + userConfig + ); + + const defaultProductsTaxonomyId = requireConfigValue('allProductsTaxonomyId') as string | false; + + const first = getAllProductsVariables.first; + const filter = !defaultProductsTaxonomyId + ? {} + : { filter: { taxons: defaultProductsTaxonomyId }, sort: '-updated_at' }; + + const variables: SpreeSdkVariables = { + methodPath: 'products.list', + arguments: [ + {}, + { + include: 'primary_variant,variants,images,option_types,variants.option_values', + per_page: first, + ...filter, + image_transformation: { + quality: imagesQuality, + size: imagesSize + } + } + ] + }; + + const config = commerce.getConfig(userConfig); + const { fetch: apiFetch } = config; // TODO: Send config.locale to Spree. + + const { data: spreeSuccessResponse } = await apiFetch( + '__UNUSED__', + { + variables + } + ); + + const normalizedProducts: Product[] = spreeSuccessResponse.data.map((spreeProduct) => + normalizeProduct(spreeSuccessResponse, spreeProduct) + ); + + return { products: normalizedProducts }; + } + + return getAllProducts; +} diff --git a/lib/spree/api/operations/get-all-taxons.ts b/lib/spree/api/operations/get-all-taxons.ts new file mode 100644 index 000000000..2fff9df42 --- /dev/null +++ b/lib/spree/api/operations/get-all-taxons.ts @@ -0,0 +1,63 @@ +import _ from 'lodash'; +import type { ITaxons, TaxonAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Taxon'; +import type { SpreeSdkVariables } from '../../types'; + +const taxonsSort = (spreeTaxon1: TaxonAttr, spreeTaxon2: TaxonAttr): number => { + const { left: left1, right: right1 } = spreeTaxon1.attributes; + const { left: left2, right: right2 } = spreeTaxon2.attributes; + + if (right1 < left2) { + return -1; + } + + if (right2 < left1) { + return 1; + } + + return 0; +}; + +const buildTaxonsTree = (taxons: TaxonAttr[], parentId: string | number): TaxonAttr[] => { + const children = _.chain(taxons) + .filter((item) => { + const relationships = item.relationships || {}; + return parentId === _.get(relationships, 'parent.data.id'); + }) + .sort(taxonsSort) + .value(); + + return children.map((child) => ({ + id: child.id, + name: child.attributes.name, + type: child.type, + position: child.attributes.position, + children: buildTaxonsTree(taxons, child.id) + })); +}; + +export default function getAllTaxonsOperation({ commerce, locale }) { + async function getAllTaxons(options = {}) { + const { config: userConfig } = options; + + const config = commerce.getConfig(userConfig); + + const { fetch: apiFetch } = config; + + const variables: SpreeSdkVariables = { + methodPath: 'taxons.list', + arguments: [ + { + locale: config.locale + } + ] + }; + + const { data: spreeSuccessResponse } = await apiFetch('__UNUSED__', { variables }); + + const normalizedTaxons = buildTaxonsTree(spreeSuccessResponse.data, '1'); + + return { taxons: normalizedTaxons }; + } + + return getAllTaxons; +} diff --git a/lib/spree/api/operations/get-customer-wishlist.ts b/lib/spree/api/operations/get-customer-wishlist.ts new file mode 100644 index 000000000..f417bf0c3 --- /dev/null +++ b/lib/spree/api/operations/get-customer-wishlist.ts @@ -0,0 +1,6 @@ +export default function getCustomerWishlistOperation() { + function getCustomerWishlist(): any { + return { wishlist: {} }; + } + return getCustomerWishlist; +} diff --git a/lib/spree/api/operations/get-page.ts b/lib/spree/api/operations/get-page.ts new file mode 100644 index 000000000..fa00ffb42 --- /dev/null +++ b/lib/spree/api/operations/get-page.ts @@ -0,0 +1,73 @@ +import type { OperationContext, OperationOptions } from '@commerce/api/operations'; +import type { GetPageOperation } from '@commerce/types/page'; +import type { SpreeSdkVariables } from '../../types'; +import type { SpreeApiConfig, SpreeApiProvider } from '..'; +import type { IPage } from '@spree/storefront-api-v2-sdk/types/interfaces/Page'; +import normalizePage from '../../utils/normalizations/normalize-page'; + +export type Page = any; +export type GetPageResult = { page?: Page }; + +export type PageVariables = { + id: number; +}; + +export default function getPageOperation({ commerce }: OperationContext) { + async function getPage(opts: { + variables: T['variables']; + config?: Partial; + preview?: boolean; + }): Promise; + + async function getPage( + opts: { + variables: T['variables']; + config?: Partial; + preview?: boolean; + } & OperationOptions + ): Promise; + + async function getPage({ + url, + config: userConfig, + preview, + variables: getPageVariables + }: { + url?: string; + variables: T['variables']; + config?: Partial; + preview?: boolean; + }): Promise { + console.info( + 'getPage called. Configuration: ', + 'userConfig: ', + userConfig, + 'preview: ', + preview, + 'url: ', + url + ); + + const config = commerce.getConfig(userConfig); + const { fetch: apiFetch } = config; + + const variables: SpreeSdkVariables = { + methodPath: 'pages.show', + arguments: [getPageVariables.id] + }; + + const { data: spreeSuccessResponse } = await apiFetch('__UNUSED__', { + variables + }); + + const normalizedPage: Page = normalizePage( + spreeSuccessResponse, + spreeSuccessResponse.data, + config.locales || [] + ); + + return { page: normalizedPage }; + } + + return getPage; +} diff --git a/lib/spree/api/operations/get-product.ts b/lib/spree/api/operations/get-product.ts new file mode 100644 index 000000000..bc415329f --- /dev/null +++ b/lib/spree/api/operations/get-product.ts @@ -0,0 +1,81 @@ +import type { SpreeApiConfig, SpreeApiProvider } from '../index'; +import type { GetProductOperation } from '@commerce/types/product'; +import type { OperationContext, OperationOptions } from '@commerce/api/operations'; +import type { IProduct } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'; +import type { SpreeSdkVariables } from '../../types'; +import MissingSlugVariableError from '../../errors/MissingSlugVariableError'; +import normalizeProduct from '../../utils/normalizations/normalize-product'; +import { requireConfigValue } from '../../isomorphic-config'; + +const imagesSize = requireConfigValue('imagesSize') as string; +const imagesQuality = requireConfigValue('imagesQuality') as number; + +export default function getProductOperation({ commerce }: OperationContext) { + async function getProduct(opts: { + variables: T['variables']; + config?: Partial; + preview?: boolean; + }): Promise; + + async function getProduct( + opts: { + variables: T['variables']; + config?: Partial; + preview?: boolean; + } & OperationOptions + ): Promise; + + async function getProduct({ + query = '', + variables: getProductVariables, + config: userConfig + }: { + query?: string; + variables?: T['variables']; + config?: Partial; + preview?: boolean; + }): Promise { + console.log( + 'getProduct called. Configuration: ', + 'getProductVariables: ', + getProductVariables, + 'config: ', + userConfig + ); + + if (!getProductVariables?.slug) { + throw new MissingSlugVariableError(); + } + + const variables: SpreeSdkVariables = { + methodPath: 'products.show', + arguments: [ + getProductVariables.slug, + {}, + { + include: 'primary_variant,variants,images,option_types,variants.option_values', + image_transformation: { + quality: imagesQuality, + size: imagesSize + } + } + ] + }; + + const config = commerce.getConfig(userConfig); + const { fetch: apiFetch } = config; // TODO: Send config.locale to Spree. + + const { data: spreeSuccessResponse } = await apiFetch( + '__UNUSED__', + { + variables + } + ); + + return { + product: normalizeProduct(spreeSuccessResponse, spreeSuccessResponse.data) + }; + } + + return getProduct; +} diff --git a/lib/spree/api/operations/get-products.js b/lib/spree/api/operations/get-products.js new file mode 100644 index 000000000..d39c66144 --- /dev/null +++ b/lib/spree/api/operations/get-products.js @@ -0,0 +1,37 @@ +import normalizeProduct from '../../utils/normalizations/normalize-product'; +import { requireConfigValue } from '../../isomorphic-config'; + +const imagesSize = requireConfigValue('imagesSize'); +const imagesQuality = requireConfigValue('imagesQuality'); + +export default function getProductsOperation({ commerce }) { + async function getProducts({ taxons = [], config: userConfig } = {}) { + const filter = { filter: { taxons: taxons.join(',') }, sort: '-updated_at' }; + + const variables = { + methodPath: 'products.list', + arguments: [ + { + include: 'primary_variant,variants,images,option_types,variants.option_values', + per_page: 100, + ...filter, + image_transformation: { + quality: imagesQuality, + size: imagesSize + } + } + ] + }; + + const config = commerce.getConfig(userConfig); + const { fetch: apiFetch } = config; + const { data: spreeSuccessResponse } = await apiFetch('__UNUSED__', { variables }); + const normalizedProducts = spreeSuccessResponse.data.map((spreeProduct) => + normalizeProduct(spreeSuccessResponse, spreeProduct) + ); + + return { products: normalizedProducts }; + } + + return getProducts; +} diff --git a/lib/spree/api/operations/get-site-info.ts b/lib/spree/api/operations/get-site-info.ts new file mode 100644 index 000000000..94c1142ff --- /dev/null +++ b/lib/spree/api/operations/get-site-info.ts @@ -0,0 +1,120 @@ +import type { OperationContext, OperationOptions } from '@commerce/api/operations'; +import type { Category, GetSiteInfoOperation } from '@commerce/types/site'; +import type { ITaxons, TaxonAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Taxon'; +import { requireConfigValue } from '../../isomorphic-config'; +import type { SpreeSdkVariables } from '../../types'; +import type { SpreeApiConfig, SpreeApiProvider } from '..'; + +const taxonsSort = (spreeTaxon1: TaxonAttr, spreeTaxon2: TaxonAttr): number => { + const { left: left1, right: right1 } = spreeTaxon1.attributes; + const { left: left2, right: right2 } = spreeTaxon2.attributes; + + if (right1 < left2) { + return -1; + } + + if (right2 < left1) { + return 1; + } + + return 0; +}; + +export type GetSiteInfoResult< + T extends { categories: any[]; brands: any[] } = { + categories: Category[]; + brands: any[]; + } +> = T; + +export default function getSiteInfoOperation({ commerce }: OperationContext) { + async function getSiteInfo(opts?: { + config?: Partial; + preview?: boolean; + }): Promise; + + async function getSiteInfo( + opts: { + config?: Partial; + preview?: boolean; + } & OperationOptions + ): Promise; + + async function getSiteInfo({ + query, + variables: getSiteInfoVariables = {}, + config: userConfig + }: { + query?: string; + variables?: any; + config?: Partial; + preview?: boolean; + } = {}): Promise { + console.info( + 'getSiteInfo called. Configuration: ', + 'query: ', + query, + 'getSiteInfoVariables ', + getSiteInfoVariables, + 'config: ', + userConfig + ); + + const createVariables = (parentPermalink: string): SpreeSdkVariables => ({ + methodPath: 'taxons.list', + arguments: [ + { + filter: { + parent_permalink: parentPermalink + } + } + ] + }); + + const config = commerce.getConfig(userConfig); + const { fetch: apiFetch } = config; // TODO: Send config.locale to Spree. + + const { data: spreeCategoriesSuccessResponse } = await apiFetch( + '__UNUSED__', + { + variables: createVariables(requireConfigValue('categoriesTaxonomyPermalink') as string) + } + ); + + const { data: spreeBrandsSuccessResponse } = await apiFetch( + '__UNUSED__', + { + variables: createVariables(requireConfigValue('brandsTaxonomyPermalink') as string) + } + ); + + const normalizedCategories: GetSiteInfoOperation['data']['categories'] = + spreeCategoriesSuccessResponse.data.sort(taxonsSort).map((spreeTaxon: TaxonAttr) => { + return { + id: spreeTaxon.id, + name: spreeTaxon.attributes.name, + slug: spreeTaxon.id, + path: spreeTaxon.id + }; + }); + + const normalizedBrands: GetSiteInfoOperation['data']['brands'] = spreeBrandsSuccessResponse.data + .sort(taxonsSort) + .map((spreeTaxon: TaxonAttr) => { + return { + node: { + entityId: spreeTaxon.id, + path: `brands/${spreeTaxon.id}`, + name: spreeTaxon.attributes.name + } + }; + }); + + return { + categories: normalizedCategories, + brands: normalizedBrands + }; + } + + return getSiteInfo; +} diff --git a/lib/spree/api/operations/index.ts b/lib/spree/api/operations/index.ts new file mode 100644 index 000000000..cffc30af8 --- /dev/null +++ b/lib/spree/api/operations/index.ts @@ -0,0 +1,8 @@ +export { default as getPage } from './get-page'; +export { default as getSiteInfo } from './get-site-info'; +export { default as getAllPages } from './get-all-pages'; +export { default as getProduct } from './get-product'; +export { default as getAllProducts } from './get-all-products'; +export { default as getAllProductPaths } from './get-all-product-paths'; +export { default as getAllTaxons } from './get-all-taxons'; +export { default as getProducts } from './get-products'; diff --git a/lib/spree/api/utils/create-api-fetch.ts b/lib/spree/api/utils/create-api-fetch.ts new file mode 100644 index 000000000..1336cebc8 --- /dev/null +++ b/lib/spree/api/utils/create-api-fetch.ts @@ -0,0 +1,74 @@ +import { SpreeApiConfig } from '..'; +import { errors, makeClient } from '@spree/storefront-api-v2-sdk'; +import { requireConfigValue } from '../../isomorphic-config'; +import convertSpreeErrorToGraphQlError from '../../utils/convert-spree-error-to-graph-ql-error'; +import type { ResultResponse } from '@spree/storefront-api-v2-sdk/types/interfaces/ResultResponse'; +import getSpreeSdkMethodFromEndpointPath from '../../utils/get-spree-sdk-method-from-endpoint-path'; +import SpreeSdkMethodFromEndpointPathError from '../../errors/SpreeSdkMethodFromEndpointPathError'; +import { GraphQLFetcher, GraphQLFetcherResult } from '@commerce/api'; +import createCustomizedFetchFetcher, { + fetchResponseKey +} from '../../utils/create-customized-fetch-fetcher'; +import fetch, { Request } from 'node-fetch'; +import type { SpreeSdkResponseWithRawResponse } from '../../types'; + +export type CreateApiFetch = ( + getConfig: () => SpreeApiConfig +) => GraphQLFetcher, any>; + +// TODO: GraphQLFetcher, any> should be GraphQLFetcher, SpreeSdkVariables>. +// But CommerceAPIConfig['fetch'] cannot be extended from Variables = any to SpreeSdkVariables. + +const createApiFetch: CreateApiFetch = (_getConfig) => { + const client = makeClient({ + host: requireConfigValue('apiHost') as string, + createFetcher: (fetcherOptions) => { + return createCustomizedFetchFetcher({ + fetch, + requestConstructor: Request, + ...fetcherOptions + }); + } + }); + + return async (url, queryData = {}, fetchOptions = {}) => { + console.log( + 'apiFetch called. query = ', + 'url = ', + url, + 'queryData = ', + queryData, + 'fetchOptions = ', + fetchOptions + ); + + const { variables } = queryData; + + if (!variables) { + throw new SpreeSdkMethodFromEndpointPathError(`Required SpreeSdkVariables not provided.`); + } + + const storeResponse: ResultResponse = + await getSpreeSdkMethodFromEndpointPath(client, variables.methodPath)(...variables.arguments); + + if (storeResponse.isSuccess()) { + const data = storeResponse.success(); + const rawFetchResponse = data[fetchResponseKey]; + + return { + data, + res: rawFetchResponse + }; + } + + const storeResponseError = storeResponse.fail(); + + if (storeResponseError instanceof errors.SpreeError) { + throw convertSpreeErrorToGraphQlError(storeResponseError); + } + + throw storeResponseError; + }; +}; + +export default createApiFetch; diff --git a/lib/spree/api/utils/fetch.ts b/lib/spree/api/utils/fetch.ts new file mode 100644 index 000000000..70407fd0c --- /dev/null +++ b/lib/spree/api/utils/fetch.ts @@ -0,0 +1,3 @@ +import vercelFetch from '@vercel/fetch'; + +export default vercelFetch(); diff --git a/lib/spree/auth/index.ts b/lib/spree/auth/index.ts new file mode 100644 index 000000000..41c664eec --- /dev/null +++ b/lib/spree/auth/index.ts @@ -0,0 +1,3 @@ +export { default as useLogin } from './use-login'; +export { default as useLogout } from './use-logout'; +export { default as useSignup } from './use-signup'; diff --git a/lib/spree/auth/use-login.tsx b/lib/spree/auth/use-login.tsx new file mode 100644 index 000000000..ce71f97f9 --- /dev/null +++ b/lib/spree/auth/use-login.tsx @@ -0,0 +1,81 @@ +import { useCallback } from 'react'; +import type { MutationHook } from '@commerce/utils/types'; +import useLogin, { UseLogin } from '@commerce/auth/use-login'; +import type { LoginHook } from '@commerce/types/login'; +import type { AuthTokenAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Authentication'; +import { FetcherError, ValidationError } from '@commerce/utils/errors'; +import useCustomer from '../customer/use-customer'; +import useCart from '../cart/use-cart'; +import useWishlist from '../wishlist/use-wishlist'; +import login from '../utils/login'; + +export default useLogin as UseLogin; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'authentication', + query: 'getToken' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useLogin fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const { email, password } = input; + + if (!email || !password) { + throw new ValidationError({ + message: 'Email and password need to be provided.' + }); + } + + const getTokenParameters: AuthTokenAttr = { + username: email, + password + }; + + try { + await login(fetch, getTokenParameters, false); + + return null; + } catch (getTokenError) { + if (getTokenError instanceof FetcherError && getTokenError.status === 400) { + // Change the error message to be more user friendly. + throw new FetcherError({ + status: getTokenError.status, + message: 'The email or password is invalid.', + code: getTokenError.code + }); + } + + throw getTokenError; + } + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType['useHook']> = () => { + const customer = useCustomer(); + const cart = useCart(); + const wishlist = useWishlist(); + + return useCallback( + async function login(input) { + const data = await fetch({ input }); + + await customer.revalidate(); + await cart.revalidate(); + await wishlist.revalidate(); + + return data; + }, + [customer, cart, wishlist] + ); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/auth/use-logout.tsx b/lib/spree/auth/use-logout.tsx new file mode 100644 index 000000000..90e0f3ba0 --- /dev/null +++ b/lib/spree/auth/use-logout.tsx @@ -0,0 +1,79 @@ +import { MutationHook } from '@commerce/utils/types'; +import useLogout, { UseLogout } from '@commerce/auth/use-logout'; +import type { LogoutHook } from '@commerce/types/logout'; +import { useCallback } from 'react'; +import useCustomer from '../customer/use-customer'; +import useCart from '../cart/use-cart'; +import useWishlist from '../wishlist/use-wishlist'; +import { + ensureUserTokenResponse, + removeUserTokenResponse +} from '../utils/tokens/user-token-response'; +import revokeUserTokens from '../utils/tokens/revoke-user-tokens'; +import TokensNotRejectedError from '../errors/TokensNotRejectedError'; + +export default useLogout as UseLogout; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'authentication', + query: 'revokeToken' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useLogout fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const userToken = ensureUserTokenResponse(); + + if (userToken) { + try { + // Revoke any tokens associated with the logged in user. + await revokeUserTokens(fetch, { + accessToken: userToken.access_token, + refreshToken: userToken.refresh_token + }); + } catch (revokeUserTokenError) { + // Squash token revocation errors and rethrow anything else. + if (!(revokeUserTokenError instanceof TokensNotRejectedError)) { + throw revokeUserTokenError; + } + } + + // Whether token revocation succeeded or not, remove them from local storage. + removeUserTokenResponse(); + } + + return null; + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType['useHook']> = () => { + const customer = useCustomer({ + swrOptions: { isPaused: () => true } + }); + const cart = useCart({ + swrOptions: { isPaused: () => true } + }); + const wishlist = useWishlist({ + swrOptions: { isPaused: () => true } + }); + + return useCallback(async () => { + const data = await fetch(); + + await customer.mutate(null, false); + await cart.mutate(null, false); + await wishlist.mutate(null, false); + + return data; + }, [customer, cart, wishlist]); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/auth/use-signup.tsx b/lib/spree/auth/use-signup.tsx new file mode 100644 index 000000000..c97080668 --- /dev/null +++ b/lib/spree/auth/use-signup.tsx @@ -0,0 +1,94 @@ +import { useCallback } from 'react'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { MutationHook } from '@commerce/utils/types'; +import useSignup, { UseSignup } from '@commerce/auth/use-signup'; +import type { SignupHook } from '@commerce/types/signup'; +import { ValidationError } from '@commerce/utils/errors'; +import type { IAccount } from '@spree/storefront-api-v2-sdk/types/interfaces/Account'; +import type { AuthTokenAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Authentication'; +import useCustomer from '../customer/use-customer'; +import useCart from '../cart/use-cart'; +import useWishlist from '../wishlist/use-wishlist'; +import login from '../utils/login'; +import { requireConfigValue } from '../isomorphic-config'; + +export default useSignup as UseSignup; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'account', + query: 'create' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useSignup fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const { email, password } = input; + + if (!email || !password) { + throw new ValidationError({ + message: 'Email and password need to be provided.' + }); + } + + // TODO: Replace any with specific type from Spree SDK + // once it's added to the SDK. + const createAccountParameters: any = { + user: { + email, + password, + // The stock NJC interface doesn't have a + // password confirmation field, so just copy password. + passwordConfirmation: password + } + }; + + // Create the user account. + await fetch>({ + variables: { + methodPath: 'account.create', + arguments: [createAccountParameters] + } + }); + + const getTokenParameters: AuthTokenAttr = { + username: email, + password + }; + + // Login immediately after the account is created. + if (requireConfigValue('loginAfterSignup')) { + await login(fetch, getTokenParameters, true); + } + + return null; + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType['useHook']> = () => { + const customer = useCustomer(); + const cart = useCart(); + const wishlist = useWishlist(); + + return useCallback( + async (input) => { + const data = await fetch({ input }); + + await customer.revalidate(); + await cart.revalidate(); + await wishlist.revalidate(); + + return data; + }, + [customer, cart, wishlist] + ); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/cart/index.ts b/lib/spree/cart/index.ts new file mode 100644 index 000000000..ce8557363 --- /dev/null +++ b/lib/spree/cart/index.ts @@ -0,0 +1,4 @@ +export { default as useCart } from './use-cart'; +export { default as useAddItem } from './use-add-item'; +export { default as useRemoveItem } from './use-remove-item'; +export { default as useUpdateItem } from './use-update-item'; diff --git a/lib/spree/cart/use-add-item.tsx b/lib/spree/cart/use-add-item.tsx new file mode 100644 index 000000000..80c4108ec --- /dev/null +++ b/lib/spree/cart/use-add-item.tsx @@ -0,0 +1,109 @@ +import useAddItem from '@commerce/cart/use-add-item'; +import type { UseAddItem } from '@commerce/cart/use-add-item'; +import type { MutationHook } from '@commerce/utils/types'; +import { useCallback } from 'react'; +import useCart from './use-cart'; +import type { AddItemHook } from '@commerce/types/cart'; +import normalizeCart from '../utils/normalizations/normalize-cart'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import type { AddItem } from '@spree/storefront-api-v2-sdk/types/interfaces/endpoints/CartClass'; +import { setCartToken } from '../utils/tokens/cart-token'; +import ensureIToken from '../utils/tokens/ensure-itoken'; +import createEmptyCart from '../utils/create-empty-cart'; +import { FetcherError } from '@commerce/utils/errors'; +import isLoggedIn from '../utils/tokens/is-logged-in'; + +export default useAddItem as UseAddItem; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'cart', + query: 'addItem' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useAddItem fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const { quantity, productId, variantId } = input; + + const safeQuantity = quantity ?? 1; + + let token: IToken | undefined = ensureIToken(); + + const addItemParameters: AddItem = { + variant_id: variantId, + quantity: safeQuantity, + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types' + ].join(',') + }; + + if (!token) { + const { data: spreeCartCreateSuccessResponse } = await createEmptyCart(fetch); + + setCartToken(spreeCartCreateSuccessResponse.data.attributes.token); + token = ensureIToken(); + } + + try { + const { data: spreeSuccessResponse } = await fetch>({ + variables: { + methodPath: 'cart.addItem', + arguments: [token, addItemParameters] + } + }); + + return normalizeCart(spreeSuccessResponse, spreeSuccessResponse.data); + } catch (addItemError) { + if (addItemError instanceof FetcherError && addItemError.status === 404) { + const { data: spreeRetroactiveCartCreateSuccessResponse } = await createEmptyCart(fetch); + + if (!isLoggedIn()) { + setCartToken(spreeRetroactiveCartCreateSuccessResponse.data.attributes.token); + } + + // Return an empty cart. The user has to add the item again. + // This is going to be a rare situation. + + return normalizeCart( + spreeRetroactiveCartCreateSuccessResponse, + spreeRetroactiveCartCreateSuccessResponse.data + ); + } + + throw addItemError; + } + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType['useHook']> = () => { + const { mutate } = useCart(); + + return useCallback( + async (input) => { + const data = await fetch({ input }); + + await mutate(data, false); + + return data; + }, + [mutate] + ); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/cart/use-cart.tsx b/lib/spree/cart/use-cart.tsx new file mode 100644 index 000000000..ed0d51061 --- /dev/null +++ b/lib/spree/cart/use-cart.tsx @@ -0,0 +1,108 @@ +import { useMemo } from 'react'; +import type { SWRHook } from '@commerce/utils/types'; +import useCart from '@commerce/cart/use-cart'; +import type { UseCart } from '@commerce/cart/use-cart'; +import type { GetCartHook } from '@commerce/types/cart'; +import normalizeCart from '../utils/normalizations/normalize-cart'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import { FetcherError } from '@commerce/utils/errors'; +import { setCartToken } from '../utils/tokens/cart-token'; +import ensureIToken from '../utils/tokens/ensure-itoken'; +import isLoggedIn from '../utils/tokens/is-logged-in'; +import createEmptyCart from '../utils/create-empty-cart'; +import { requireConfigValue } from '../isomorphic-config'; + +const imagesSize = requireConfigValue('imagesSize') as string; +const imagesQuality = requireConfigValue('imagesQuality') as number; + +export default useCart as UseCart; + +// This handler avoids calling /api/cart. +// There doesn't seem to be a good reason to call it. +// So far, only @framework/bigcommerce uses it. +export const handler: SWRHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'cart', + query: 'show' + }, + async fetcher({ input, options, fetch }) { + console.info('useCart fetcher called. Configuration: ', 'input: ', input, 'options: ', options); + + let spreeCartResponse: IOrder | null; + + const token: IToken | undefined = ensureIToken(); + + if (!token) { + spreeCartResponse = null; + } else { + try { + const { data: spreeCartShowSuccessResponse } = await fetch>({ + variables: { + methodPath: 'cart.show', + arguments: [ + token, + { + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types' + ].join(','), + image_transformation: { + quality: imagesQuality, + size: imagesSize + } + } + ] + } + }); + + spreeCartResponse = spreeCartShowSuccessResponse; + } catch (fetchCartError) { + if (!(fetchCartError instanceof FetcherError) || fetchCartError.status !== 404) { + throw fetchCartError; + } + + spreeCartResponse = null; + } + } + + if (!spreeCartResponse || spreeCartResponse?.data.attributes.completed_at) { + const { data: spreeCartCreateSuccessResponse } = await createEmptyCart(fetch); + + spreeCartResponse = spreeCartCreateSuccessResponse; + + if (!isLoggedIn()) { + setCartToken(spreeCartResponse.data.attributes.token); + } + } + + return normalizeCart(spreeCartResponse, spreeCartResponse.data); + }, + useHook: ({ useData }) => { + const useWrappedHook: ReturnType['useHook']> = (input) => { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions } + }); + + return useMemo(() => { + return Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) === 0; + }, + enumerable: true + } + }); + }, [response]); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/cart/use-remove-item.tsx b/lib/spree/cart/use-remove-item.tsx new file mode 100644 index 000000000..bdc8fc5ca --- /dev/null +++ b/lib/spree/cart/use-remove-item.tsx @@ -0,0 +1,107 @@ +import type { MutationHook } from '@commerce/utils/types'; +import useRemoveItem from '@commerce/cart/use-remove-item'; +import type { UseRemoveItem } from '@commerce/cart/use-remove-item'; +import type { RemoveItemHook } from '@commerce/types/cart'; +import useCart from './use-cart'; +import { useCallback } from 'react'; +import normalizeCart from '../utils/normalizations/normalize-cart'; +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { IQuery } from '@spree/storefront-api-v2-sdk/types/interfaces/Query'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import ensureIToken from '../utils/tokens/ensure-itoken'; +import createEmptyCart from '../utils/create-empty-cart'; +import { setCartToken } from '../utils/tokens/cart-token'; +import { FetcherError } from '@commerce/utils/errors'; +import isLoggedIn from '../utils/tokens/is-logged-in'; + +export default useRemoveItem as UseRemoveItem; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'cart', + query: 'removeItem' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useRemoveItem fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const { itemId: lineItemId } = input; + + let token: IToken | undefined = ensureIToken(); + + if (!token) { + const { data: spreeCartCreateSuccessResponse } = await createEmptyCart(fetch); + + setCartToken(spreeCartCreateSuccessResponse.data.attributes.token); + token = ensureIToken(); + } + + const removeItemParameters: IQuery = { + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types' + ].join(',') + }; + + try { + const { data: spreeSuccessResponse } = await fetch>({ + variables: { + methodPath: 'cart.removeItem', + arguments: [token, lineItemId, removeItemParameters] + } + }); + + return normalizeCart(spreeSuccessResponse, spreeSuccessResponse.data); + } catch (removeItemError) { + if (removeItemError instanceof FetcherError && removeItemError.status === 404) { + const { data: spreeRetroactiveCartCreateSuccessResponse } = await createEmptyCart(fetch); + + if (!isLoggedIn()) { + setCartToken(spreeRetroactiveCartCreateSuccessResponse.data.attributes.token); + } + + // Return an empty cart. This is going to be a rare situation. + + return normalizeCart( + spreeRetroactiveCartCreateSuccessResponse, + spreeRetroactiveCartCreateSuccessResponse.data + ); + } + + throw removeItemError; + } + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType['useHook']> = () => { + const { mutate } = useCart(); + + return useCallback( + async (input) => { + const data = await fetch({ input: { itemId: input.id } }); + + // Upon calling cart.removeItem, Spree returns the old version of the cart, + // with the already removed line item. Invalidate the useCart mutation + // to fetch the cart again. + await mutate(data, true); + + return data; + }, + [mutate] + ); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/cart/use-update-item.tsx b/lib/spree/cart/use-update-item.tsx new file mode 100644 index 000000000..b53c762ce --- /dev/null +++ b/lib/spree/cart/use-update-item.tsx @@ -0,0 +1,134 @@ +import type { MutationHook } from '@commerce/utils/types'; +import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item'; +import type { UpdateItemHook } from '@commerce/types/cart'; +import useCart from './use-cart'; +import { useMemo } from 'react'; +import { FetcherError, ValidationError } from '@commerce/utils/errors'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import type { SetQuantity } from '@spree/storefront-api-v2-sdk/types/interfaces/endpoints/CartClass'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order'; +import normalizeCart from '../utils/normalizations/normalize-cart'; +import debounce from 'lodash.debounce'; +import ensureIToken from '../utils/tokens/ensure-itoken'; +import createEmptyCart from '../utils/create-empty-cart'; +import { setCartToken } from '../utils/tokens/cart-token'; +import isLoggedIn from '../utils/tokens/is-logged-in'; + +export default useUpdateItem as UseUpdateItem; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'cart', + query: 'setQuantity' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useRemoveItem fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const { itemId, item } = input; + + if (!item.quantity) { + throw new ValidationError({ + message: 'Line item quantity needs to be provided.' + }); + } + + let token: IToken | undefined = ensureIToken(); + + if (!token) { + const { data: spreeCartCreateSuccessResponse } = await createEmptyCart(fetch); + + setCartToken(spreeCartCreateSuccessResponse.data.attributes.token); + token = ensureIToken(); + } + + try { + const setQuantityParameters: SetQuantity = { + line_item_id: itemId, + quantity: item.quantity, + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types' + ].join(',') + }; + + const { data: spreeSuccessResponse } = await fetch>({ + variables: { + methodPath: 'cart.setQuantity', + arguments: [token, setQuantityParameters] + } + }); + + return normalizeCart(spreeSuccessResponse, spreeSuccessResponse.data); + } catch (updateItemError) { + if (updateItemError instanceof FetcherError && updateItemError.status === 404) { + const { data: spreeRetroactiveCartCreateSuccessResponse } = await createEmptyCart(fetch); + + if (!isLoggedIn()) { + setCartToken(spreeRetroactiveCartCreateSuccessResponse.data.attributes.token); + } + + // Return an empty cart. The user has to update the item again. + // This is going to be a rare situation. + + return normalizeCart( + spreeRetroactiveCartCreateSuccessResponse, + spreeRetroactiveCartCreateSuccessResponse.data + ); + } + + throw updateItemError; + } + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType['useHook']> = (context) => { + const { mutate } = useCart(); + + return useMemo( + () => + debounce(async (input: UpdateItemHook['actionInput']) => { + const itemId = context?.item?.id; + const productId = input.productId ?? context?.item?.productId; + const variantId = input.variantId ?? context?.item?.variantId; + const quantity = input.quantity; + + if (!itemId || !productId || !variantId) { + throw new ValidationError({ + message: 'Invalid input used for this operation' + }); + } + + const data = await fetch({ + input: { + item: { + productId, + variantId, + quantity + }, + itemId + } + }); + + await mutate(data, false); + + return data; + }, context?.wait ?? 500), + [mutate, context] + ); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/checkout/use-checkout.tsx b/lib/spree/checkout/use-checkout.tsx new file mode 100644 index 000000000..738fddac3 --- /dev/null +++ b/lib/spree/checkout/use-checkout.tsx @@ -0,0 +1,17 @@ +import { SWRHook } from '@commerce/utils/types'; +import useCheckout, { UseCheckout } from '@commerce/checkout/use-checkout'; + +export default useCheckout as UseCheckout; + +export const handler: SWRHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + // TODO: Revise url and query + url: 'checkout', + query: 'show' + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ useData }) => + async (input) => ({}) +}; diff --git a/lib/spree/commerce.config.json b/lib/spree/commerce.config.json new file mode 100644 index 000000000..6f8399fb5 --- /dev/null +++ b/lib/spree/commerce.config.json @@ -0,0 +1,10 @@ +{ + "provider": "spree", + "features": { + "wishlist": true, + "cart": true, + "search": true, + "customerAuth": true, + "customCheckout": false + } +} diff --git a/lib/spree/customer/address/use-add-item.tsx b/lib/spree/customer/address/use-add-item.tsx new file mode 100644 index 000000000..06bda6a27 --- /dev/null +++ b/lib/spree/customer/address/use-add-item.tsx @@ -0,0 +1,18 @@ +import useAddItem from '@commerce/customer/address/use-add-item'; +import type { UseAddItem } from '@commerce/customer/address/use-add-item'; +import type { MutationHook } from '@commerce/utils/types'; + +export default useAddItem as UseAddItem; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'account', + query: 'createAddress' + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ fetch }) => + () => + async () => ({}) +}; diff --git a/lib/spree/customer/card/use-add-item.tsx b/lib/spree/customer/card/use-add-item.tsx new file mode 100644 index 000000000..1b05a4bed --- /dev/null +++ b/lib/spree/customer/card/use-add-item.tsx @@ -0,0 +1,19 @@ +import useAddItem from '@commerce/customer/address/use-add-item'; +import type { UseAddItem } from '@commerce/customer/address/use-add-item'; +import type { MutationHook } from '@commerce/utils/types'; + +export default useAddItem as UseAddItem; + +export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + // TODO: Revise url and query + url: 'checkout', + query: 'addPayment' + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ fetch }) => + () => + async () => ({}) +}; diff --git a/lib/spree/customer/index.ts b/lib/spree/customer/index.ts new file mode 100644 index 000000000..8410d6ad4 --- /dev/null +++ b/lib/spree/customer/index.ts @@ -0,0 +1 @@ +export { default as useCustomer } from './use-customer'; diff --git a/lib/spree/customer/use-customer.tsx b/lib/spree/customer/use-customer.tsx new file mode 100644 index 000000000..d9fe6028e --- /dev/null +++ b/lib/spree/customer/use-customer.tsx @@ -0,0 +1,75 @@ +import type { SWRHook } from '@commerce/utils/types'; +import useCustomer from '@commerce/customer/use-customer'; +import type { UseCustomer } from '@commerce/customer/use-customer'; +import type { CustomerHook } from '@commerce/types/customer'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { IAccount } from '@spree/storefront-api-v2-sdk/types/interfaces/Account'; +import { FetcherError } from '@commerce/utils/errors'; +import normalizeUser from '../utils/normalizations/normalize-user'; +import isLoggedIn from '../utils/tokens/is-logged-in'; +import ensureIToken from '../utils/tokens/ensure-itoken'; + +export default useCustomer as UseCustomer; + +export const handler: SWRHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'account', + query: 'get' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useCustomer fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + if (!isLoggedIn()) { + return null; + } + + const token: IToken | undefined = ensureIToken(); + + if (!token) { + return null; + } + + try { + const { data: spreeAccountInfoSuccessResponse } = await fetch>( + { + variables: { + methodPath: 'account.accountInfo', + arguments: [token] + } + } + ); + + const spreeUser = spreeAccountInfoSuccessResponse.data; + + const normalizedUser = normalizeUser(spreeAccountInfoSuccessResponse, spreeUser); + + return normalizedUser; + } catch (fetchUserError) { + if (!(fetchUserError instanceof FetcherError) || fetchUserError.status !== 404) { + throw fetchUserError; + } + + return null; + } + }, + useHook: ({ useData }) => { + const useWrappedHook: ReturnType['useHook']> = (input) => { + return useData({ + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions + } + }); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/errors/AccessTokenError.ts b/lib/spree/errors/AccessTokenError.ts new file mode 100644 index 000000000..4c79c0be8 --- /dev/null +++ b/lib/spree/errors/AccessTokenError.ts @@ -0,0 +1 @@ +export default class AccessTokenError extends Error {} diff --git a/lib/spree/errors/MisconfigurationError.ts b/lib/spree/errors/MisconfigurationError.ts new file mode 100644 index 000000000..0717ae404 --- /dev/null +++ b/lib/spree/errors/MisconfigurationError.ts @@ -0,0 +1 @@ +export default class MisconfigurationError extends Error {} diff --git a/lib/spree/errors/MissingConfigurationValueError.ts b/lib/spree/errors/MissingConfigurationValueError.ts new file mode 100644 index 000000000..02b497bf1 --- /dev/null +++ b/lib/spree/errors/MissingConfigurationValueError.ts @@ -0,0 +1 @@ +export default class MissingConfigurationValueError extends Error {} diff --git a/lib/spree/errors/MissingLineItemVariantError.ts b/lib/spree/errors/MissingLineItemVariantError.ts new file mode 100644 index 000000000..d9bee0803 --- /dev/null +++ b/lib/spree/errors/MissingLineItemVariantError.ts @@ -0,0 +1 @@ +export default class MissingLineItemVariantError extends Error {} diff --git a/lib/spree/errors/MissingOptionValueError.ts b/lib/spree/errors/MissingOptionValueError.ts new file mode 100644 index 000000000..04457ac5e --- /dev/null +++ b/lib/spree/errors/MissingOptionValueError.ts @@ -0,0 +1 @@ +export default class MissingOptionValueError extends Error {} diff --git a/lib/spree/errors/MissingPrimaryVariantError.ts b/lib/spree/errors/MissingPrimaryVariantError.ts new file mode 100644 index 000000000..f9af41b03 --- /dev/null +++ b/lib/spree/errors/MissingPrimaryVariantError.ts @@ -0,0 +1 @@ +export default class MissingPrimaryVariantError extends Error {} diff --git a/lib/spree/errors/MissingProductError.ts b/lib/spree/errors/MissingProductError.ts new file mode 100644 index 000000000..3098be689 --- /dev/null +++ b/lib/spree/errors/MissingProductError.ts @@ -0,0 +1 @@ +export default class MissingProductError extends Error {} diff --git a/lib/spree/errors/MissingSlugVariableError.ts b/lib/spree/errors/MissingSlugVariableError.ts new file mode 100644 index 000000000..09b9d2e20 --- /dev/null +++ b/lib/spree/errors/MissingSlugVariableError.ts @@ -0,0 +1 @@ +export default class MissingSlugVariableError extends Error {} diff --git a/lib/spree/errors/MissingVariantError.ts b/lib/spree/errors/MissingVariantError.ts new file mode 100644 index 000000000..5ed9e0ed2 --- /dev/null +++ b/lib/spree/errors/MissingVariantError.ts @@ -0,0 +1 @@ +export default class MissingVariantError extends Error {} diff --git a/lib/spree/errors/RefreshTokenError.ts b/lib/spree/errors/RefreshTokenError.ts new file mode 100644 index 000000000..a79365bbb --- /dev/null +++ b/lib/spree/errors/RefreshTokenError.ts @@ -0,0 +1 @@ +export default class RefreshTokenError extends Error {} diff --git a/lib/spree/errors/SpreeResponseContentError.ts b/lib/spree/errors/SpreeResponseContentError.ts new file mode 100644 index 000000000..19c10cf2e --- /dev/null +++ b/lib/spree/errors/SpreeResponseContentError.ts @@ -0,0 +1 @@ +export default class SpreeResponseContentError extends Error {} diff --git a/lib/spree/errors/SpreeSdkMethodFromEndpointPathError.ts b/lib/spree/errors/SpreeSdkMethodFromEndpointPathError.ts new file mode 100644 index 000000000..bf15aada0 --- /dev/null +++ b/lib/spree/errors/SpreeSdkMethodFromEndpointPathError.ts @@ -0,0 +1 @@ +export default class SpreeSdkMethodFromEndpointPathError extends Error {} diff --git a/lib/spree/errors/TokensNotRejectedError.ts b/lib/spree/errors/TokensNotRejectedError.ts new file mode 100644 index 000000000..245f66414 --- /dev/null +++ b/lib/spree/errors/TokensNotRejectedError.ts @@ -0,0 +1 @@ +export default class TokensNotRejectedError extends Error {} diff --git a/lib/spree/errors/UserTokenResponseParseError.ts b/lib/spree/errors/UserTokenResponseParseError.ts new file mode 100644 index 000000000..9631971c1 --- /dev/null +++ b/lib/spree/errors/UserTokenResponseParseError.ts @@ -0,0 +1 @@ +export default class UserTokenResponseParseError extends Error {} diff --git a/lib/spree/index.tsx b/lib/spree/index.tsx new file mode 100644 index 000000000..dc6bc1ccb --- /dev/null +++ b/lib/spree/index.tsx @@ -0,0 +1,9 @@ +const createAxiosFetcher = require('@spree/axios-fetcher/dist/server/index').default; +import { makeClient } from '@spree/storefront-api-v2-sdk/dist/client'; + +const spreeClient = makeClient({ + host: 'http://localhost:3000', + createFetcher: createAxiosFetcher +}); + +export default spreeClient; diff --git a/lib/spree/next.config.js b/lib/spree/next.config.js new file mode 100644 index 000000000..90e720888 --- /dev/null +++ b/lib/spree/next.config.js @@ -0,0 +1,16 @@ +const commerce = require('./commerce.config.json'); + +module.exports = { + commerce, + images: { + domains: [process.env.NEXT_PUBLIC_SPREE_ALLOWED_IMAGE_DOMAIN] + }, + rewrites() { + return [ + { + source: '/checkout', + destination: '/api/checkout' + } + ]; + } +}; diff --git a/lib/spree/product/index.ts b/lib/spree/product/index.ts new file mode 100644 index 000000000..6c5a2d91d --- /dev/null +++ b/lib/spree/product/index.ts @@ -0,0 +1,2 @@ +export { default as usePrice } from './use-price'; +export { default as useSearch } from './use-search'; diff --git a/lib/spree/product/use-price.tsx b/lib/spree/product/use-price.tsx new file mode 100644 index 000000000..63b587cb0 --- /dev/null +++ b/lib/spree/product/use-price.tsx @@ -0,0 +1,2 @@ +export * from '@commerce/product/use-price'; +export { default } from '@commerce/product/use-price'; diff --git a/lib/spree/product/use-search.tsx b/lib/spree/product/use-search.tsx new file mode 100644 index 000000000..e1ca4d887 --- /dev/null +++ b/lib/spree/product/use-search.tsx @@ -0,0 +1,96 @@ +import type { SWRHook } from '@commerce/utils/types'; +import useSearch from '@commerce/product/use-search'; +import type { Product, SearchProductsHook } from '@commerce/types/product'; +import type { UseSearch } from '@commerce/product/use-search'; +import normalizeProduct from '../utils/normalizations/normalize-product'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import { IProducts } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'; +import { requireConfigValue } from '../isomorphic-config'; + +const imagesSize = requireConfigValue('imagesSize') as string; +const imagesQuality = requireConfigValue('imagesQuality') as number; + +const nextToSpreeSortMap: { [key: string]: string } = { + 'trending-desc': 'available_on', + 'latest-desc': 'updated_at', + 'price-asc': 'price', + 'price-desc': '-price' +}; + +export const handler: SWRHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'products', + query: 'list' + }, + async fetcher({ input, options, fetch }) { + // This method is only needed if the options need to be modified before calling the generic fetcher (created in createFetcher). + + console.info( + 'useSearch fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const taxons = [input.categoryId, input.brandId].filter(Boolean); + + const filter = { + filter: { + ...(taxons.length > 0 ? { taxons: taxons.join(',') } : {}), + ...(input.search ? { name: input.search } : {}) + } + }; + + const sort = input.sort ? { sort: nextToSpreeSortMap[input.sort] } : {}; + + const { data: spreeSuccessResponse } = await fetch>({ + variables: { + methodPath: 'products.list', + arguments: [ + {}, + { + include: 'primary_variant,variants,images,option_types,variants.option_values', + per_page: 50, + ...filter, + ...sort, + image_transformation: { + quality: imagesQuality, + size: imagesSize + } + } + ] + } + }); + + const normalizedProducts: Product[] = spreeSuccessResponse.data.map((spreeProduct) => + normalizeProduct(spreeSuccessResponse, spreeProduct) + ); + + const found = spreeSuccessResponse.data.length > 0; + + return { products: normalizedProducts, found }; + }, + useHook: ({ useData }) => { + const useWrappedHook: ReturnType['useHook']> = (input = {}) => { + return useData({ + input: [ + ['search', input.search], + ['categoryId', input.categoryId], + ['brandId', input.brandId], + ['sort', input.sort] + ], + swrOptions: { + revalidateOnFocus: false, + // revalidateOnFocus: false means do not fetch products again when website is refocused in the web browser. + ...input.swrOptions + } + }); + }; + + return useWrappedHook; + } +}; + +export default useSearch as UseSearch; diff --git a/lib/spree/provider.ts b/lib/spree/provider.ts new file mode 100644 index 000000000..91ed5f6ea --- /dev/null +++ b/lib/spree/provider.ts @@ -0,0 +1,35 @@ +import fetcher from './fetcher'; +import { handler as useCart } from './cart/use-cart'; +import { handler as useAddItem } from './cart/use-add-item'; +import { handler as useUpdateItem } from './cart/use-update-item'; +import { handler as useRemoveItem } from './cart/use-remove-item'; +import { handler as useCustomer } from './customer/use-customer'; +import { handler as useSearch } from './product/use-search'; +import { handler as useLogin } from './auth/use-login'; +import { handler as useLogout } from './auth/use-logout'; +import { handler as useSignup } from './auth/use-signup'; +import { handler as useCheckout } from './checkout/use-checkout'; +import { handler as useWishlist } from './wishlist/use-wishlist'; +import { handler as useWishlistAddItem } from './wishlist/use-add-item'; +import { handler as useWishlistRemoveItem } from './wishlist/use-remove-item'; +import { requireConfigValue } from './isomorphic-config'; + +const spreeProvider = { + locale: requireConfigValue('defaultLocale') as string, + cartCookie: requireConfigValue('cartCookieName') as string, + fetcher, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, + customer: { useCustomer }, + products: { useSearch }, + auth: { useLogin, useLogout, useSignup }, + checkout: { useCheckout }, + wishlist: { + useWishlist, + useAddItem: useWishlistAddItem, + useRemoveItem: useWishlistRemoveItem + } +}; + +export { spreeProvider }; + +export type SpreeProvider = typeof spreeProvider; diff --git a/lib/spree/types/index.ts b/lib/spree/types/index.ts new file mode 100644 index 000000000..9ea74c282 --- /dev/null +++ b/lib/spree/types/index.ts @@ -0,0 +1,166 @@ +import type { fetchResponseKey } from '../utils/create-customized-fetch-fetcher'; +import type { + JsonApiDocument, + JsonApiListResponse, + JsonApiSingleResponse +} from '@spree/storefront-api-v2-sdk/types/interfaces/JsonApi'; +import type { ResultResponse } from '@spree/storefront-api-v2-sdk/types/interfaces/ResultResponse'; +import type { Response } from '@vercel/fetch'; +import type { ProductOption, Product } from '@commerce/types/product'; +import type { + AddItemHook, + RemoveItemHook, + WishlistItemBody, + WishlistTypes +} from '@commerce/types/wishlist'; + +export type UnknownObjectValues = Record; + +export type NonUndefined = T extends undefined ? never : T; + +export type ValueOf = T[keyof T]; + +export type SpreeSdkResponse = JsonApiSingleResponse | JsonApiListResponse; + +export type SpreeSdkResponseWithRawResponse = SpreeSdkResponse & { + [fetchResponseKey]: Response; +}; + +export type SpreeSdkResultResponseSuccessType = SpreeSdkResponseWithRawResponse; + +export type SpreeSdkMethodReturnType< + ResultResponseSuccessType extends + SpreeSdkResultResponseSuccessType = SpreeSdkResultResponseSuccessType +> = Promise>; + +export type SpreeSdkMethod< + ResultResponseSuccessType extends + SpreeSdkResultResponseSuccessType = SpreeSdkResultResponseSuccessType +> = (...args: any[]) => SpreeSdkMethodReturnType; + +export type SpreeSdkVariables = { + methodPath: string; + arguments: any[]; +}; + +export type FetcherVariables = SpreeSdkVariables & { + refreshExpiredAccessToken: boolean; + replayUnauthorizedRequest: boolean; +}; + +export interface ImageStyle { + url: string; + width: string; + height: string; + size: string; +} + +export interface SpreeProductImage extends JsonApiDocument { + attributes: { + position: number; + alt: string; + original_url: string; + transformed_url: string | null; + styles: ImageStyle[]; + }; +} + +export interface OptionTypeAttr extends JsonApiDocument { + attributes: { + name: string; + presentation: string; + position: number; + created_at: string; + updated_at: string; + filterable: boolean; + }; +} + +export interface LineItemAttr extends JsonApiDocument { + attributes: { + name: string; + quantity: number; + slug: string; + options_text: string; + price: string; + currency: string; + display_price: string; + total: string; + display_total: string; + adjustment_total: string; + display_adjustment_total: string; + additional_tax_total: string; + display_additional_tax_total: string; + discounted_amount: string; + display_discounted_amount: string; + pre_tax_amount: string; + display_pre_tax_amount: string; + promo_total: string; + display_promo_total: string; + included_tax_total: string; + display_inluded_tax_total: string; + }; +} + +export interface VariantAttr extends JsonApiDocument { + attributes: { + sku: string; + price: string; + currency: string; + display_price: string; + weight: string; + height: string; + width: string; + depth: string; + is_master: boolean; + options_text: string; + purchasable: boolean; + in_stock: boolean; + backorderable: boolean; + }; +} + +export interface ProductSlugAttr extends JsonApiDocument { + attributes: { + slug: string; + }; +} +export interface IProductsSlugs extends JsonApiListResponse { + data: ProductSlugAttr[]; +} + +export type ExpandedProductOption = ProductOption & { position: number }; + +export type UserOAuthTokens = { + refreshToken: string; + accessToken: string; +}; + +// TODO: ExplicitCommerceWishlist is a temporary type +// derived from tsx views. It will be removed once +// Wishlist in @commerce/types/wishlist is updated +// to a more specific type than `any`. +export type ExplicitCommerceWishlist = { + id: string; + token: string; + items: { + id: string; + product_id: number; + variant_id: number; + product: Product; + }[]; +}; + +export type ExplicitWishlistAddItemHook = AddItemHook< + WishlistTypes & { + wishlist: ExplicitCommerceWishlist; + itemBody: WishlistItemBody & { + wishlistToken?: string; + }; + } +>; + +export type ExplicitWishlistRemoveItemHook = RemoveItemHook & { + fetcherInput: { wishlistToken?: string }; + body: { wishlistToken?: string }; +}; diff --git a/lib/spree/utils/convert-spree-error-to-graph-ql-error.ts b/lib/spree/utils/convert-spree-error-to-graph-ql-error.ts new file mode 100644 index 000000000..4103d1c63 --- /dev/null +++ b/lib/spree/utils/convert-spree-error-to-graph-ql-error.ts @@ -0,0 +1,50 @@ +import { FetcherError } from '@commerce/utils/errors'; +import { errors } from '@spree/storefront-api-v2-sdk'; + +const convertSpreeErrorToGraphQlError = (error: errors.SpreeError): FetcherError => { + if (error instanceof errors.ExpandedSpreeError) { + // Assuming error.errors[key] is a list of strings. + + if ('base' in error.errors) { + const baseErrorMessage = error.errors.base as unknown as string; + + return new FetcherError({ + status: error.serverResponse.status, + message: baseErrorMessage + }); + } + + const fetcherErrors = Object.keys(error.errors).map((sdkErrorKey) => { + const errors = error.errors[sdkErrorKey] as string[]; + + // Naively assume sdkErrorKey is a label. Capitalize it for a better + // out-of-the-box experience. + const capitalizedSdkErrorKey = sdkErrorKey.replace(/^\w/, (firstChar) => + firstChar.toUpperCase() + ); + + return { + message: `${capitalizedSdkErrorKey} ${errors.join(', ')}` + }; + }); + + return new FetcherError({ + status: error.serverResponse.status, + errors: fetcherErrors + }); + } + + if (error instanceof errors.BasicSpreeError) { + return new FetcherError({ + status: error.serverResponse.status, + message: error.summary + }); + } + + return new FetcherError({ + status: error.serverResponse.status, + message: error.message + }); +}; + +export default convertSpreeErrorToGraphQlError; diff --git a/lib/spree/utils/create-customized-fetch-fetcher.ts b/lib/spree/utils/create-customized-fetch-fetcher.ts new file mode 100644 index 000000000..f49fdbe83 --- /dev/null +++ b/lib/spree/utils/create-customized-fetch-fetcher.ts @@ -0,0 +1,96 @@ +import { errors, request as spreeSdkRequestHelpers } from '@spree/storefront-api-v2-sdk'; +import type { CreateCustomizedFetchFetcher } from '@spree/storefront-api-v2-sdk/types/interfaces/CreateCustomizedFetchFetcher'; +import isJsonContentType from './is-json-content-type'; + +export const fetchResponseKey = Symbol('fetch-response-key'); + +const createCustomizedFetchFetcher: CreateCustomizedFetchFetcher = (fetcherOptions) => { + const { FetchError } = errors; + const sharedHeaders = { + 'Content-Type': 'application/json' + }; + + const { host, fetch, requestConstructor } = fetcherOptions; + + return { + fetch: async (fetchOptions) => { + // This fetcher always returns request equal null, + // because @vercel/fetch doesn't accept a Request object as argument + // and it's not used by NJC anyway. + try { + const { url, params, method, headers, responseParsing } = fetchOptions; + const absoluteUrl = new URL(url, host); + let payload; + + switch (method.toUpperCase()) { + case 'PUT': + case 'POST': + case 'DELETE': + case 'PATCH': + payload = { body: JSON.stringify(params) }; + break; + default: + payload = null; + absoluteUrl.search = spreeSdkRequestHelpers.objectToQuerystring(params); + } + + const request: Request = new requestConstructor(absoluteUrl.toString(), { + method: method.toUpperCase(), + headers: { ...sharedHeaders, ...headers }, + ...payload + }); + + try { + const response: Response = await fetch(request); + const responseContentType = response.headers.get('content-type'); + let data; + + if (responseParsing === 'automatic') { + if (responseContentType && isJsonContentType(responseContentType)) { + data = await response.json(); + } else { + data = await response.text(); + } + } else if (responseParsing === 'text') { + data = await response.text(); + } else if (responseParsing === 'json') { + data = await response.json(); + } else if (responseParsing === 'stream') { + data = await response.body; + } + + if (!response.ok) { + // Use the "traditional" approach and reject non 2xx responses. + throw new FetchError(response, request, data); + } + + data[fetchResponseKey] = response; + + return { data }; + } catch (error) { + if (error instanceof FetchError) { + throw error; + } + + if (!(error instanceof Error)) { + throw error; + } + + throw new FetchError(null, request, null, error.message); + } + } catch (error) { + if (error instanceof FetchError) { + throw error; + } + + if (!(error instanceof Error)) { + throw error; + } + + throw new FetchError(null, null, null, error.message); + } + } + }; +}; + +export default createCustomizedFetchFetcher; diff --git a/lib/spree/utils/create-empty-cart.ts b/lib/spree/utils/create-empty-cart.ts new file mode 100644 index 000000000..968346380 --- /dev/null +++ b/lib/spree/utils/create-empty-cart.ts @@ -0,0 +1,22 @@ +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { HookFetcherContext } from '@commerce/utils/types'; +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import ensureIToken from './tokens/ensure-itoken'; + +const createEmptyCart = ( + fetch: HookFetcherContext<{ + data: any; + }>['fetch'] +): Promise> => { + const token: IToken | undefined = ensureIToken(); + + return fetch>({ + variables: { + methodPath: 'cart.create', + arguments: [token] + } + }); +}; + +export default createEmptyCart; diff --git a/lib/spree/utils/create-get-absolute-image-url.ts b/lib/spree/utils/create-get-absolute-image-url.ts new file mode 100644 index 000000000..2a4955a94 --- /dev/null +++ b/lib/spree/utils/create-get-absolute-image-url.ts @@ -0,0 +1,22 @@ +import { SpreeProductImage } from '../types'; +import getImageUrl from './get-image-url'; + +const createGetAbsoluteImageUrl = + (host: string, useOriginalImageSize: boolean = true) => + (image: SpreeProductImage, minWidth: number, minHeight: number): string | null => { + let url; + + if (useOriginalImageSize) { + url = image.attributes.transformed_url || null; + } else { + url = getImageUrl(image, minWidth, minHeight); + } + + if (url === null) { + return null; + } + + return `${host}${url}`; + }; + +export default createGetAbsoluteImageUrl; diff --git a/lib/spree/utils/expand-options.ts b/lib/spree/utils/expand-options.ts new file mode 100644 index 000000000..5bc18591b --- /dev/null +++ b/lib/spree/utils/expand-options.ts @@ -0,0 +1,102 @@ +import type { ProductOptionValues } from '@commerce/types/product'; +import type { + JsonApiDocument, + JsonApiResponse +} from '@spree/storefront-api-v2-sdk/types/interfaces/JsonApi'; +import { jsonApi } from '@spree/storefront-api-v2-sdk'; +import type { RelationType } from '@spree/storefront-api-v2-sdk/types/interfaces/Relationships'; +import SpreeResponseContentError from '../errors/SpreeResponseContentError'; +import type { OptionTypeAttr, ExpandedProductOption } from '../types'; +import sortOptionsByPosition from '../utils/sort-option-types'; + +const isColorProductOption = (productOption: ExpandedProductOption) => { + return productOption.displayName === 'Color'; +}; + +const expandOptions = ( + spreeSuccessResponse: JsonApiResponse, + spreeOptionValue: JsonApiDocument, + accumulatedOptions: ExpandedProductOption[] +): ExpandedProductOption[] => { + const spreeOptionTypeIdentifier = spreeOptionValue.relationships.option_type.data as RelationType; + + const existingOptionIndex = accumulatedOptions.findIndex( + (option) => option.id == spreeOptionTypeIdentifier.id + ); + + let option: ExpandedProductOption; + + if (existingOptionIndex === -1) { + const spreeOptionType = jsonApi.findDocument( + spreeSuccessResponse, + spreeOptionTypeIdentifier + ); + + if (!spreeOptionType) { + throw new SpreeResponseContentError( + `Option type with id ${spreeOptionTypeIdentifier.id} not found.` + ); + } + + option = { + __typename: 'MultipleChoiceOption', + id: spreeOptionType.id, + displayName: spreeOptionType.attributes.presentation, + position: spreeOptionType.attributes.position, + values: [] + }; + } else { + const existingOption = accumulatedOptions[existingOptionIndex]; + + option = existingOption; + } + + let optionValue: ProductOptionValues; + + const label = isColorProductOption(option) + ? spreeOptionValue.attributes.name + : spreeOptionValue.attributes.presentation; + + const productOptionValueExists = option.values.some( + (optionValue: ProductOptionValues) => optionValue.label === label + ); + + if (!productOptionValueExists) { + if (isColorProductOption(option)) { + optionValue = { + label, + hexColors: [spreeOptionValue.attributes.presentation] + }; + } else { + optionValue = { + label + }; + } + + if (existingOptionIndex === -1) { + return [ + ...accumulatedOptions, + { + ...option, + values: [optionValue] + } + ]; + } + + const expandedOptionValues = [...option.values, optionValue]; + const expandedOptions = [...accumulatedOptions]; + + expandedOptions[existingOptionIndex] = { + ...option, + values: expandedOptionValues + }; + + const sortedOptions = sortOptionsByPosition(expandedOptions); + + return sortedOptions; + } + + return accumulatedOptions; +}; + +export default expandOptions; diff --git a/lib/spree/utils/force-isomorphic-config-values.ts b/lib/spree/utils/force-isomorphic-config-values.ts new file mode 100644 index 000000000..322d0d787 --- /dev/null +++ b/lib/spree/utils/force-isomorphic-config-values.ts @@ -0,0 +1,42 @@ +import type { NonUndefined, UnknownObjectValues } from '../types'; +import MisconfigurationError from '../errors/MisconfigurationError'; +import isServer from './is-server'; + +const generateMisconfigurationErrorMessage = (keys: Array) => + `${keys.join(', ')} must have a value before running the Framework.`; + +const forceIsomorphicConfigValues = < + X extends keyof T, + T extends UnknownObjectValues, + H extends Record> +>( + config: T, + requiredServerKeys: string[], + requiredPublicKeys: X[] +) => { + if (isServer) { + const missingServerConfigValues = requiredServerKeys.filter( + (requiredServerKey) => typeof config[requiredServerKey] === 'undefined' + ); + + if (missingServerConfigValues.length > 0) { + throw new MisconfigurationError( + generateMisconfigurationErrorMessage(missingServerConfigValues) + ); + } + } + + const missingPublicConfigValues = requiredPublicKeys.filter( + (requiredPublicKey) => typeof config[requiredPublicKey] === 'undefined' + ); + + if (missingPublicConfigValues.length > 0) { + throw new MisconfigurationError( + generateMisconfigurationErrorMessage(missingPublicConfigValues) + ); + } + + return config as T & H; +}; + +export default forceIsomorphicConfigValues; diff --git a/lib/spree/utils/get-image-url.ts b/lib/spree/utils/get-image-url.ts new file mode 100644 index 000000000..76f5a561c --- /dev/null +++ b/lib/spree/utils/get-image-url.ts @@ -0,0 +1,38 @@ +// Based on https://github.com/spark-solutions/spree2vuestorefront/blob/d88d85ae1bcd2ec99b13b81cd2e3c25600a0216e/src/utils/index.ts + +import type { ImageStyle, SpreeProductImage } from '../types'; + +const getImageUrl = (image: SpreeProductImage, minWidth: number, _: number): string | null => { + // every image is still resized in vue-storefront-api, no matter what getImageUrl returns + if (image) { + const { + attributes: { styles } + } = image; + const bestStyleIndex = styles.reduce( + (bSIndex: number | null, style: ImageStyle, styleIndex: number) => { + // assuming all images are the same dimensions, just scaled + if (bSIndex === null) { + return 0; + } + const bestStyle = styles[bSIndex]; + const widthDiff = +bestStyle.width - minWidth; + const minWidthDiff = +style.width - minWidth; + if (widthDiff < 0 && minWidthDiff > 0) { + return styleIndex; + } + if (widthDiff > 0 && minWidthDiff < 0) { + return bSIndex; + } + return Math.abs(widthDiff) < Math.abs(minWidthDiff) ? bSIndex : styleIndex; + }, + null + ); + + if (bestStyleIndex !== null) { + return styles[bestStyleIndex].url; + } + } + return null; +}; + +export default getImageUrl; diff --git a/lib/spree/utils/get-media-gallery.ts b/lib/spree/utils/get-media-gallery.ts new file mode 100644 index 000000000..91e2ddb7a --- /dev/null +++ b/lib/spree/utils/get-media-gallery.ts @@ -0,0 +1,21 @@ +// Based on https://github.com/spark-solutions/spree2vuestorefront/blob/d88d85ae1bcd2ec99b13b81cd2e3c25600a0216e/src/utils/index.ts + +import type { ProductImage } from '@commerce/types/product'; +import type { SpreeProductImage } from '../types'; + +const getMediaGallery = ( + images: SpreeProductImage[], + getImageUrl: (image: SpreeProductImage, minWidth: number, minHeight: number) => string | null +) => { + return images.reduce((productImages, _, imageIndex) => { + const url = getImageUrl(images[imageIndex], 800, 800); + + if (url) { + return [...productImages, { url }]; + } + + return productImages; + }, []); +}; + +export default getMediaGallery; diff --git a/lib/spree/utils/get-product-path.ts b/lib/spree/utils/get-product-path.ts new file mode 100644 index 000000000..12c27f52c --- /dev/null +++ b/lib/spree/utils/get-product-path.ts @@ -0,0 +1,7 @@ +import type { ProductSlugAttr } from '../types'; + +const getProductPath = (partialSpreeProduct: ProductSlugAttr) => { + return `/${partialSpreeProduct.attributes.slug}`; +}; + +export default getProductPath; diff --git a/lib/spree/utils/get-spree-sdk-method-from-endpoint-path.ts b/lib/spree/utils/get-spree-sdk-method-from-endpoint-path.ts new file mode 100644 index 000000000..98744cc21 --- /dev/null +++ b/lib/spree/utils/get-spree-sdk-method-from-endpoint-path.ts @@ -0,0 +1,50 @@ +import type { Client } from '@spree/storefront-api-v2-sdk'; +import SpreeSdkMethodFromEndpointPathError from '../errors/SpreeSdkMethodFromEndpointPathError'; +import type { SpreeSdkMethod, SpreeSdkResultResponseSuccessType } from '../types'; + +const getSpreeSdkMethodFromEndpointPath = < + ExactSpreeSdkClientType extends Client, + ResultResponseSuccessType extends + SpreeSdkResultResponseSuccessType = SpreeSdkResultResponseSuccessType +>( + client: ExactSpreeSdkClientType, + path: string +): SpreeSdkMethod => { + const pathParts = path.split('.'); + const reachedPath: string[] = []; + let node = >client; + + console.log(`Looking for ${path} in Spree Sdk.`); + + while (reachedPath.length < pathParts.length - 1) { + const checkedPathPart = pathParts[reachedPath.length]; + const checkedNode = node[checkedPathPart]; + + console.log(`Checking part ${checkedPathPart}.`); + + if (typeof checkedNode !== 'object') { + throw new SpreeSdkMethodFromEndpointPathError( + `Couldn't reach ${path}. Farthest path reached was: ${reachedPath.join('.')}.` + ); + } + + if (checkedNode === null) { + throw new SpreeSdkMethodFromEndpointPathError(`Path ${path} doesn't exist.`); + } + + node = >checkedNode; + reachedPath.push(checkedPathPart); + } + + const foundEndpointMethod = node[pathParts[reachedPath.length]]; + + if (reachedPath.length !== pathParts.length - 1 || typeof foundEndpointMethod !== 'function') { + throw new SpreeSdkMethodFromEndpointPathError( + `Couldn't reach ${path}. Farthest path reached was: ${reachedPath.join('.')}.` + ); + } + + return foundEndpointMethod.bind(node); +}; + +export default getSpreeSdkMethodFromEndpointPath; diff --git a/lib/spree/utils/handle-token-errors.ts b/lib/spree/utils/handle-token-errors.ts new file mode 100644 index 000000000..49f1b6935 --- /dev/null +++ b/lib/spree/utils/handle-token-errors.ts @@ -0,0 +1,14 @@ +import AccessTokenError from '../errors/AccessTokenError'; +import RefreshTokenError from '../errors/RefreshTokenError'; + +const handleTokenErrors = (error: unknown, action: () => void): boolean => { + if (error instanceof AccessTokenError || error instanceof RefreshTokenError) { + action(); + + return true; + } + + return false; +}; + +export default handleTokenErrors; diff --git a/lib/spree/utils/is-json-content-type.ts b/lib/spree/utils/is-json-content-type.ts new file mode 100644 index 000000000..020407c67 --- /dev/null +++ b/lib/spree/utils/is-json-content-type.ts @@ -0,0 +1,4 @@ +const isJsonContentType = (contentType: string): boolean => + contentType.includes('application/json') || contentType.includes('application/vnd.api+json'); + +export default isJsonContentType; diff --git a/lib/spree/utils/is-server.ts b/lib/spree/utils/is-server.ts new file mode 100644 index 000000000..246d8b700 --- /dev/null +++ b/lib/spree/utils/is-server.ts @@ -0,0 +1 @@ +export default typeof window === 'undefined'; diff --git a/lib/spree/utils/login.ts b/lib/spree/utils/login.ts new file mode 100644 index 000000000..8cce71b0a --- /dev/null +++ b/lib/spree/utils/login.ts @@ -0,0 +1,53 @@ +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { HookFetcherContext } from '@commerce/utils/types'; +import type { AuthTokenAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Authentication'; +import type { AssociateCart } from '@spree/storefront-api-v2-sdk/types/interfaces/endpoints/CartClass'; +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order'; +import type { IOAuthToken, IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import { getCartToken, removeCartToken } from './tokens/cart-token'; +import { setUserTokenResponse } from './tokens/user-token-response'; + +const login = async ( + fetch: HookFetcherContext<{ + data: any; + }>['fetch'], + getTokenParameters: AuthTokenAttr, + associateGuestCart: boolean +): Promise => { + const { data: spreeGetTokenSuccessResponse } = await fetch>({ + variables: { + methodPath: 'authentication.getToken', + arguments: [getTokenParameters] + } + }); + + setUserTokenResponse(spreeGetTokenSuccessResponse); + + if (associateGuestCart) { + const cartToken = getCartToken(); + + if (cartToken) { + // If the user had a cart as guest still use its contents + // after logging in. + const accessToken = spreeGetTokenSuccessResponse.access_token; + const token: IToken = { bearerToken: accessToken }; + + const associateGuestCartParameters: AssociateCart = { + guest_order_token: cartToken + }; + + await fetch>({ + variables: { + methodPath: 'cart.associateGuestCart', + arguments: [token, associateGuestCartParameters] + } + }); + + // We no longer need the guest cart token, so let's remove it. + } + } + + removeCartToken(); +}; + +export default login; diff --git a/lib/spree/utils/normalizations/normalize-cart.ts b/lib/spree/utils/normalizations/normalize-cart.ts new file mode 100644 index 000000000..95248edf6 --- /dev/null +++ b/lib/spree/utils/normalizations/normalize-cart.ts @@ -0,0 +1,191 @@ +import type { Cart, LineItem, ProductVariant, SelectedOption } from '@commerce/types/cart'; +import MissingLineItemVariantError from '../../errors/MissingLineItemVariantError'; +import { requireConfigValue } from '../../isomorphic-config'; +import type { OrderAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Order'; +import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'; +import type { Image } from '@commerce/types/common'; +import { jsonApi } from '@spree/storefront-api-v2-sdk'; +import createGetAbsoluteImageUrl from '../create-get-absolute-image-url'; +import getMediaGallery from '../get-media-gallery'; +import type { + LineItemAttr, + OptionTypeAttr, + SpreeProductImage, + SpreeSdkResponse, + VariantAttr +} from '../../types'; + +const placeholderImage = requireConfigValue('lineItemPlaceholderImageUrl') as string | false; + +const isColorProductOption = (productOptionType: OptionTypeAttr) => { + return productOptionType.attributes.presentation === 'Color'; +}; + +const normalizeVariant = ( + spreeSuccessResponse: SpreeSdkResponse, + spreeVariant: VariantAttr +): ProductVariant => { + const spreeProduct = jsonApi.findSingleRelationshipDocument( + spreeSuccessResponse, + spreeVariant, + 'product' + ); + + if (spreeProduct === null) { + throw new MissingLineItemVariantError( + `Couldn't find product for variant with id ${spreeVariant.id}.` + ); + } + + const spreeVariantImageRecords = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + spreeVariant, + 'images' + ); + + let lineItemImage; + + const variantImage = getMediaGallery( + spreeVariantImageRecords, + createGetAbsoluteImageUrl(requireConfigValue('imageHost') as string) + )[0]; + + if (variantImage) { + lineItemImage = variantImage; + } else { + const spreeProductImageRecords = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + spreeProduct, + 'images' + ); + + const productImage = getMediaGallery( + spreeProductImageRecords, + createGetAbsoluteImageUrl(requireConfigValue('imageHost') as string) + )[0]; + + lineItemImage = productImage; + } + + const image: Image = + lineItemImage ?? (placeholderImage === false ? undefined : { url: placeholderImage }); + + return { + id: spreeVariant.id, + sku: spreeVariant.attributes.sku, + name: spreeProduct.attributes.name, + requiresShipping: true, + price: parseFloat(spreeVariant.attributes.price), + listPrice: parseFloat(spreeVariant.attributes.price), + image, + isInStock: spreeVariant.attributes.in_stock, + availableForSale: spreeVariant.attributes.purchasable, + ...(spreeVariant.attributes.weight === '0.0' + ? {} + : { + weight: { + value: parseFloat(spreeVariant.attributes.weight), + unit: 'KILOGRAMS' + } + }) + // TODO: Add height, width and depth when Measurement type allows distance measurements. + }; +}; + +const normalizeLineItem = ( + spreeSuccessResponse: SpreeSdkResponse, + spreeLineItem: LineItemAttr +): LineItem => { + const variant = jsonApi.findSingleRelationshipDocument( + spreeSuccessResponse, + spreeLineItem, + 'variant' + ); + + if (variant === null) { + throw new MissingLineItemVariantError( + `Couldn't find variant for line item with id ${spreeLineItem.id}.` + ); + } + + const product = jsonApi.findSingleRelationshipDocument( + spreeSuccessResponse, + variant, + 'product' + ); + + if (product === null) { + throw new MissingLineItemVariantError( + `Couldn't find product for variant with id ${variant.id}.` + ); + } + + // CartItem.tsx expects path without a '/' prefix unlike pages/product/[slug].tsx and others. + const path = `${product.attributes.slug}`; + + const spreeOptionValues = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + variant, + 'option_values' + ); + + const options: SelectedOption[] = spreeOptionValues.map((spreeOptionValue) => { + const spreeOptionType = jsonApi.findSingleRelationshipDocument( + spreeSuccessResponse, + spreeOptionValue, + 'option_type' + ); + + if (spreeOptionType === null) { + throw new MissingLineItemVariantError( + `Couldn't find option type of option value with id ${spreeOptionValue.id}.` + ); + } + + const label = isColorProductOption(spreeOptionType) + ? spreeOptionValue.attributes.name + : spreeOptionValue.attributes.presentation; + + return { + id: spreeOptionValue.id, + name: spreeOptionType.attributes.presentation, + value: label + }; + }); + + return { + id: spreeLineItem.id, + variantId: variant.id, + productId: product.id, + name: spreeLineItem.attributes.name, + quantity: spreeLineItem.attributes.quantity, + discounts: [], // TODO: Implement when the template starts displaying them. + path, + variant: normalizeVariant(spreeSuccessResponse, variant), + options + }; +}; + +const normalizeCart = (spreeSuccessResponse: SpreeSdkResponse, spreeCart: OrderAttr): Cart => { + const lineItems = jsonApi + .findRelationshipDocuments(spreeSuccessResponse, spreeCart, 'line_items') + .map((lineItem) => normalizeLineItem(spreeSuccessResponse, lineItem)); + + return { + id: spreeCart.id, + createdAt: spreeCart.attributes.created_at.toString(), + currency: { code: spreeCart.attributes.currency }, + taxesIncluded: true, + lineItems, + lineItemsSubtotalPrice: parseFloat(spreeCart.attributes.item_total), + subtotalPrice: parseFloat(spreeCart.attributes.item_total), + totalPrice: parseFloat(spreeCart.attributes.total), + customerId: spreeCart.attributes.token, + email: spreeCart.attributes.email, + discounts: [] // TODO: Implement when the template starts displaying them. + }; +}; + +export { normalizeLineItem }; + +export default normalizeCart; diff --git a/lib/spree/utils/normalizations/normalize-page.ts b/lib/spree/utils/normalizations/normalize-page.ts new file mode 100644 index 000000000..c257bacc1 --- /dev/null +++ b/lib/spree/utils/normalizations/normalize-page.ts @@ -0,0 +1,42 @@ +import { Page } from '@commerce/types/page'; +import type { PageAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Page'; +import { SpreeSdkResponse } from '../../types'; + +const normalizePage = ( + _spreeSuccessResponse: SpreeSdkResponse, + spreePage: PageAttr, + commerceLocales: string[] +): Page => { + // If the locale returned by Spree is not available, search + // for a similar one. + + const spreeLocale = spreePage.attributes.locale; + let usedCommerceLocale: string; + + if (commerceLocales.includes(spreeLocale)) { + usedCommerceLocale = spreeLocale; + } else { + const genericSpreeLocale = spreeLocale.split('-')[0]; + + const foundExactGenericLocale = commerceLocales.includes(genericSpreeLocale); + + if (foundExactGenericLocale) { + usedCommerceLocale = genericSpreeLocale; + } else { + const foundSimilarLocale = commerceLocales.find((locale) => { + return locale.split('-')[0] === genericSpreeLocale; + }); + + usedCommerceLocale = foundSimilarLocale || spreeLocale; + } + } + + return { + id: spreePage.id, + name: spreePage.attributes.title, + url: `/${usedCommerceLocale}/${spreePage.attributes.slug}`, + body: spreePage.attributes.content + }; +}; + +export default normalizePage; diff --git a/lib/spree/utils/normalizations/normalize-product.ts b/lib/spree/utils/normalizations/normalize-product.ts new file mode 100644 index 000000000..716980aa1 --- /dev/null +++ b/lib/spree/utils/normalizations/normalize-product.ts @@ -0,0 +1,196 @@ +import type { Product, ProductImage, ProductPrice, ProductVariant } from '@commerce/types/product'; +import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'; +import type { RelationType } from '@spree/storefront-api-v2-sdk/types/interfaces/Relationships'; +import { jsonApi } from '@spree/storefront-api-v2-sdk'; +import { JsonApiDocument } from '@spree/storefront-api-v2-sdk/types/interfaces/JsonApi'; +import { requireConfigValue } from '../../isomorphic-config'; +import createGetAbsoluteImageUrl from '../create-get-absolute-image-url'; +import expandOptions from '../expand-options'; +import getMediaGallery from '../get-media-gallery'; +import getProductPath from '../get-product-path'; +import MissingPrimaryVariantError from '../../errors/MissingPrimaryVariantError'; +import MissingOptionValueError from '../../errors/MissingOptionValueError'; +import type { ExpandedProductOption, SpreeSdkResponse, VariantAttr } from '../../types'; + +const placeholderImage = requireConfigValue('productPlaceholderImageUrl') as string | false; + +const imagesOptionFilter = requireConfigValue('imagesOptionFilter') as string | false; + +const normalizeProduct = ( + spreeSuccessResponse: SpreeSdkResponse, + spreeProduct: ProductAttr +): Product => { + const spreePrimaryVariant = jsonApi.findSingleRelationshipDocument( + spreeSuccessResponse, + spreeProduct, + 'primary_variant' + ); + + if (spreePrimaryVariant === null) { + throw new MissingPrimaryVariantError( + `Couldn't find primary variant for product with id ${spreeProduct.id}.` + ); + } + + const sku = spreePrimaryVariant.attributes.sku; + + const price: ProductPrice = { + value: parseFloat(spreeProduct.attributes.price), + currencyCode: spreeProduct.attributes.currency + }; + + const hasNonMasterVariants = + (spreeProduct.relationships.variants.data as RelationType[]).length > 1; + + const showOptions = + (requireConfigValue('showSingleVariantOptions') as boolean) || hasNonMasterVariants; + + let options: ExpandedProductOption[] = []; + + const spreeVariantRecords = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + spreeProduct, + 'variants' + ); + + // Use variants with option values if available. Fall back to + // Spree primary_variant if no explicit variants are present. + const spreeOptionsVariantsOrPrimary = + spreeVariantRecords.length === 0 ? [spreePrimaryVariant] : spreeVariantRecords; + + const variants: ProductVariant[] = spreeOptionsVariantsOrPrimary.map((spreeVariantRecord) => { + let variantOptions: ExpandedProductOption[] = []; + + if (showOptions) { + const spreeOptionValues = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + spreeVariantRecord, + 'option_values' + ); + + // Only include options which are used by variants. + + spreeOptionValues.forEach((spreeOptionValue) => { + variantOptions = expandOptions(spreeSuccessResponse, spreeOptionValue, variantOptions); + + options = expandOptions(spreeSuccessResponse, spreeOptionValue, options); + }); + } + + return { + id: spreeVariantRecord.id, + options: variantOptions + }; + }); + + const spreePrimaryVariantImageRecords = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + spreePrimaryVariant, + 'images' + ); + + let spreeVariantImageRecords: JsonApiDocument[]; + + if (imagesOptionFilter === false) { + spreeVariantImageRecords = spreeVariantRecords.reduce( + (accumulatedImageRecords, spreeVariantRecord) => { + return [ + ...accumulatedImageRecords, + ...jsonApi.findRelationshipDocuments(spreeSuccessResponse, spreeVariantRecord, 'images') + ]; + }, + [] + ); + } else { + const spreeOptionTypes = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + spreeProduct, + 'option_types' + ); + + const imagesFilterOptionType = spreeOptionTypes.find( + (spreeOptionType) => spreeOptionType.attributes.name === imagesOptionFilter + ); + + if (!imagesFilterOptionType) { + console.warn( + `Couldn't find option type having name ${imagesOptionFilter} for product with id ${spreeProduct.id}.` + + ' Showing no images for this product.' + ); + + spreeVariantImageRecords = []; + } else { + const imagesOptionTypeFilterId = imagesFilterOptionType.id; + const includedOptionValuesImagesIds: string[] = []; + + spreeVariantImageRecords = spreeVariantRecords.reduce( + (accumulatedImageRecords, spreeVariantRecord) => { + const spreeVariantOptionValuesIdentifiers: RelationType[] = + spreeVariantRecord.relationships.option_values.data; + + const spreeOptionValueOfFilterTypeIdentifier = spreeVariantOptionValuesIdentifiers.find( + (spreeVariantOptionValuesIdentifier: RelationType) => + imagesFilterOptionType.relationships.option_values.data.some( + (filterOptionTypeValueIdentifier: RelationType) => + filterOptionTypeValueIdentifier.id === spreeVariantOptionValuesIdentifier.id + ) + ); + + if (!spreeOptionValueOfFilterTypeIdentifier) { + throw new MissingOptionValueError( + `Couldn't find option value related to option type with id ${imagesOptionTypeFilterId}.` + ); + } + + const optionValueImagesAlreadyIncluded = includedOptionValuesImagesIds.includes( + spreeOptionValueOfFilterTypeIdentifier.id + ); + + if (optionValueImagesAlreadyIncluded) { + return accumulatedImageRecords; + } + + includedOptionValuesImagesIds.push(spreeOptionValueOfFilterTypeIdentifier.id); + + return [ + ...accumulatedImageRecords, + ...jsonApi.findRelationshipDocuments(spreeSuccessResponse, spreeVariantRecord, 'images') + ]; + }, + [] + ); + } + } + + const spreeImageRecords = [...spreePrimaryVariantImageRecords, ...spreeVariantImageRecords]; + + const productImages = getMediaGallery( + spreeImageRecords, + createGetAbsoluteImageUrl(requireConfigValue('imageHost') as string) + ); + + const images: ProductImage[] = + productImages.length === 0 + ? placeholderImage === false + ? [] + : [{ url: placeholderImage }] + : productImages; + + const slug = spreeProduct.attributes.slug; + const path = getProductPath(spreeProduct); + + return { + id: spreeProduct.id, + name: spreeProduct.attributes.name, + description: spreeProduct.attributes.description, + images, + variants, + options, + price, + slug, + path, + sku + }; +}; + +export default normalizeProduct; diff --git a/lib/spree/utils/normalizations/normalize-user.ts b/lib/spree/utils/normalizations/normalize-user.ts new file mode 100644 index 000000000..246936152 --- /dev/null +++ b/lib/spree/utils/normalizations/normalize-user.ts @@ -0,0 +1,16 @@ +import type { Customer } from '@commerce/types/customer'; +import type { AccountAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Account'; +import type { SpreeSdkResponse } from '../../types'; + +const normalizeUser = ( + _spreeSuccessResponse: SpreeSdkResponse, + spreeUser: AccountAttr +): Customer => { + const email = spreeUser.attributes.email; + + return { + email + }; +}; + +export default normalizeUser; diff --git a/lib/spree/utils/normalizations/normalize-wishlist.ts b/lib/spree/utils/normalizations/normalize-wishlist.ts new file mode 100644 index 000000000..15a73ef4f --- /dev/null +++ b/lib/spree/utils/normalizations/normalize-wishlist.ts @@ -0,0 +1,60 @@ +import MissingProductError from '../../errors/MissingProductError'; +import MissingVariantError from '../../errors/MissingVariantError'; +import { jsonApi } from '@spree/storefront-api-v2-sdk'; +import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'; +import type { WishedItemAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/WishedItem'; +import type { WishlistAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Wishlist'; +import type { ExplicitCommerceWishlist, SpreeSdkResponse, VariantAttr } from '../../types'; +import normalizeProduct from './normalize-product'; + +const normalizeWishlist = ( + spreeSuccessResponse: SpreeSdkResponse, + spreeWishlist: WishlistAttr +): ExplicitCommerceWishlist => { + const spreeWishedItems = jsonApi.findRelationshipDocuments( + spreeSuccessResponse, + spreeWishlist, + 'wished_items' + ); + + const items: ExplicitCommerceWishlist['items'] = spreeWishedItems.map((spreeWishedItem) => { + const spreeWishedVariant = jsonApi.findSingleRelationshipDocument( + spreeSuccessResponse, + spreeWishedItem, + 'variant' + ); + + if (spreeWishedVariant === null) { + throw new MissingVariantError( + `Couldn't find variant for wished item with id ${spreeWishedItem.id}.` + ); + } + + const spreeWishedProduct = jsonApi.findSingleRelationshipDocument( + spreeSuccessResponse, + spreeWishedVariant, + 'product' + ); + + if (spreeWishedProduct === null) { + throw new MissingProductError( + `Couldn't find product for variant with id ${spreeWishedVariant.id}.` + ); + } + + return { + id: spreeWishedItem.id, + product_id: parseInt(spreeWishedProduct.id, 10), + variant_id: parseInt(spreeWishedVariant.id, 10), + product: normalizeProduct(spreeSuccessResponse, spreeWishedProduct) + }; + }); + + return { + id: spreeWishlist.id, + token: spreeWishlist.attributes.token, + items + }; +}; + +export default normalizeWishlist; diff --git a/lib/spree/utils/require-config.ts b/lib/spree/utils/require-config.ts new file mode 100644 index 000000000..2d0072b63 --- /dev/null +++ b/lib/spree/utils/require-config.ts @@ -0,0 +1,14 @@ +import MissingConfigurationValueError from '../errors/MissingConfigurationValueError'; +import type { NonUndefined, ValueOf } from '../types'; + +const requireConfig = (isomorphicConfig: T, key: keyof T) => { + const valueUnderKey = isomorphicConfig[key]; + + if (typeof valueUnderKey === 'undefined') { + throw new MissingConfigurationValueError(`Value for configuration key ${key} was undefined.`); + } + + return valueUnderKey as NonUndefined>; +}; + +export default requireConfig; diff --git a/lib/spree/utils/sort-option-types.ts b/lib/spree/utils/sort-option-types.ts new file mode 100644 index 000000000..99e05ac02 --- /dev/null +++ b/lib/spree/utils/sort-option-types.ts @@ -0,0 +1,9 @@ +import type { ExpandedProductOption } from '../types'; + +const sortOptionsByPosition = (options: ExpandedProductOption[]): ExpandedProductOption[] => { + return options.sort((firstOption, secondOption) => { + return firstOption.position - secondOption.position; + }); +}; + +export default sortOptionsByPosition; diff --git a/lib/spree/utils/tokens/cart-token.ts b/lib/spree/utils/tokens/cart-token.ts new file mode 100644 index 000000000..596d6ea27 --- /dev/null +++ b/lib/spree/utils/tokens/cart-token.ts @@ -0,0 +1,16 @@ +import { requireConfigValue } from '../../isomorphic-config'; +import Cookies from 'js-cookie'; + +export const getCartToken = () => Cookies.get(requireConfigValue('cartCookieName') as string); + +export const setCartToken = (cartToken: string) => { + const cookieOptions = { + expires: requireConfigValue('cartCookieExpire') as number + }; + + Cookies.set(requireConfigValue('cartCookieName') as string, cartToken, cookieOptions); +}; + +export const removeCartToken = () => { + Cookies.remove(requireConfigValue('cartCookieName') as string); +}; diff --git a/lib/spree/utils/tokens/ensure-fresh-user-access-token.ts b/lib/spree/utils/tokens/ensure-fresh-user-access-token.ts new file mode 100644 index 000000000..a2483ad1f --- /dev/null +++ b/lib/spree/utils/tokens/ensure-fresh-user-access-token.ts @@ -0,0 +1,49 @@ +import { SpreeSdkResponseWithRawResponse } from '../../types'; +import type { Client } from '@spree/storefront-api-v2-sdk'; +import type { IOAuthToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import getSpreeSdkMethodFromEndpointPath from '../get-spree-sdk-method-from-endpoint-path'; +import { + ensureUserTokenResponse, + removeUserTokenResponse, + setUserTokenResponse +} from './user-token-response'; +import AccessTokenError from '../../errors/AccessTokenError'; + +/** + * If the user has a saved access token, make sure it's not expired + * If it is expired, attempt to refresh it. + */ +const ensureFreshUserAccessToken = async (client: Client): Promise => { + const userTokenResponse = ensureUserTokenResponse(); + + if (!userTokenResponse) { + // There's no user token or it has an invalid format. + return; + } + + const isAccessTokenExpired = + (userTokenResponse.created_at + userTokenResponse.expires_in) * 1000 < Date.now(); + + if (!isAccessTokenExpired) { + return; + } + + const spreeRefreshAccessTokenSdkMethod = getSpreeSdkMethodFromEndpointPath< + Client, + SpreeSdkResponseWithRawResponse & IOAuthToken + >(client, 'authentication.refreshToken'); + + const spreeRefreshAccessTokenResponse = await spreeRefreshAccessTokenSdkMethod({ + refresh_token: userTokenResponse.refresh_token + }); + + if (spreeRefreshAccessTokenResponse.isFail()) { + removeUserTokenResponse(); + + throw new AccessTokenError('Could not refresh access token.'); + } + + setUserTokenResponse(spreeRefreshAccessTokenResponse.success()); +}; + +export default ensureFreshUserAccessToken; diff --git a/lib/spree/utils/tokens/ensure-itoken.ts b/lib/spree/utils/tokens/ensure-itoken.ts new file mode 100644 index 000000000..df412f53f --- /dev/null +++ b/lib/spree/utils/tokens/ensure-itoken.ts @@ -0,0 +1,25 @@ +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import { getCartToken } from './cart-token'; +import { ensureUserTokenResponse } from './user-token-response'; + +const ensureIToken = (): IToken | undefined => { + const userTokenResponse = ensureUserTokenResponse(); + + if (userTokenResponse) { + return { + bearerToken: userTokenResponse.access_token + }; + } + + const cartToken = getCartToken(); + + if (cartToken) { + return { + orderToken: cartToken + }; + } + + return undefined; +}; + +export default ensureIToken; diff --git a/lib/spree/utils/tokens/is-logged-in.ts b/lib/spree/utils/tokens/is-logged-in.ts new file mode 100644 index 000000000..214aef4df --- /dev/null +++ b/lib/spree/utils/tokens/is-logged-in.ts @@ -0,0 +1,9 @@ +import { ensureUserTokenResponse } from './user-token-response'; + +const isLoggedIn = (): boolean => { + const userTokenResponse = ensureUserTokenResponse(); + + return !!userTokenResponse; +}; + +export default isLoggedIn; diff --git a/lib/spree/utils/tokens/revoke-user-tokens.ts b/lib/spree/utils/tokens/revoke-user-tokens.ts new file mode 100644 index 000000000..de2510a91 --- /dev/null +++ b/lib/spree/utils/tokens/revoke-user-tokens.ts @@ -0,0 +1,45 @@ +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { HookFetcherContext } from '@commerce/utils/types'; +import TokensNotRejectedError from '../../errors/TokensNotRejectedError'; +import type { UserOAuthTokens } from '../../types'; +import type { EmptyObjectResponse } from '@spree/storefront-api-v2-sdk/types/interfaces/EmptyObject'; + +const revokeUserTokens = async ( + fetch: HookFetcherContext<{ + data: any; + }>['fetch'], + userTokens: UserOAuthTokens +): Promise => { + const spreeRevokeTokensResponses = await Promise.allSettled([ + fetch>({ + variables: { + methodPath: 'authentication.revokeToken', + arguments: [ + { + token: userTokens.refreshToken + } + ] + } + }), + fetch>({ + variables: { + methodPath: 'authentication.revokeToken', + arguments: [ + { + token: userTokens.accessToken + } + ] + } + }) + ]); + + const anyRejected = spreeRevokeTokensResponses.some((response) => response.status === 'rejected'); + + if (anyRejected) { + throw new TokensNotRejectedError('Some tokens could not be rejected in Spree.'); + } + + return undefined; +}; + +export default revokeUserTokens; diff --git a/lib/spree/utils/tokens/user-token-response.ts b/lib/spree/utils/tokens/user-token-response.ts new file mode 100644 index 000000000..516ecf89f --- /dev/null +++ b/lib/spree/utils/tokens/user-token-response.ts @@ -0,0 +1,50 @@ +import { requireConfigValue } from '../../isomorphic-config'; +import Cookies from 'js-cookie'; +import type { IOAuthToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import UserTokenResponseParseError from '../../errors/UserTokenResponseParseError'; + +export const getUserTokenResponse = (): IOAuthToken | undefined => { + const stringifiedToken = Cookies.get(requireConfigValue('userCookieName') as string); + + if (!stringifiedToken) { + return undefined; + } + + try { + const token: IOAuthToken = JSON.parse(stringifiedToken); + + return token; + } catch (parseError) { + throw new UserTokenResponseParseError('Could not parse stored user token response.'); + } +}; + +/** + * Retrieves the saved user token response. If the response fails json parsing, + * removes the saved token and returns @type {undefined} instead. + */ +export const ensureUserTokenResponse = (): IOAuthToken | undefined => { + try { + return getUserTokenResponse(); + } catch (error) { + if (error instanceof UserTokenResponseParseError) { + removeUserTokenResponse(); + + return undefined; + } + + throw error; + } +}; + +export const setUserTokenResponse = (token: IOAuthToken) => { + const cookieOptions = { + expires: requireConfigValue('userCookieExpire') as number + }; + + Cookies.set(requireConfigValue('userCookieName') as string, JSON.stringify(token), cookieOptions); +}; + +export const removeUserTokenResponse = () => { + Cookies.remove(requireConfigValue('userCookieName') as string); +}; diff --git a/lib/spree/utils/validations/validate-all-products-taxonomy-id.ts b/lib/spree/utils/validations/validate-all-products-taxonomy-id.ts new file mode 100644 index 000000000..392ae4a7e --- /dev/null +++ b/lib/spree/utils/validations/validate-all-products-taxonomy-id.ts @@ -0,0 +1,13 @@ +const validateAllProductsTaxonomyId = (taxonomyId: unknown): string | false => { + if (!taxonomyId || taxonomyId === 'false') { + return false; + } + + if (typeof taxonomyId === 'string') { + return taxonomyId; + } + + throw new TypeError('taxonomyId must be a string or falsy.'); +}; + +export default validateAllProductsTaxonomyId; diff --git a/lib/spree/utils/validations/validate-cookie-expire.ts b/lib/spree/utils/validations/validate-cookie-expire.ts new file mode 100644 index 000000000..54daf50ad --- /dev/null +++ b/lib/spree/utils/validations/validate-cookie-expire.ts @@ -0,0 +1,19 @@ +const validateCookieExpire = (expire: unknown): number => { + let expireInteger: number; + + if (typeof expire === 'string') { + expireInteger = parseFloat(expire); + } else if (typeof expire === 'number') { + expireInteger = expire; + } else { + throw new TypeError('expire must be a string containing a number or an integer.'); + } + + if (expireInteger < 0) { + throw new RangeError('expire must be non-negative.'); + } + + return expireInteger; +}; + +export default validateCookieExpire; diff --git a/lib/spree/utils/validations/validate-images-option-filter.ts b/lib/spree/utils/validations/validate-images-option-filter.ts new file mode 100644 index 000000000..4e0083947 --- /dev/null +++ b/lib/spree/utils/validations/validate-images-option-filter.ts @@ -0,0 +1,13 @@ +const validateImagesOptionFilter = (optionTypeNameOrFalse: unknown): string | false => { + if (!optionTypeNameOrFalse || optionTypeNameOrFalse === 'false') { + return false; + } + + if (typeof optionTypeNameOrFalse === 'string') { + return optionTypeNameOrFalse; + } + + throw new TypeError('optionTypeNameOrFalse must be a string or falsy.'); +}; + +export default validateImagesOptionFilter; diff --git a/lib/spree/utils/validations/validate-images-quality.ts b/lib/spree/utils/validations/validate-images-quality.ts new file mode 100644 index 000000000..7eb5181e8 --- /dev/null +++ b/lib/spree/utils/validations/validate-images-quality.ts @@ -0,0 +1,19 @@ +const validateImagesQuality = (quality: unknown): number => { + let quality_level: number; + + if (typeof quality === 'string') { + quality_level = parseInt(quality); + } else if (typeof quality === 'number') { + quality_level = quality; + } else { + throw new TypeError('prerenderCount count must be a string containing a number or an integer.'); + } + + if (quality_level === NaN) { + throw new TypeError('prerenderCount count must be a string containing a number or an integer.'); + } + + return quality_level; +}; + +export default validateImagesQuality; diff --git a/lib/spree/utils/validations/validate-images-size.ts b/lib/spree/utils/validations/validate-images-size.ts new file mode 100644 index 000000000..501027c08 --- /dev/null +++ b/lib/spree/utils/validations/validate-images-size.ts @@ -0,0 +1,13 @@ +const validateImagesSize = (size: unknown): string => { + if (typeof size !== 'string') { + throw new TypeError('size must be a string.'); + } + + if (!size.includes('x') || size.split('x').length != 2) { + throw new Error("size must have two numbers separated with an 'x'"); + } + + return size; +}; + +export default validateImagesSize; diff --git a/lib/spree/utils/validations/validate-placeholder-image-url.ts b/lib/spree/utils/validations/validate-placeholder-image-url.ts new file mode 100644 index 000000000..e42ba64bd --- /dev/null +++ b/lib/spree/utils/validations/validate-placeholder-image-url.ts @@ -0,0 +1,13 @@ +const validatePlaceholderImageUrl = (placeholderUrlOrFalse: unknown): string | false => { + if (!placeholderUrlOrFalse || placeholderUrlOrFalse === 'false') { + return false; + } + + if (typeof placeholderUrlOrFalse === 'string') { + return placeholderUrlOrFalse; + } + + throw new TypeError('placeholderUrlOrFalse must be a string or falsy.'); +}; + +export default validatePlaceholderImageUrl; diff --git a/lib/spree/utils/validations/validate-products-prerender-count.ts b/lib/spree/utils/validations/validate-products-prerender-count.ts new file mode 100644 index 000000000..533d42473 --- /dev/null +++ b/lib/spree/utils/validations/validate-products-prerender-count.ts @@ -0,0 +1,19 @@ +const validateProductsPrerenderCount = (prerenderCount: unknown): number => { + let prerenderCountInteger: number; + + if (typeof prerenderCount === 'string') { + prerenderCountInteger = parseInt(prerenderCount); + } else if (typeof prerenderCount === 'number') { + prerenderCountInteger = prerenderCount; + } else { + throw new TypeError('prerenderCount count must be a string containing a number or an integer.'); + } + + if (prerenderCountInteger < 0) { + throw new RangeError('prerenderCount must be non-negative.'); + } + + return prerenderCountInteger; +}; + +export default validateProductsPrerenderCount; diff --git a/lib/spree/wishlist/index.ts b/lib/spree/wishlist/index.ts new file mode 100644 index 000000000..79b8a0b94 --- /dev/null +++ b/lib/spree/wishlist/index.ts @@ -0,0 +1,3 @@ +export { default as useAddItem } from './use-add-item'; +export { default as useWishlist } from './use-wishlist'; +export { default as useRemoveItem } from './use-remove-item'; diff --git a/lib/spree/wishlist/use-add-item.tsx b/lib/spree/wishlist/use-add-item.tsx new file mode 100644 index 000000000..cce3d1401 --- /dev/null +++ b/lib/spree/wishlist/use-add-item.tsx @@ -0,0 +1,86 @@ +import { useCallback } from 'react'; +import type { MutationHook } from '@commerce/utils/types'; +import useAddItem from '@commerce/wishlist/use-add-item'; +import type { UseAddItem } from '@commerce/wishlist/use-add-item'; +import useWishlist from './use-wishlist'; +import type { ExplicitWishlistAddItemHook } from '../types'; +import type { + WishedItem, + WishlistsAddWishedItem +} from '@spree/storefront-api-v2-sdk/types/interfaces/WishedItem'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import ensureIToken from '../utils/tokens/ensure-itoken'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import type { AddItemHook } from '@commerce/types/wishlist'; +import isLoggedIn from '../utils/tokens/is-logged-in'; + +export default useAddItem as UseAddItem; + +export const handler: MutationHook = { + fetchOptions: { + url: 'wishlists', + query: 'addWishedItem' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useAddItem (wishlist) fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const { + item: { productId, variantId, wishlistToken } + } = input; + + if (!isLoggedIn() || !wishlistToken) { + return null; + } + + let token: IToken | undefined = ensureIToken(); + + const addItemParameters: WishlistsAddWishedItem = { + variant_id: `${variantId}`, + quantity: 1 + }; + + await fetch>({ + variables: { + methodPath: 'wishlists.addWishedItem', + arguments: [token, wishlistToken, addItemParameters] + } + }); + + return null; + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType['useHook']> = () => { + const wishlist = useWishlist(); + + return useCallback( + async (item) => { + if (!wishlist.data) { + return null; + } + + const data = await fetch({ + input: { + item: { + ...item, + wishlistToken: wishlist.data.token + } + } + }); + + await wishlist.revalidate(); + + return data; + }, + [wishlist] + ); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/wishlist/use-remove-item.tsx b/lib/spree/wishlist/use-remove-item.tsx new file mode 100644 index 000000000..e66b1d849 --- /dev/null +++ b/lib/spree/wishlist/use-remove-item.tsx @@ -0,0 +1,75 @@ +import { useCallback } from 'react'; +import type { MutationHook } from '@commerce/utils/types'; +import useRemoveItem from '@commerce/wishlist/use-remove-item'; +import type { UseRemoveItem } from '@commerce/wishlist/use-remove-item'; +import useWishlist from './use-wishlist'; +import type { ExplicitWishlistRemoveItemHook } from '../types'; +import isLoggedIn from '../utils/tokens/is-logged-in'; +import ensureIToken from '../utils/tokens/ensure-itoken'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { WishedItem } from '@spree/storefront-api-v2-sdk/types/interfaces/WishedItem'; + +export default useRemoveItem as UseRemoveItem; + +export const handler: MutationHook = { + fetchOptions: { + url: 'wishlists', + query: 'removeWishedItem' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useRemoveItem (wishlist) fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + const { itemId, wishlistToken } = input; + + if (!isLoggedIn() || !wishlistToken) { + return null; + } + + let token: IToken | undefined = ensureIToken(); + + await fetch>({ + variables: { + methodPath: 'wishlists.removeWishedItem', + arguments: [token, wishlistToken, itemId] + } + }); + + return null; + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType< + MutationHook['useHook'] + > = () => { + const wishlist = useWishlist(); + + return useCallback( + async (input) => { + if (!wishlist.data) { + return null; + } + + const data = await fetch({ + input: { + itemId: `${input.id}`, + wishlistToken: wishlist.data.token + } + }); + + await wishlist.revalidate(); + + return data; + }, + [wishlist] + ); + }; + + return useWrappedHook; + } +}; diff --git a/lib/spree/wishlist/use-wishlist.tsx b/lib/spree/wishlist/use-wishlist.tsx new file mode 100644 index 000000000..4c94c8bbb --- /dev/null +++ b/lib/spree/wishlist/use-wishlist.tsx @@ -0,0 +1,91 @@ +import { useMemo } from 'react'; +import type { SWRHook } from '@commerce/utils/types'; +import useWishlist from '@commerce/wishlist/use-wishlist'; +import type { UseWishlist } from '@commerce/wishlist/use-wishlist'; +import type { GetWishlistHook } from '@commerce/types/wishlist'; +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token'; +import type { GraphQLFetcherResult } from '@commerce/api'; +import type { Wishlist } from '@spree/storefront-api-v2-sdk/types/interfaces/Wishlist'; +import ensureIToken from '../utils/tokens/ensure-itoken'; +import normalizeWishlist from '../utils/normalizations/normalize-wishlist'; +import isLoggedIn from '../utils/tokens/is-logged-in'; + +export default useWishlist as UseWishlist; + +export const handler: SWRHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + url: 'wishlists', + query: 'default' + }, + async fetcher({ input, options, fetch }) { + console.info( + 'useWishlist fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ); + + if (!isLoggedIn()) { + return null; + } + + // TODO: Optimize with includeProducts. + + const token: IToken | undefined = ensureIToken(); + + const { data: spreeWishlistsDefaultSuccessResponse } = await fetch< + GraphQLFetcherResult + >({ + variables: { + methodPath: 'wishlists.default', + arguments: [ + token, + { + include: [ + 'wished_items', + 'wished_items.variant', + 'wished_items.variant.product', + 'wished_items.variant.product.primary_variant', + 'wished_items.variant.product.images', + 'wished_items.variant.product.option_types', + 'wished_items.variant.product.variants', + 'wished_items.variant.product.variants.option_values' + ].join(',') + } + ] + } + }); + + return normalizeWishlist( + spreeWishlistsDefaultSuccessResponse, + spreeWishlistsDefaultSuccessResponse.data + ); + }, + useHook: ({ useData }) => { + const useWrappedHook: ReturnType['useHook']> = (input) => { + const response = useData({ + swrOptions: { + revalidateOnFocus: false, + ...input?.swrOptions + } + }); + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.items?.length || 0) <= 0; + }, + enumerable: true + } + }), + [response] + ); + }; + + return useWrappedHook; + } +}; diff --git a/next.config.js b/next.config.js index 8bab35c40..ce04f5a91 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,5 @@ /** @type {import('next').NextConfig} */ -module.exports = { +const baseConfig = { eslint: { // Disabling on production builds because we're running checks on PRs via GitHub Actions. ignoreDuringBuilds: true @@ -24,3 +24,7 @@ module.exports = { ]; } }; + +const spreeConfig = require('./lib/spree/next.config.js'); + +module.exports = { ...baseConfig, ...spreeConfig }; diff --git a/package.json b/package.json index 711a9a38b..76880cdbe 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "pnpm": ">=8" }, "scripts": { - "dev": "next dev --turbo", + "dev": "next dev -p 4000 --turbo", "build": "next build", "start": "next start", "lint": "next lint", @@ -24,6 +24,9 @@ "dependencies": { "@headlessui/react": "^1.7.19", "@heroicons/react": "^2.1.3", + "@spree/axios-fetcher": "^1.0.0", + "@spree/storefront-api-v2-sdk": "^6.0.6", + "axios": "^1.7.1", "clsx": "^2.1.0", "geist": "^1.3.0", "next": "14.2.2", diff --git a/tsconfig.json b/tsconfig.json index 6cd05f98a..14ac13ac8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,9 @@ "jsx": "preserve", "incremental": true, "baseUrl": ".", + "paths": { + "@commerce/*": ["lib/spree/*"] + }, "noUncheckedIndexedAccess": true, "plugins": [ { diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..a542e52dc --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3465 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@babel/code-frame@^7.0.0": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" + integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== + +"@babel/highlight@^7.24.2": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.5.tgz#bc0613f98e1dd0720e99b2a9ee3760194a704b6e" + integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.5" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/runtime@^7.23.2": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" + integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== + dependencies: + regenerator-runtime "^0.14.0" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + +"@headlessui/react@^1.7.19": + version "1.7.19" + resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.19.tgz#91c78cf5fcb254f4a0ebe96936d48421caf75f40" + integrity sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw== + dependencies: + "@tanstack/react-virtual" "^3.0.0-beta.60" + client-only "^0.0.1" + +"@heroicons/react@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.3.tgz#78a2a7f504a7370283d07eabcddc7fec04f503db" + integrity sha512-fEcPfo4oN345SoqdlCDdSa4ivjaKbk0jTd+oubcgNxnNgAfzysfwWfQUr+51wigiWHQQRiZNd1Ao0M5Y3M2EGg== + +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.24": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@next/env@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.2.tgz#6c36fe0b04a22ea78bd60a645ae77d53cd16d3ca" + integrity sha512-sk72qRfM1Q90XZWYRoJKu/UWlTgihrASiYw/scb15u+tyzcze3bOuJ/UV6TBOQEeUaxOkRqGeuGUdiiuxc5oqw== + +"@next/eslint-plugin-next@14.2.3": + version "14.2.3" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.3.tgz#287ad8620e7061ba01e8d3313d464db6d217b6df" + integrity sha512-L3oDricIIjgj1AVnRdRor21gI7mShlSwU/1ZGHmqM3LzHhXXhdkrfeNY5zif25Bi5Dd7fiJHsbhoZCHfXYvlAw== + dependencies: + glob "10.3.10" + +"@next/swc-darwin-arm64@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.2.tgz#55e395b0db6dd5ea2dc92818260ff3a399f1a056" + integrity sha512-3iPgMhzbalizGwHNFUcGnDhFPSgVBHQ8aqSTAMxB5BvJG0oYrDf1WOJZlbXBgunOEj/8KMVbejEur/FpvFsgFQ== + +"@next/swc-darwin-x64@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.2.tgz#f96fb65510be798c03b0432129792c6ac8885bc8" + integrity sha512-x7Afi/jt0ZBRUZHTi49yyej4o8znfIMHO4RvThuoc0P+uli8Jd99y5GKjxoYunPKsXL09xBXEM1+OQy2xEL0Ag== + +"@next/swc-linux-arm64-gnu@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.2.tgz#443f0d4ab9d1aa4338e40f77ca4e182d60e88448" + integrity sha512-zbfPtkk7L41ODMJwSp5VbmPozPmMMQrzAc0HAUomVeVIIwlDGs/UCqLJvLNDt4jpWgc21SjjyIn762lNGrMaUA== + +"@next/swc-linux-arm64-musl@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.2.tgz#182c00b3d2f3ed4eaacdd385d07b230252c64de9" + integrity sha512-wPbS3pI/JU16rm3XdLvvTmlsmm1nd+sBa2ohXgBZcShX4TgOjD4R+RqHKlI1cjo/jDZKXt6OxmcU0Iys0OC/yg== + +"@next/swc-linux-x64-gnu@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.2.tgz#e826a08085dcc61685ff42884ad4032e71ac154f" + integrity sha512-NqWOHqqq8iC9tuHvZxjQ2tX+jWy2X9y8NX2mcB4sj2bIccuCxbIZrU/ThFPZZPauygajZuVQ6zediejQHwZHwQ== + +"@next/swc-linux-x64-musl@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.2.tgz#42f921ca6d93fdfb2b13de70cd8a44ba5526b318" + integrity sha512-lGepHhwb9sGhCcU7999+iK1ZZT+6rrIoVg40MP7DZski9GIZP80wORSbt5kJzh9v2x2ev2lxC6VgwMQT0PcgTA== + +"@next/swc-win32-arm64-msvc@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.2.tgz#9c8f60da8e3882c4c66f21747abf944a627d05ff" + integrity sha512-TZSh/48SfcLEQ4rD25VVn2kdIgUWmMflRX3OiyPwGNXn3NiyPqhqei/BaqCYXViIQ+6QsG9R0C8LftMqy8JPMA== + +"@next/swc-win32-ia32-msvc@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.2.tgz#fdb0b5f74e6dc0dcb34b7f7d24775ad034d915e8" + integrity sha512-M0tBVNMEBJN2ZNQWlcekMn6pvLria7Sa2Fai5znm7CCJz4pP3lrvlSxhKdkCerk0D9E0bqx5yAo3o2Q7RrD4gA== + +"@next/swc-win32-x64-msvc@14.2.2": + version "14.2.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.2.tgz#95cc0dad2c7ac5177fa6eeab070dccfa30532353" + integrity sha512-a/20E/wtTJZ3Ykv3f/8F0l7TtgQa2LWHU2oNB9bsu0VjqGuGGHmm/q6waoUNQYTVPYrrlxxaHjJcDV6aiSTt/w== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@rushstack/eslint-patch@^1.3.3": + version "1.10.3" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz#391d528054f758f81e53210f1a1eebcf1a8b1d20" + integrity sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg== + +"@spree/axios-fetcher@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@spree/axios-fetcher/-/axios-fetcher-1.0.0.tgz#d990ed38ee8bc33706f196a797f90117f8bd4d6d" + integrity sha512-mflTBxdhiYAlVvHqZnzsDOs2w4e3CDIUTa4SvK6X9jZy7VhWhPocS9u8Zo8nsLm77kus2oeq3jcZljbEJEbEhw== + +"@spree/storefront-api-v2-sdk@^6.0.6": + version "6.0.6" + resolved "https://registry.yarnpkg.com/@spree/storefront-api-v2-sdk/-/storefront-api-v2-sdk-6.0.6.tgz#e6b4a847e6409474bfb0f2fbf50308f6570475b6" + integrity sha512-22y90GmxJyIxaXKPmUB/jjMTnlw405B/CIy8jA8ZW9ox2afJTPw6w2Q3tn3pL/M7t/p+IlLIf4jBkoD2oVUSMg== + +"@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/helpers@0.5.5": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.5.tgz#12689df71bfc9b21c4f4ca00ae55f2f16c8b77c0" + integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A== + dependencies: + "@swc/counter" "^0.1.3" + tslib "^2.4.0" + +"@tailwindcss/container-queries@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz#9a759ce2cb8736a4c6a0cb93aeb740573a731974" + integrity sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA== + +"@tailwindcss/typography@^0.5.12": + version "0.5.13" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.13.tgz#cd788a4fa4d0ca2506e242d512f377b22c1f7932" + integrity sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw== + dependencies: + lodash.castarray "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + postcss-selector-parser "6.0.10" + +"@tanstack/react-virtual@^3.0.0-beta.60": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.5.0.tgz#873b5b77cf78af563a4a11e6251ed51ee8868132" + integrity sha512-rtvo7KwuIvqK9zb0VZ5IL7fiJAEnG+0EiFZz8FUOs+2mhGqdGmjKIaT1XU7Zq0eFqL0jonLlhbayJI/J2SA/Bw== + dependencies: + "@tanstack/virtual-core" "3.5.0" + +"@tanstack/virtual-core@3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.5.0.tgz#108208d0f1d75271300bc5560cf9a85a1fa01e89" + integrity sha512-KnPRCkQTyqhanNC0K63GBG3wA8I+D1fQuVnAvcBF8f13akOKeQp1gSbu6f77zCxhEk727iV5oQnbHLYzHrECLg== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/node@20.12.7": + version "20.12.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384" + integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg== + dependencies: + undici-types "~5.26.4" + +"@types/normalize-package-data@^2.4.0": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" + integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== + +"@types/prop-types@*": + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + +"@types/react-dom@18.2.25": + version "18.2.25" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.25.tgz#2946a30081f53e7c8d585eb138277245caedc521" + integrity sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA== + dependencies: + "@types/react" "*" + +"@types/react@*": + version "18.3.2" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.2.tgz#462ae4904973bc212fa910424d901e3d137dbfcd" + integrity sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@types/react@18.2.79": + version "18.2.79" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.79.tgz#c40efb4f255711f554d47b449f796d1c7756d865" + integrity sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.2.0.tgz#44356312aea8852a3a82deebdacd52ba614ec07a" + integrity sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg== + dependencies: + "@typescript-eslint/scope-manager" "7.2.0" + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/typescript-estree" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz#cfb437b09a84f95a0930a76b066e89e35d94e3da" + integrity sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg== + dependencies: + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" + +"@typescript-eslint/types@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.2.0.tgz#0feb685f16de320e8520f13cca30779c8b7c403f" + integrity sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA== + +"@typescript-eslint/typescript-estree@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz#5beda2876c4137f8440c5a84b4f0370828682556" + integrity sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA== + dependencies: + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/visitor-keys@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz#5035f177752538a5750cca1af6044b633610bf9e" + integrity sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A== + dependencies: + "@typescript-eslint/types" "7.2.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@vercel/git-hooks@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@vercel/git-hooks/-/git-hooks-1.0.0.tgz#40ed416e532b868eb0ef77dd7566cd5059dc0fc3" + integrity sha512-OxDFAAdyiJ/H0b8zR9rFCu3BIb78LekBXOphOYG3snV4ULhKFX387pBPpqZ9HLiRTejBWBxYEahkw79tuIgdAA== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-6.2.1.tgz#76c54ce9b081dad39acec4b5d53377913825fb0f" + integrity sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.0.0, ansi-styles@^6.1.0, ansi-styles@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.6, array-includes@^3.1.7: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.findlast@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.findlastindex@^1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.toreversed@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz#b989a6bf35c4c5051e1dc0325151bf8088954eba" + integrity sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz#c8c89348337e51b8a3c48a9227f9ce93ceedcba8" + integrity sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.1.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +autoprefixer@^10.4.19: + version "10.4.19" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.19.tgz#ad25a856e82ee9d7898c59583c1afeb3fa65f89f" + integrity sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew== + dependencies: + browserslist "^4.23.0" + caniuse-lite "^1.0.30001599" + fraction.js "^4.3.7" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axe-core@=4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== + +axios@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.1.tgz#522145622a09dfaf49359837db9649ff245a35b9" + integrity sha512-+LV37nQcd1EpFalkXksWNBiA17NZ5m5/WspmHGmZmdx1qBOg/VNq/c4eRJiA9VQQHBOs+N0ZhhdU10h2TyNK7Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axobject-query@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" + integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== + dependencies: + dequal "^2.0.3" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.23.0: + version "4.23.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== + dependencies: + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +busboy@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599: + version "1.0.30001620" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz#78bb6f35b8fe315b96b8590597094145d0b146b4" + integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew== + +chalk@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2" + integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== + +clean-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7" + integrity sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw== + dependencies: + escape-string-regexp "^1.0.5" + +cli-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" + integrity sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== + dependencies: + restore-cursor "^4.0.0" + +cli-truncate@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" + integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== + dependencies: + slice-ansi "^5.0.0" + string-width "^7.0.0" + +client-only@0.0.1, client-only@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +clsx@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.20: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" + integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +core-js-compat@^3.34.0: + version "3.37.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.1.tgz#c844310c7852f4bdf49b8d339730b97e17ff09ee" + integrity sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg== + dependencies: + browserslist "^4.23.0" + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +debug@4.3.4, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.4.668: + version "1.4.774" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.774.tgz#1017d1758aaeeefe5423aa9d67b4b1e5d1d0a856" + integrity sha512-132O1XCd7zcTkzS3FgkAzKmnBuNJjK8WjcTtNuoylj7MYbqw5eXehjQ5OK91g0zm7OTKIPeaAG4CPoRfD9M1Mg== + +emoji-regex@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" + integrity sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enhanced-resolve@^5.12.0: + version "5.16.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz#e8bc63d51b826d6f1cbc0a150ecb5a8b0c62e567" + integrity sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" + is-callable "^1.2.7" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-iterator-helpers@^1.0.15, es-iterator-helpers@^1.0.17: + version "1.0.19" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + iterator.prototype "^1.1.2" + safe-array-concat "^1.1.2" + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-next@^14.2.2: + version "14.2.3" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.2.3.tgz#2fb0f7c4eccda530a4b5054438162b2303786d4f" + integrity sha512-ZkNztm3Q7hjqvB1rRlOX8P9E/cXRL9ajRcs8jufEtwMfTVYRqnmtnaSu57QqHyBlovMuiB8LEzfLBkh5RYV6Fg== + dependencies: + "@next/eslint-plugin-next" "14.2.3" + "@rushstack/eslint-patch" "^1.3.3" + "@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.28.1" + eslint-plugin-jsx-a11y "^6.7.1" + eslint-plugin-react "^7.33.2" + eslint-plugin-react-hooks "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-import-resolver-typescript@^3.5.2: + version "3.6.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" + integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== + dependencies: + debug "^4.3.4" + enhanced-resolve "^5.12.0" + eslint-module-utils "^2.7.4" + fast-glob "^3.3.1" + get-tsconfig "^4.5.0" + is-core-module "^2.11.0" + is-glob "^4.0.3" + +eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" + integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.28.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" + integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.15.0" + +eslint-plugin-jsx-a11y@^6.7.1: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" + integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== + dependencies: + "@babel/runtime" "^7.23.2" + aria-query "^5.3.0" + array-includes "^3.1.7" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "=4.7.0" + axobject-query "^3.2.1" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + es-iterator-helpers "^1.0.15" + hasown "^2.0.0" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.entries "^1.1.7" + object.fromentries "^2.0.7" + +"eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": + version "4.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" + integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== + +eslint-plugin-react@^7.33.2: + version "7.34.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz#6806b70c97796f5bbfb235a5d3379ece5f4da997" + integrity sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw== + dependencies: + array-includes "^3.1.7" + array.prototype.findlast "^1.2.4" + array.prototype.flatmap "^1.3.2" + array.prototype.toreversed "^1.1.2" + array.prototype.tosorted "^1.1.3" + doctrine "^2.1.0" + es-iterator-helpers "^1.0.17" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.7" + object.fromentries "^2.0.7" + object.hasown "^1.1.3" + object.values "^1.1.7" + prop-types "^15.8.1" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.10" + +eslint-plugin-unicorn@^52.0.0: + version "52.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz#c7a559edd52e3932cf2b3a05c3b0efc604c1eeb8" + integrity sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + "@eslint-community/eslint-utils" "^4.4.0" + "@eslint/eslintrc" "^2.1.4" + ci-info "^4.0.0" + clean-regexp "^1.0.0" + core-js-compat "^3.34.0" + esquery "^1.5.0" + indent-string "^4.0.0" + is-builtin-module "^3.2.1" + jsesc "^3.0.2" + pluralize "^8.0.0" + read-pkg-up "^7.0.1" + regexp-tree "^0.1.27" + regjsparser "^0.10.0" + semver "^7.5.4" + strip-indent "^3.0.0" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.57.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2, esquery@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +execa@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fraction.js@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +geist@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/geist/-/geist-1.3.0.tgz#e22a87478d64ab452c03e4766f8929d76058f93f" + integrity sha512-IoGBfcqVEYB4bEwsfHd35jF4+X9LHRPYZymHL4YOltHSs9LJa24DYs1Z7rEMQ/lsEvaAIc61Y9aUxgcJaQ8lrg== + +get-east-asian-width@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e" + integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== + dependencies: + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + +get-tsconfig@^4.5.0: + version "4.7.5" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.5.tgz#5e012498579e9a6947511ed0cd403272c7acbbaf" + integrity sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw== + dependencies: + resolve-pkg-maps "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@10.3.10: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + +glob@^10.3.10: + version "10.3.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.15.tgz#e72bc61bc3038c90605f5dd48543dc67aaf3b50d" + integrity sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.11.0" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.2.11, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + +ignore@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" + +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + +is-date-object@^1.0.1, is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-fullwidth-code-point@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz#9609efced7c2f97da7b60145ef481c787c7ba704" + integrity sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA== + dependencies: + get-east-asian-width "^1.0.0" + +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== + dependencies: + call-bind "^1.0.7" + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" + +jackspeak@^2.3.5, jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jiti@^1.21.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +language-subtag-registry@^0.3.20: + version "0.3.22" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" + integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== + +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== + dependencies: + language-subtag-registry "^0.3.20" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc" + integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g== + +lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lilconfig@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.1.tgz#9d8a246fa753106cfc205fd2d77042faca56e5e3" + integrity sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lint-staged@^15.2.2: + version "15.2.2" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.2.2.tgz#ad7cbb5b3ab70e043fa05bff82a09ed286bc4c5f" + integrity sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw== + dependencies: + chalk "5.3.0" + commander "11.1.0" + debug "4.3.4" + execa "8.0.1" + lilconfig "3.0.0" + listr2 "8.0.1" + micromatch "4.0.5" + pidtree "0.6.0" + string-argv "0.3.2" + yaml "2.3.4" + +listr2@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.0.1.tgz#4d3f50ae6cec3c62bdf0e94f5c2c9edebd4b9c34" + integrity sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA== + dependencies: + cli-truncate "^4.0.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^6.0.0" + rfdc "^1.3.0" + wrap-ansi "^9.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.castarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + integrity sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +log-update@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.0.0.tgz#0ddeb7ac6ad658c944c1de902993fce7c33f5e59" + integrity sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw== + dependencies: + ansi-escapes "^6.2.0" + cli-cursor "^4.0.0" + slice-ansi "^7.0.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" + +loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^10.2.0: + version "10.2.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" + integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@4.0.5, micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.1: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4: + version "7.1.1" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.1.tgz#f7f85aff59aa22f110b20e27692465cf3bf89481" + integrity sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nanoid@^3.3.6, nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +next@14.2.2: + version "14.2.2" + resolved "https://registry.yarnpkg.com/next/-/next-14.2.2.tgz#707311b5e4bf973ada2305233f322bdd0cd9d579" + integrity sha512-oGwUaa2bCs47FbuxWMpOoXtBMPYpvTPgdZr3UAo+pu7Ns00z9otmYpoeV1HEiYL06AlRQQIA/ypK526KjJfaxg== + dependencies: + "@next/env" "14.2.2" + "@swc/helpers" "0.5.5" + busboy "1.6.0" + caniuse-lite "^1.0.30001579" + graceful-fs "^4.2.11" + postcss "8.4.31" + styled-jsx "5.1.1" + optionalDependencies: + "@next/swc-darwin-arm64" "14.2.2" + "@next/swc-darwin-x64" "14.2.2" + "@next/swc-linux-arm64-gnu" "14.2.2" + "@next/swc-linux-arm64-musl" "14.2.2" + "@next/swc-linux-x64-gnu" "14.2.2" + "@next/swc-linux-x64-musl" "14.2.2" + "@next/swc-win32-arm64-msvc" "14.2.2" + "@next/swc-win32-ia32-msvc" "14.2.2" + "@next/swc-win32-x64-msvc" "14.2.2" + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +npm-run-path@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== + dependencies: + path-key "^4.0.0" + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4, object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +object.fromentries@^2.0.7: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.hasown@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" + integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== + dependencies: + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.values@^1.1.6, object.values@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.10.1, path-scurry@^1.11.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pidtree@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pirates@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-js@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== + dependencies: + camelcase-css "^2.0.1" + +postcss-load-config@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== + dependencies: + lilconfig "^3.0.0" + yaml "^2.3.4" + +postcss-nested@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c" + integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ== + dependencies: + postcss-selector-parser "^6.0.11" + +postcss-selector-parser@6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-selector-parser@^6.0.11: + version "6.0.16" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz#3b88b9f5c5abd989ef4e2fc9ec8eedd34b20fb04" + integrity sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@8.4.31: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.23, postcss@^8.4.38: + version "8.4.38" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" + integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.2.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-plugin-tailwindcss@^0.5.14: + version "0.5.14" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.14.tgz#4482eed357d5e22eac259541c70aca5a4c7b9d5c" + integrity sha512-Puaz+wPUAhFp8Lo9HuciYKM2Y2XExESjeT+9NQoVFXZsPPnc9VYss2SpxdQ6vbatmt8/4+SN0oe0I1cPDABg9Q== + +prettier@3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== + +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-dom@18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react@18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== + dependencies: + pify "^2.3.0" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reflect.getprototypeof@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regexp-tree@^0.1.27: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== + dependencies: + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" + +regjsparser@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.10.0.tgz#b1ed26051736b436f22fdec1c8f72635f9f44892" + integrity sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA== + dependencies: + jsesc "~0.5.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@^1.1.7, resolve@^1.10.0, resolve@^1.22.2, resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-4.0.0.tgz#519560a4318975096def6e609d44100edaa4ccb9" + integrity sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" + integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-regex "^1.1.4" + +scheduler@^0.23.0: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +"semver@2 || 3 || 4 || 5": + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1, set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4, side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1, signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + +slice-ansi@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.0.tgz#cd6b4655e298a8d1bdeb04250a433094b347b9a9" + integrity sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg== + dependencies: + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" + +source-map-js@^1.0.2, source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.17" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" + integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg== + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +string-argv@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: + name string-width-cjs + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string-width@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.1.0.tgz#d994252935224729ea3719c49f7206dc9c46550a" + integrity sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw== + dependencies: + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" + +string.prototype.matchall@^4.0.10: + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" + +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1, strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +styled-jsx@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f" + integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== + dependencies: + client-only "0.0.1" + +sucrase@^3.32.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tailwindcss@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.3.tgz#be48f5283df77dfced705451319a5dffb8621519" + integrity sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^1.0.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.4.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + +typescript@5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +update-browserslist-db@^1.0.13: + version "1.0.16" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356" + integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-builtin-type@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== + dependencies: + function.prototype.name "^1.1.5" + has-tostringtag "^1.0.0" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" + +which-collection@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrap-ansi@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.0.tgz#1a3dc8b70d85eeb8398ddfb1e4a02cd186e58b3e" + integrity sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yaml@2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" + integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== + +yaml@^2.3.4: + version "2.4.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.2.tgz#7a2b30f2243a5fc299e1f14ca58d475ed4bc5362" + integrity sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==