Loading dashboard...
No data available.
} + + {status && ( +OS Uptime: {formatUptime(status.uptime)}
+App Uptime: {formatUptime(status.appStats.uptime)}
+Load Avg: {status.loads?.join(' / ')}
+CPU Cores: {status.cpuCores} ({status.logicalPro} logical)
+CPU Speed: {toFixedIfNecessary(status.cpuSpeedMhz,0)} MHz
+Not available
}Upload: {formatBytes(status.netIO.up)}/s
Download: {formatBytes(status.netIO.down)}/s
Total Sent: {formatBytes(status.netTraffic.sent)}
Total Received: {formatBytes(status.netTraffic.recv)}
TCP: {status.tcpCount}
UDP: {status.udpCount}
IPv4: {status.publicIP.ipv4 || 'N/A'}
IPv6: {status.publicIP.ipv6 || 'N/A'}
dAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJw b z_^v8bbg` SAn{I*4bH$u(RZ6*x UhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=p C^ S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk( $?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU ^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvh CL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c 70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397* _cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111a H}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*I cmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU &68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-= A= yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v #ix45EVrcEhr>!NMhprl $InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~ &^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7< 4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}sc Zlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+ 9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2 `1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M =hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S( O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/new-frontend/src/app/globals.css b/new-frontend/src/app/globals.css new file mode 100644 index 00000000..b5c61c95 --- /dev/null +++ b/new-frontend/src/app/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/new-frontend/src/app/inbounds/.gitkeep b/new-frontend/src/app/inbounds/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/app/inbounds/[id]/clients/page.tsx b/new-frontend/src/app/inbounds/[id]/clients/page.tsx new file mode 100644 index 00000000..d422f5a0 --- /dev/null +++ b/new-frontend/src/app/inbounds/[id]/clients/page.tsx @@ -0,0 +1,297 @@ +"use client"; + +import React, { useEffect, useState, useCallback } from 'react'; +import { useParams, useRouter } from 'next/navigation'; +import { useAuth } from '@/context/AuthContext'; +import { post } from '@/services/api'; +import { Inbound, ClientSetting, Protocol } from '@/types/inbound'; +import { formatBytes } from '@/lib/formatters'; +import ClientFormModal from '@/components/inbounds/ClientFormModal'; +import ClientShareModal from '@/components/inbounds/ClientShareModal'; // Import Share Modal + +// Define button styles locally for consistency +const btnPrimaryStyles = "px-4 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors text-sm"; +const btnTextPrimaryStyles = "text-primary-600 hover:text-primary-800 dark:text-primary-400 dark:hover:text-primary-300 disabled:opacity-50"; +const btnTextDangerStyles = "text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300 disabled:opacity-50"; +const btnTextWarningStyles = "text-yellow-500 hover:text-yellow-700 dark:text-yellow-400 dark:hover:text-yellow-300 disabled:opacity-50"; +const btnTextIndigoStyles = "text-indigo-500 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 disabled:opacity-50"; + + +interface DisplayClient extends ClientSetting { + up?: number; down?: number; actualTotal?: number; + actualExpiryTime?: number; enableClientStat?: boolean; + inboundId?: number; clientTrafficId?: number; + originalIndex?: number; +} + +enum ClientAction { NONE = '', DELETING = 'deleting', RESETTING_TRAFFIC = 'resetting_traffic' } + +const ManageClientsPage: React.FC = () => { + const params = useParams(); + const router = useRouter(); + const { isAuthenticated, isLoading: authLoading } = useAuth(); + const inboundId = parseInt(params.id as string, 10); + + const [inbound, setInbound] = useState (null); + const [displayClients, setDisplayClients] = useState ([]); + const [isLoading, setIsLoading] = useState(true); + const [pageError, setPageError] = useState (null); + + const [isClientFormModalOpen, setIsClientFormModalOpen] = useState(false); + const [editingClient, setEditingClient] = useState (null); + const [clientFormModalError, setClientFormModalError] = useState (null); + const [clientFormModalLoading, setClientFormModalLoading] = useState(false); + + const [isShareModalOpen, setIsShareModalOpen] = useState(false); + const [sharingClient, setSharingClient] = useState (null); + + const [currentAction, setCurrentAction] = useState (ClientAction.NONE); + const [actionTargetEmail, setActionTargetEmail] = useState (null); + const [actionError, setActionError] = useState (null); + + const fetchInboundAndClients = useCallback(async () => { + if (!isAuthenticated || !inboundId) return; + setIsLoading(true); setPageError(null); setActionError(null); + try { + const response = await post ('/inbound/list', {}); + if (response.success && response.data) { + const currentInbound = response.data.find(ib => ib.id === inboundId); + if (currentInbound) { + setInbound(currentInbound); + let definedClients: ClientSetting[] = []; + if (currentInbound.protocol === 'vmess' || currentInbound.protocol === 'vless' || currentInbound.protocol === 'trojan') { + if (currentInbound.settings) { + try { + const parsedSettings = JSON.parse(currentInbound.settings); + if (Array.isArray(parsedSettings.clients)) definedClients = parsedSettings.clients; + } catch (e) { console.error("Error parsing settings:", e); setPageError("Could not parse client definitions."); } + } + } + const mergedClients: DisplayClient[] = definedClients.map((dc, index) => { + const stat = currentInbound.clientStats?.find(cs => cs.email === dc.email); + return { + ...dc, + up: stat?.up, down: stat?.down, actualTotal: stat?.total, + actualExpiryTime: stat?.expiryTime, enableClientStat: stat?.enable, + inboundId: stat?.inboundId, clientTrafficId: stat?.id, + originalIndex: index + }; + }); + currentInbound.clientStats?.forEach(stat => { + if (!mergedClients.find(mc => mc.email === stat.email)) { + mergedClients.push({ + email: stat.email, up: stat.up, down: stat.down, actualTotal: stat.total, + actualExpiryTime: stat.expiryTime, enableClientStat: stat.enable, + inboundId: stat.inboundId, clientTrafficId: stat.id, + }); + } + }); + setDisplayClients(mergedClients); + } else { setPageError('Inbound not found.'); setInbound(null); setDisplayClients([]); } + } else { setPageError(response.message || 'Failed to fetch inbound data.'); setInbound(null); setDisplayClients([]); } + } catch (err) { setPageError(err instanceof Error ? err.message : 'An unknown error occurred.'); setInbound(null); setDisplayClients([]); } + finally { setIsLoading(false); } + }, [isAuthenticated, inboundId]); + + useEffect(() => { + if (!authLoading && isAuthenticated) fetchInboundAndClients(); + else if (!authLoading && !isAuthenticated) { setIsLoading(false); router.push('/auth/login'); } + }, [isAuthenticated, authLoading, fetchInboundAndClients, router]); + + const openAddModal = () => { + setEditingClient(null); setClientFormModalError(null); setIsClientFormModalOpen(true); + }; + const openEditModal = (client: DisplayClient) => { + setEditingClient(client); setClientFormModalError(null); setIsClientFormModalOpen(true); + }; + const openShareModal = (client: ClientSetting) => { // ClientSetting is enough for link generation + setSharingClient(client); setIsShareModalOpen(true); + }; + + + const handleClientFormSubmit = async (submittedClientData: ClientSetting) => { + if (!inbound) { setClientFormModalError("Inbound data not available."); return; } + setClientFormModalLoading(true); setClientFormModalError(null); setActionError(null); + try { + let currentSettings: { clients?: ClientSetting[], [key:string]: unknown } = {}; + try { currentSettings = JSON.parse(inbound.settings || '{}'); } + catch (e) { console.error("Corrupted inbound settings:", e); currentSettings.clients = []; } + + const updatedClients = [...(currentSettings.clients || [])]; + let clientIdentifierForApi: string | undefined; + + if (editingClient && editingClient.originalIndex !== undefined) { + updatedClients[editingClient.originalIndex] = submittedClientData; + clientIdentifierForApi = inbound.protocol === 'trojan' ? editingClient.password : editingClient.id; + if (!clientIdentifierForApi && submittedClientData.password && inbound.protocol === 'trojan') clientIdentifierForApi = submittedClientData.password; + if (!clientIdentifierForApi && submittedClientData.id && (inbound.protocol === 'vmess' || inbound.protocol === 'vless')) clientIdentifierForApi = submittedClientData.id; + } else { + if (updatedClients.some(c => c.email === submittedClientData.email)) { + setClientFormModalError(`Client with email "${submittedClientData.email}" already exists.`); + setClientFormModalLoading(false); return; + } + updatedClients.push(submittedClientData); + } + + const updatedSettingsJson = JSON.stringify({ ...currentSettings, clients: updatedClients }, null, 2); + const payloadForApi: Partial = { ...inbound, id: inbound.id, settings: updatedSettingsJson }; + + let response; + if (editingClient) { + if (!clientIdentifierForApi) { + clientIdentifierForApi = inbound.protocol === 'trojan' ? editingClient?.password : editingClient?.id; + } + if (!clientIdentifierForApi) { + setClientFormModalError("Original client identifier for API is missing for editing."); + setClientFormModalLoading(false); return; + } + response = await post (`/inbound/updateClient/${clientIdentifierForApi}`, payloadForApi); + } else { + response = await post ('/inbound/addClient', payloadForApi); + } + + if (response.success) { + setIsClientFormModalOpen(false); setEditingClient(null); + await fetchInboundAndClients(); + } else { setClientFormModalError(response.message || `Failed to ${editingClient ? 'update' : 'add'} client.`); } + } catch (err) { setClientFormModalError(err instanceof Error ? err.message : `An error occurred.`); } + finally { setClientFormModalLoading(false); } + }; + + const handleDeleteClient = async (clientToDelete: DisplayClient) => { + if (!inbound || !clientToDelete.email) { setActionError("Client or Inbound data is missing."); return; } + const clientApiId = clientToDelete.email; + if (!window.confirm(`Delete client: ${clientToDelete.email}?`)) return; + setCurrentAction(ClientAction.DELETING); setActionTargetEmail(clientToDelete.email); setActionError(null); + try { + const response = await post(`/inbound/${inbound.id}/delClient/${clientApiId}`, {}); + if (response.success) { await fetchInboundAndClients(); } + else { setActionError(response.message || "Failed to delete client."); } + } catch (err) { setActionError(err instanceof Error ? err.message : "Error deleting client."); } + finally { setCurrentAction(ClientAction.NONE); setActionTargetEmail(null); } + }; + + const handleResetClientTraffic = async (clientToReset: DisplayClient) => { + if (!inbound || !clientToReset.email) { setActionError("Client/Inbound data missing."); return; } + if (!window.confirm(`Reset traffic for: ${clientToReset.email}?`)) return; + setCurrentAction(ClientAction.RESETTING_TRAFFIC); setActionTargetEmail(clientToReset.email); setActionError(null); + try { + const response = await post(`/inbound/${inbound.id}/resetClientTraffic/${clientToReset.email}`, {}); + if (response.success) { await fetchInboundAndClients(); } + else { setActionError(response.message || "Failed to reset traffic."); } + } catch (err) { setActionError(err instanceof Error ? err.message : "Error resetting traffic."); } + finally { setCurrentAction(ClientAction.NONE); setActionTargetEmail(null); } + }; + + const getClientIdentifier = (client: DisplayClient, proto: Protocol | undefined): string => proto === 'trojan' ? client.password || 'N/A' : client.id || 'N/A'; + const getClientIdentifierLabel = (proto: Protocol | undefined): string => proto === 'trojan' ? 'Password' : 'UUID'; + + if (isLoading || authLoading) return Loading...; + if (pageError && !inbound) returnError: {pageError}; + if (!inbound && !isLoading) returnInbound not found.; + + const canManageClients = inbound && (inbound.protocol === 'vmess' || inbound.protocol === 'vless' || inbound.protocol === 'trojan' || inbound.protocol === 'shadowsocks'); + + return ( +++ ); +}; +export default ManageClientsPage; diff --git a/new-frontend/src/app/inbounds/[id]/clients/page.tsx.bak-reset-traffic-1748992960 b/new-frontend/src/app/inbounds/[id]/clients/page.tsx.bak-reset-traffic-1748992960 new file mode 100644 index 00000000..c5b2e3a0 --- /dev/null +++ b/new-frontend/src/app/inbounds/[id]/clients/page.tsx.bak-reset-traffic-1748992960 @@ -0,0 +1,267 @@ +"use client"; + +import React, { useEffect, useState, useCallback } from 'react'; +import { useParams, useRouter } from 'next/navigation'; +import { useAuth } from '@/context/AuthContext'; +import { post } from '@/services/api'; +import { Inbound, ClientSetting, Protocol } from '@/types/inbound'; +import { formatBytes } from '@/lib/formatters'; +import ClientFormModal from '@/components/inbounds/ClientFormModal'; + +// Define button styles locally for consistency +const btnPrimaryStyles = "px-4 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors text-sm"; +const btnTextPrimaryStyles = "text-primary-600 hover:text-primary-800 dark:text-primary-400 dark:hover:text-primary-300 disabled:opacity-50"; +const btnTextDangerStyles = "text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300 disabled:opacity-50"; +const btnTextWarningStyles = "text-yellow-500 hover:text-yellow-700 dark:text-yellow-400 dark:hover:text-yellow-300 disabled:opacity-50"; +const btnTextIndigoStyles = "text-indigo-500 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 disabled:opacity-50"; + + +interface DisplayClient extends ClientSetting { + up?: number; down?: number; actualTotal?: number; + actualExpiryTime?: number; enableClientStat?: boolean; + inboundId?: number; clientTrafficId?: number; + originalIndex?: number; +} + +const ManageClientsPage: React.FC = () => { + const params = useParams(); + const router = useRouter(); + const { isAuthenticated, isLoading: authLoading } = useAuth(); + + const inboundId = parseInt(params.id as string, 10); + + const [inbound, setInbound] = useState++ + {pageError && inbound &&+ Clients for: {inbound?.remark || `#${inbound?.id}`} + ({inbound?.protocol}) +
+ {canManageClients && (inbound?.protocol !== 'shadowsocks') && + () + } +Page load error: {pageError} (stale data)} + {actionError &&Action Error: {actionError}} + + {displayClients.length === 0 && !pageError && inbound?.protocol !== 'shadowsocks' &&No clients configured for this inbound.
} + {inbound?.protocol === 'shadowsocks' && ++ For Shadowsocks, client configuration (method and password) is part of the main inbound settings. + The QR code / subscription link below uses these global settings. +
+ } + + {(displayClients.length > 0 || inbound?.protocol === 'shadowsocks') && ( +++ )} + {isClientFormModalOpen && inbound && ( ++ +
++ + + + { (inbound?.protocol === 'shadowsocks') ? ( +Email / Identifier + {(inbound?.protocol !== 'shadowsocks') &&{getClientIdentifierLabel(inbound?.protocol)} } +Traffic (Up/Down) +Quota +Expiry +Status +Actions ++ + ) : displayClients.map((client) => { + const clientActionTargetId = client.email; + const isCurrentActionTarget = actionTargetEmail === clientActionTargetId; + return ( +{inbound.remark || 'Shadowsocks Settings'} +{formatBytes(inbound.up || 0)} / {formatBytes(inbound.down || 0)} +{inbound.total > 0 ? formatBytes(inbound.total) : 'Unlimited'} +{inbound.expiryTime > 0 ? new Date(inbound.expiryTime).toLocaleDateString() : 'Never'} ++ {inbound.enable ? Enabled : Disabled } + ++ + {/* No Edit/Delete/Reset for SS "client" as it's part of inbound config */} + ++ + )})} + +{client.email} +{getClientIdentifier(client, inbound?.protocol)} +{formatBytes(client.up || 0)} / {formatBytes(client.down || 0)} ++ { (client.totalGB !== undefined && client.totalGB > 0) ? formatBytes(client.totalGB * 1024 * 1024 * 1024) : (client.actualTotal !== undefined && client.actualTotal > 0) ? formatBytes(client.actualTotal) : 'Unlimited' } + ++ {client.actualExpiryTime && client.actualExpiryTime > 0 ? new Date(client.actualExpiryTime).toLocaleDateString() : client.expiryTime && client.expiryTime > 0 ? new Date(client.expiryTime).toLocaleDateString() + " (Def)" : 'Never'} + ++ {client.enableClientStat === undefined ? 'N/A' : client.enableClientStat ? + Enabled : + Disabled + } + ++ + + + + +{ setIsClientFormModalOpen(false); setEditingClient(null); }} + onSubmit={handleClientFormSubmit} protocol={inbound.protocol as Protocol} + existingClient={editingClient} formError={clientFormModalError} isLoading={clientFormModalLoading} + /> + )} + {isShareModalOpen && inbound && ( + setIsShareModalOpen(false)} + inbound={inbound} client={sharingClient} + /> + )} + (null); + const [displayClients, setDisplayClients] = useState ([]); + const [isLoading, setIsLoading] = useState(true); // Page loading state + const [pageError, setPageError] = useState (null); + + const [isModalOpen, setIsModalOpen] = useState(false); + const [editingClient, setEditingClient] = useState (null); + const [modalError, setModalError] = useState (null); + const [modalLoading, setModalLoading] = useState(false); // For add/edit operations + + const [actionClientId, setActionClientId] = useState (null); // For delete loading state + const [actionError, setActionError] = useState (null); // For errors during actions like delete + + const fetchInboundAndClients = useCallback(async () => { + if (!isAuthenticated || !inboundId) return; + setIsLoading(true); setPageError(null); setActionError(null); // Clear action error on refresh + try { + const response = await post ('/inbound/list', {}); + if (response.success && response.data) { + const currentInbound = response.data.find(ib => ib.id === inboundId); + if (currentInbound) { + setInbound(currentInbound); + let definedClients: ClientSetting[] = []; + if (currentInbound.protocol === 'vmess' || currentInbound.protocol === 'vless' || currentInbound.protocol === 'trojan') { + if (currentInbound.settings) { + try { + const parsedSettings = JSON.parse(currentInbound.settings); + if (Array.isArray(parsedSettings.clients)) definedClients = parsedSettings.clients; + } catch (e) { console.error("Error parsing settings:", e); setPageError("Could not parse client definitions."); } + } + } + const mergedClients: DisplayClient[] = definedClients.map((dc, index) => { + const stat = currentInbound.clientStats?.find(cs => cs.email === dc.email); + return { + ...dc, + up: stat?.up, down: stat?.down, actualTotal: stat?.total, + actualExpiryTime: stat?.expiryTime, enableClientStat: stat?.enable, + inboundId: stat?.inboundId, clientTrafficId: stat?.id, + originalIndex: index + }; + }); + currentInbound.clientStats?.forEach(stat => { + if (!mergedClients.find(mc => mc.email === stat.email)) { + mergedClients.push({ + email: stat.email, up: stat.up, down: stat.down, actualTotal: stat.total, + actualExpiryTime: stat.expiryTime, enableClientStat: stat.enable, + inboundId: stat.inboundId, clientTrafficId: stat.id, + }); + } + }); + setDisplayClients(mergedClients); + } else { setPageError('Inbound not found.'); setInbound(null); setDisplayClients([]); } + } else { setPageError(response.message || 'Failed to fetch inbound data.'); setInbound(null); setDisplayClients([]); } + } catch (err) { setPageError(err instanceof Error ? err.message : 'An unknown error occurred.'); setInbound(null); setDisplayClients([]); } + finally { setIsLoading(false); } + }, [isAuthenticated, inboundId]); + + useEffect(() => { + if (!authLoading && isAuthenticated) fetchInboundAndClients(); + else if (!authLoading && !isAuthenticated) { setIsLoading(false); router.push('/auth/login'); } + }, [isAuthenticated, authLoading, fetchInboundAndClients, router]); + + const openAddModal = () => { + setEditingClient(null); setModalError(null); setIsModalOpen(true); + }; + + const openEditModal = (client: DisplayClient) => { + setEditingClient(client); setModalError(null); setIsModalOpen(true); + }; + + const handleClientFormSubmit = async (submittedClientData: ClientSetting) => { + if (!inbound) { setModalError("Inbound data not available."); return; } + setModalLoading(true); setModalError(null); setActionError(null); + try { + let currentSettings: { clients?: ClientSetting[], [key:string]: unknown } = {}; + try { currentSettings = JSON.parse(inbound.settings || '{}'); } + catch (e) { console.error("Corrupted inbound settings:", e); currentSettings.clients = []; } + + const updatedClients = [...(currentSettings.clients || [])]; // Changed to const + // clientIdentifierForApi and related logic removed + + if (editingClient && editingClient.originalIndex !== undefined) { + updatedClients[editingClient.originalIndex] = submittedClientData; + } else { // Add mode (or if originalIndex is somehow undefined for an edit - fallback to add) + // Check if client with this email already exists to avoid duplicates if adding + if (!editingClient && updatedClients.some(c => c.email === submittedClientData.email)) { + setModalError(`Client with email ${submittedClientData.email} already exists.`); + setModalLoading(false); + return; + } + updatedClients.push(submittedClientData); + } + + const updatedSettingsJson = JSON.stringify({ ...currentSettings, clients: updatedClients }, null, 2); + const payloadForApi: Partial = { ...inbound, id: inbound.id, settings: updatedSettingsJson }; + + // Using a single update endpoint for simplicity + const response = await post (`/inbound/update/${inbound.id}`, payloadForApi); + + if (response.success) { + setIsModalOpen(false); setEditingClient(null); + await fetchInboundAndClients(); + } else { setModalError(response.message || `Failed to ${editingClient ? 'update' : 'add'} client.`); } + } catch (err) { setModalError(err instanceof Error ? err.message : `An error occurred.`); } + finally { setModalLoading(false); } + }; + + const handleDeleteClient = async (clientToDelete: DisplayClient) => { + if (!inbound) { setActionError("Inbound data not available for delete operation."); return; } + + // For deletion, we need the client's main identifier (email or id/password based on how backend delClient works) + // The backend /inbound/:id/delClient/:clientId expects :clientId to be the user's email. + // This was based on existing panel's behavior (delUser function in controllers). + const clientIdentifierForApi = clientToDelete.email; + + if (!clientIdentifierForApi) { + setActionError("Client email (identifier for API) is missing."); + return; + } + + if (!window.confirm(`Are you sure you want to delete client: ${clientToDelete.email}? This action might also remove associated traffic stats.`)) return; + + setActionClientId(clientIdentifierForApi); // Use email or other unique ID for loading state + setActionError(null); + try { + // API endpoint: /inbound/:id/delClient/:email + const response = await post(`/inbound/${inbound.id}/delClient/${clientIdentifierForApi}`, {}); + if (response.success) { + await fetchInboundAndClients(); // Refresh list + } else { + setActionError(response.message || "Failed to delete client."); + } + } catch (err) { + setActionError(err instanceof Error ? err.message : "An error occurred while deleting client."); + } finally { + setActionClientId(null); + } + }; + + const getClientIdentifier = (client: DisplayClient, proto: Protocol | undefined): string => proto === 'trojan' ? client.password || 'N/A' : client.id || 'N/A'; + const getClientIdentifierLabel = (proto: Protocol | undefined): string => proto === 'trojan' ? 'Password' : 'UUID'; + + if (isLoading || authLoading) return Loading client data...; + if (pageError && !inbound) returnError: {pageError}; + if (!inbound && !isLoading) returnInbound data not available or not found.; + + const canManageClients = inbound && (inbound.protocol === 'vmess' || inbound.protocol === 'vless' || inbound.protocol === 'trojan'); + + return ( +++ ); +}; +export default ManageClientsPage; diff --git a/new-frontend/src/app/inbounds/add/page.tsx b/new-frontend/src/app/inbounds/add/page.tsx new file mode 100644 index 00000000..5a96217d --- /dev/null +++ b/new-frontend/src/app/inbounds/add/page.tsx @@ -0,0 +1,42 @@ +"use client"; +import React, { useState } from 'react'; +import InboundForm from '@/components/inbounds/InboundForm'; +import { Inbound } from '@/types/inbound'; +import { post } from '@/services/api'; +import { useRouter } from 'next/navigation'; + +const AddInboundPage: React.FC = () => { + const [formLoading, setFormLoading] = useState(false); + const [error, setError] = useState++ + {pageError && inbound &&+ Clients for: {inbound?.remark || `#${inbound?.id}`} + ({inbound?.protocol}) +
+ {canManageClients && ( + + )} +Page load error: {pageError} (displaying potentially stale data)} + {actionError &&Action Error: {actionError}} + + + {displayClients.length === 0 && !pageError &&No clients configured for this inbound.
} + + {displayClients.length > 0 && ( +++ )} + {isModalOpen && inbound && ( ++ +
++ + + + {displayClients.map((client) => { + const clientActionId = client.email; // Using email as the unique ID for delete action tracking + return ( +{getClientIdentifierLabel(inbound?.protocol)} } +Traffic (Up/Down) +Quota +Expiry +Status +Actions ++ + )})} + +{client.email} + {canManageClients &&{getClientIdentifier(client, inbound?.protocol)} } +{formatBytes(client.up || 0)} / {formatBytes(client.down || 0)} ++ { (client.totalGB !== undefined && client.totalGB > 0) ? formatBytes(client.totalGB * 1024 * 1024 * 1024) : (client.actualTotal !== undefined && client.actualTotal > 0) ? formatBytes(client.actualTotal) : 'Unlimited' } + ++ {client.actualExpiryTime && client.actualExpiryTime > 0 ? new Date(client.actualExpiryTime).toLocaleDateString() : client.expiryTime && client.expiryTime > 0 ? new Date(client.expiryTime).toLocaleDateString() + " (Def)" : 'Never'} + ++ {client.enableClientStat === undefined ? 'N/A' : client.enableClientStat ? + Enabled : + Disabled + } + ++ {canManageClients && } + {canManageClients && + + } + + {canManageClients && (client.id || client.password) && } + +{ setIsModalOpen(false); setEditingClient(null); }} + onSubmit={handleClientFormSubmit} + protocol={inbound.protocol as Protocol} + existingClient={editingClient} + formError={modalError} + isLoading={modalLoading} + /> + )} + (null); + const router = useRouter(); + + const handleSubmit = async (inboundData: Partial ) => { + setFormLoading(true); + setError(null); + try { + const response = await post ('/inbound/add', inboundData); + if (response.success && response.data) { + router.push('/inbounds'); + } else { + setError(response.message || 'Failed to create inbound.'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'An unknown error occurred.'); + } finally { + setFormLoading(false); + } + }; + + return ( + ++ ); +}; +export default AddInboundPage; diff --git a/new-frontend/src/app/inbounds/edit/[id]/page.tsx b/new-frontend/src/app/inbounds/edit/[id]/page.tsx new file mode 100644 index 00000000..0face4f7 --- /dev/null +++ b/new-frontend/src/app/inbounds/edit/[id]/page.tsx @@ -0,0 +1,97 @@ +"use client"; +import React, { useState, useEffect, useCallback } from 'react'; +import InboundForm from '@/components/inbounds/InboundForm'; +import { Inbound } from '@/types/inbound'; +import { post } from '@/services/api'; +import { useRouter, useParams } from 'next/navigation'; + +const EditInboundPage: React.FC = () => { + const [pageLoading, setPageLoading] = useState(true); + const [formProcessing, setFormProcessing] = useState(false); + const [error, setError] = useStateAdd New Inbound
+ {error && ( ++ {error} ++ )} ++ (null); + const [initialInboundData, setInitialInboundData] = useState (undefined); + const router = useRouter(); + const params = useParams(); + const id = params.id as string; + + const fetchInboundData = useCallback(async () => { + if (!id) { + setError("Inbound ID is missing."); + setPageLoading(false); + return; + } + setPageLoading(true); + setError(null); + try { + // The /inbound/list endpoint returns all inbounds. + // We then find the specific one by ID. + // This is not ideal for a single item fetch but matches current backend capabilities shown. + // A dedicated /inbound/get/{id} would be better. + const response = await post ('/inbound/list', {}); + if (response.success && response.data) { + const numericId = parseInt(id, 10); + const inbound = response.data.find(ib => ib.id === numericId); + if (inbound) { + setInitialInboundData(inbound); + } else { + setError('Inbound not found.'); + } + } else { + setError(response.message || 'Failed to fetch inbound data.'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'An unknown error occurred while fetching data.'); + } finally { + setPageLoading(false); + } + }, [id]); + + useEffect(() => { + fetchInboundData(); + }, [fetchInboundData]); + + const handleSubmit = async (inboundData: Partial ) => { + setFormProcessing(true); + setError(null); + try { + const response = await post (`/inbound/update/${id}`, inboundData); + if (response.success) { + router.push('/inbounds'); + } else { + setError(response.message || 'Failed to update inbound.'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'An unknown error occurred.'); + } finally { + setFormProcessing(false); + } + }; + + if (pageLoading) { + return Loading inbound data...; + } + if (error && !initialInboundData) { + returnError: {error}; + } + if (!initialInboundData && !pageLoading) { + returnInbound not found.; + } + + return ( +++ ); +}; +export default EditInboundPage; diff --git a/new-frontend/src/app/inbounds/page.tsx b/new-frontend/src/app/inbounds/page.tsx new file mode 100644 index 00000000..17660238 --- /dev/null +++ b/new-frontend/src/app/inbounds/page.tsx @@ -0,0 +1,194 @@ +"use client"; + +import React, { useEffect, useState, useCallback } from 'react'; +import { useAuth } from '@/context/AuthContext'; +import { post } from '@/services/api'; // ApiResponse removed +import { InboundFromList } from '@/types/inbound'; // Import the new types +import { formatBytes } from '@/lib/formatters'; // formatUptime removed +import Link from 'next/link'; // For "Add New Inbound" button + +// Simple toggle switch component (can be moved to ui components later) +const ToggleSwitch: React.FC<{ enabled: boolean; onChange: (enabled: boolean) => void; disabled?: boolean }> = ({ enabled, onChange, disabled }) => { + return ( + + ); +}; + + +const InboundsPage: React.FC = () => { + const { isAuthenticated, isLoading: authLoading } = useAuth(); + const [inbounds, setInbounds] = useStateEdit Inbound: {initialInboundData?.remark || id}
+ {error && initialInboundData && ( ++ {error} {/* Show non-critical errors above the form if data is loaded */} ++ )} + {initialInboundData &&} + ([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState (null); + + // Action loading states + const [deletingId, setDeletingId] = useState (null); + const [togglingId, setTogglingId] = useState (null); + + + const fetchInbounds = useCallback(async () => { + if (!isAuthenticated) return; + setIsLoading(true); + try { + const response = await post ('/inbound/list', {}); + if (response.success && response.data) { + setInbounds(response.data); + setError(null); + } else { + setError(response.message || 'Failed to fetch inbounds.'); + setInbounds([]); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'An unknown error occurred.'); + setInbounds([]); + } finally { + setIsLoading(false); + } + }, [isAuthenticated]); + + useEffect(() => { + if (!authLoading && isAuthenticated) { + fetchInbounds(); + } else if (!authLoading && !isAuthenticated) { + setIsLoading(false); + setInbounds([]); + } + }, [isAuthenticated, authLoading, fetchInbounds]); + + const handleToggleEnable = async (inboundId: number, currentEnableStatus: boolean) => { + setTogglingId(inboundId); + // Find the inbound to get all its data for the update + const inboundToUpdate = inbounds.find(ib => ib.id === inboundId); + if (!inboundToUpdate) { + console.error("Inbound not found for toggling"); + setTogglingId(null); + return; + } + + // Create a payload that matches the expected structure for update, + // only changing the 'enable' field. + const payload = { ...inboundToUpdate, enable: !currentEnableStatus }; + + try { + const response = await post (`/inbound/update/${inboundId}`, payload); + if (response.success) { + await fetchInbounds(); // Refresh list + } else { + setError(response.message || 'Failed to update inbound status.'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'Error updating inbound.'); + } finally { + setTogglingId(null); + } + }; + + const handleDeleteInbound = async (inboundId: number) => { + if (!confirm('Are you sure you want to delete this inbound? This action cannot be undone.')) { + return; + } + setDeletingId(inboundId); + try { + const response = await post(`/inbound/del/${inboundId}`, {}); + if (response.success) { + await fetchInbounds(); // Refresh list + } else { + setError(response.message || 'Failed to delete inbound.'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'Error deleting inbound.'); + } finally { + setDeletingId(null); + } + }; + + + if (authLoading || isLoading) { + return Loading inbounds...; + } + + // If not authenticated and not loading auth, show message (AuthContext should redirect anyway) + if (!isAuthenticated && !authLoading) { + returnPlease login to view inbounds.; + } + + + return ( +++ ); +}; + +export default InboundsPage; diff --git a/new-frontend/src/app/layout.tsx b/new-frontend/src/app/layout.tsx new file mode 100644 index 00000000..6bfeb8d8 --- /dev/null +++ b/new-frontend/src/app/layout.tsx @@ -0,0 +1,28 @@ +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; +import MainLayout from '@/components/layout/MainLayout'; +import { AuthProvider } from '@/context/AuthContext'; // Import AuthProvider + +const inter = Inter({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: "3X-UI New Panel", + description: "A new panel for 3X-UI", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + +++ + {error &&Inbounds Management
+ + Add New Inbound + +Error: {error}} + + {inbounds.length === 0 && !error &&No inbounds found.
} + + {inbounds.length > 0 && ( +++ )} ++ +
++ + + + {inbounds.map((inbound) => ( +Remark +Protocol +Port / Listen +Traffic (Up/Down) +Quota +Expiry +Status +Actions ++ + ))} + +{inbound.remark || 'N/A'} +{inbound.protocol} +{inbound.port}{inbound.listen ? ` (${inbound.listen})` : ''} +{formatBytes(inbound.up)} / {formatBytes(inbound.down)} +{inbound.total > 0 ? formatBytes(inbound.total) : 'Unlimited'} ++ {inbound.expiryTime === 0 ? 'Never' : new Date(inbound.expiryTime).toLocaleDateString()} + ++ +handleToggleEnable(inbound.id, inbound.enable)} + disabled={togglingId === inbound.id} + /> + + Edit + + {/* Placeholder for Manage Clients/Details */} + Clients + +{/* Wrap with AuthProvider */} + + + + ); +} diff --git a/new-frontend/src/app/page.tsx b/new-frontend/src/app/page.tsx new file mode 100644 index 00000000..4d8f249f --- /dev/null +++ b/new-frontend/src/app/page.tsx @@ -0,0 +1,13 @@ +import Link from 'next/link'; + +export default function HomePage() { + return ( +{children} +++ ); +} diff --git a/new-frontend/src/app/settings/.gitkeep b/new-frontend/src/app/settings/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/app/settings/page.tsx b/new-frontend/src/app/settings/page.tsx new file mode 100644 index 00000000..f4dc9654 --- /dev/null +++ b/new-frontend/src/app/settings/page.tsx @@ -0,0 +1,199 @@ +"use client"; + +import React, { useEffect, useState, useCallback } from 'react'; +import { useAuth } from '@/context/AuthContext'; +import { post } from '@/services/api'; +import { AllSetting, UpdateUserPayload } from '@/types/settings'; +import PanelSettingsForm from '@/components/settings/PanelSettingsForm'; +import UserAccountSettingsForm from '@/components/settings/UserAccountSettingsForm'; +import TelegramSettingsForm from '@/components/settings/TelegramSettingsForm'; +import SubscriptionSettingsForm from '@/components/settings/SubscriptionSettingsForm'; +import OtherSettingsForm from '@/components/settings/OtherSettingsForm'; // Import the new form + +// Define button styles locally +const btnSecondaryStyles = "px-4 py-2 bg-gray-200 text-gray-800 font-semibold rounded-lg shadow-md hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 transition-colors"; + +interface TabProps { label: string; isActive: boolean; onClick: () => void; } +const Tab: React.FCWelcome to the New 3X-UI Panel
+Experience a fresh new look and feel.
+ + Go to Dashboard + += ({ label, isActive, onClick }) => ( + +); + +const SettingsPage: React.FC = () => { + const { user: authUser, checkAuthState, isAuthenticated, isLoading: authContextLoading } = useAuth(); + const [settings, setSettings] = useState >({}); + const [isLoading, setIsLoading] = useState(true); + const [isSaving, setIsSaving] = useState(false); + const [isUpdatingUser, setIsUpdatingUser] = useState(false); + + const [pageError, setPageError] = useState (null); + const [formError, setFormError] = useState (null); + const [successMessage, setSuccessMessage] = useState (null); + const [activeTab, setActiveTab] = useState ('panel'); + + const fetchSettings = useCallback(async () => { + if (!isAuthenticated) return; + setIsLoading(true); setPageError(null); setFormError(null); + try { + const response = await post ('/setting/all', {}); + if (response.success && response.data) { + setSettings(response.data); + } else { setPageError(response.message || 'Failed to fetch settings.'); } + } catch (err) { setPageError(err instanceof Error ? err.message : 'Unknown error fetching settings.'); } + finally { setIsLoading(false); } + }, [isAuthenticated]); + + useEffect(() => { + if (!authContextLoading && isAuthenticated) fetchSettings(); + else if (!authContextLoading && !isAuthenticated) setIsLoading(false); + }, [isAuthenticated, authContextLoading, fetchSettings]); + + const handleSaveSettings = async (updatedSettingsData: Partial ) => { + setIsSaving(true); setFormError(null); setSuccessMessage(null); + let response; + try { + const fullSettingsPayload = { ...settings, ...updatedSettingsData }; + response = await post('/setting/update', fullSettingsPayload); + if (response.success) { + setSuccessMessage(response.message || 'Settings updated successfully! Some changes may require a panel restart.'); + await fetchSettings(); + } else { setFormError(response.message || 'Failed to update settings.'); } + } catch (err) { setFormError(err instanceof Error ? err.message : 'Unknown error saving settings.'); } + finally { + setIsSaving(false); + if (response?.success) { + setTimeout(()=>setSuccessMessage(null), 5000); + } else { + setTimeout(()=>setFormError(null), 6000); + } + } + }; + + const handleUpdateUserCredentials = async (payload: UpdateUserPayload): Promise => { + setIsUpdatingUser(true); setFormError(null); setSuccessMessage(null); + const finalPayload = { ...payload, oldUsername: payload.oldUsername || authUser?.username }; + let response; + try { + response = await post('/setting/updateUser', finalPayload); + if (response.success) { + setSuccessMessage(response.message || 'User credentials updated. You might need to log in again.'); + await checkAuthState(); + return true; + } else { setFormError(response.message || 'Failed to update user credentials.'); return false; } + } catch (err) { setFormError(err instanceof Error ? err.message : 'Unknown error updating user.'); return false; } + finally { setIsUpdatingUser(false); if (response?.success) setTimeout(()=>setSuccessMessage(null), 5000); if (formError) setTimeout(()=>setFormError(null), 6000);} + }; + + const handleUpdateTwoFactor = async (twoFactorEnabled: boolean) : Promise => { + setIsSaving(true); setFormError(null); setSuccessMessage(null); + let opSuccess = false; + try { + await handleSaveSettings({ twoFactorEnable: twoFactorEnabled }); + if (formError) { // Check if handleSaveSettings set an error + opSuccess = false; + } else { + const refreshed = await post ('/setting/all', {}); + if(refreshed.success && refreshed.data){ + setSettings(refreshed.data); + if(refreshed.data.twoFactorEnable === twoFactorEnabled){ + setSuccessMessage(`2FA status successfully ${twoFactorEnabled ? 'enabled' : 'disabled'}.`); + opSuccess = true; + } else { + setFormError("2FA status change was not reflected after save. Please check."); + } + } else { + setFormError("Failed to re-fetch settings after 2FA update."); + } + } + } catch (err) { + setFormError(err instanceof Error ? err.message : "Error in 2FA update process."); + } finally { + setIsSaving(false); + if (opSuccess) setTimeout(()=>setSuccessMessage(null), 5000); + else if (formError) setTimeout(()=>setFormError(null), 8000); + } + return opSuccess; + }; + + const handleRestartPanel = async () => { + if (!window.confirm("Are you sure you want to restart the panel?")) return; + setIsSaving(true); setFormError(null); setSuccessMessage(null); + try { + const response = await post('/setting/restartPanel', {}); + if (response.success) { + setSuccessMessage(response.message || "Panel is restarting... Please wait and refresh."); + } else { setFormError(response.message || "Failed to restart panel."); } + } catch (err) { setFormError(err instanceof Error ? err.message : "Error restarting panel."); } + finally { setIsSaving(false); if (successMessage) setTimeout(()=>setSuccessMessage(null), 7000); if (formError) setTimeout(()=>setFormError(null), 6000); } + }; + + const onTabChange = (tab: string) => { + setActiveTab(tab); setFormError(null); setSuccessMessage(null); + }; + + const renderSettingsContent = () => { + if (isLoading && !Object.keys(settings).length) return Loading settings data...
; + + switch(activeTab) { + case 'panel': + return; + case 'user': + return ; + case 'telegram': + return ; + case 'subscription': + return ; + case 'other': + return ; + default: + return ; + } + }; + + if (authContextLoading) returnPlease select a settings category.
Loading authentication...; + if (pageError && !Object.keys(settings).length) returnError: {pageError}; + + return ( +++ ); +}; + +export default SettingsPage; diff --git a/new-frontend/src/components/dashboard/StatCard.tsx b/new-frontend/src/components/dashboard/StatCard.tsx new file mode 100644 index 00000000..31cbf735 --- /dev/null +++ b/new-frontend/src/components/dashboard/StatCard.tsx @@ -0,0 +1,21 @@ +import React, { ReactNode } from 'react'; + +interface StatCardProps { + title: string; + children: ReactNode; + className?: string; + actions?: ReactNode; +} + +const StatCard: React.FCPanel Settings
+ + {successMessage &&{successMessage}} + {pageError && !isLoading &&Page Error: {pageError}} + ++ ++ ++ {renderSettingsContent()} ++ ++ ++= ({ title, children, className = '', actions }) => { + return ( + ++ ); +}; +export default StatCard; diff --git a/new-frontend/src/components/dashboard/XrayGeoManagementModal.tsx b/new-frontend/src/components/dashboard/XrayGeoManagementModal.tsx new file mode 100644 index 00000000..3a8662e4 --- /dev/null +++ b/new-frontend/src/components/dashboard/XrayGeoManagementModal.tsx @@ -0,0 +1,191 @@ +"use client"; + +import React, { useState, useEffect, useCallback } from 'react'; +import { post } from '@/services/api'; + +// Define styles locally +const btnSecondaryStyles = "px-3 py-1 text-xs bg-gray-200 text-gray-800 font-semibold rounded-lg shadow-md hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 transition-colors"; + +interface XrayGeoManagementModalProps { + isOpen: boolean; + onClose: () => void; + currentXrayVersion: string | undefined; + onActionComplete: () => Promise{title}
++ {children} ++ {actions &&{actions}} +; // Callback to refresh dashboard status +} + +const GEO_FILES_LIST = [ + "geoip.dat", + "geosite.dat", + "geoip_IR.dat", + "geosite_IR.dat", +]; + +const XrayGeoManagementModal: React.FC = ({ + isOpen, onClose, currentXrayVersion, onActionComplete +}) => { + const [xrayVersions, setXrayVersions] = useState ([]); + const [isLoadingVersions, setIsLoadingVersions] = useState(false); + const [isInstalling, setIsInstalling] = useState (null); + const [isUpdatingFile, setIsUpdatingFile] = useState (null); + const [error, setError] = useState (null); + const [successMessage, setSuccessMessage] = useState (null); + + const [activeTab, setActiveTab] = useState<'xray' | 'geo'>('xray'); + + const fetchXrayVersions = useCallback(async () => { + if (!isOpen) return; // Ensure modal is open before fetching + setIsLoadingVersions(true); setError(null); + try { + // Explicitly type the expected response structure + const response = await post<{ versions?: string[], data?: string[] }>('/server/getXrayVersion', {}); + if (response.success) { + const versionsData = response.data; // data might be string[] or { versions: string[] } + if (Array.isArray(versionsData)) { // Case: data is string[] + setXrayVersions(versionsData); + } else if (versionsData && Array.isArray(versionsData.versions)) { // Case: data is { versions: string[] } + setXrayVersions(versionsData.versions); + } else { + setError('Fetched Xray versions data is not in the expected format.'); + setXrayVersions([]); + } + } else { + setError(response.message || 'Failed to fetch Xray versions.'); + setXrayVersions([]); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'Unknown error fetching versions.'); + setXrayVersions([]); + } finally { + setIsLoadingVersions(false); + } + }, [isOpen]); + + useEffect(() => { + if (isOpen && activeTab === 'xray') { + fetchXrayVersions(); + } + }, [isOpen, activeTab, fetchXrayVersions]); + + const handleInstallXray = async (version: string) => { + if (!window.confirm(`Are you sure you want to install Xray version: ${version}?\nThis will restart Xray service.`)) return; + setIsInstalling(version); setError(null); setSuccessMessage(null); + let response; // Declare response here + try { + response = await post(`/server/installXray/${version}`, {}); + if (response.success) { + setSuccessMessage(response.message || `Xray ${version} installed successfully. Xray service is restarting.`); + onActionComplete(); + } else { + setError(response.message || 'Failed to install Xray version.'); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'Unknown error during Xray installation.'); + } finally { + setIsInstalling(null); + if (response?.success) setTimeout(() => setSuccessMessage(null), 4000); + else if (error) setTimeout(() => setError(null), 4000); // Check local error state + } + }; + + const handleUpdateGeoFile = async (fileName: string) => { + if (!window.confirm(`Are you sure you want to update ${fileName}?\nThis may restart Xray service if changes are detected.`)) return; + setIsUpdatingFile(fileName); setError(null); setSuccessMessage(null); + let response; // Declare response here + try { + response = await post(`/server/updateGeofile/${fileName}`, {}); + if (response.success) { + setSuccessMessage(response.message || `${fileName} updated successfully.`); + onActionComplete(); + } else { + setError(response.message || `Failed to update ${fileName}.`); + } + } catch (err) { + setError(err instanceof Error ? err.message : `Unknown error updating ${fileName}.`); + } finally { + setIsUpdatingFile(null); + if (response?.success) setTimeout(() => setSuccessMessage(null), 4000); + else if (error) setTimeout(() => setError(null), 4000); // Check local error state + } + }; + + const handleClose = () => { + setError(null); + setSuccessMessage(null); + onClose(); + }; + + if (!isOpen) return null; + + return ( + ++ ); +}; +export default XrayGeoManagementModal; diff --git a/new-frontend/src/components/dashboard/XrayStatusIndicator.tsx b/new-frontend/src/components/dashboard/XrayStatusIndicator.tsx new file mode 100644 index 00000000..a9b08d38 --- /dev/null +++ b/new-frontend/src/components/dashboard/XrayStatusIndicator.tsx @@ -0,0 +1,45 @@ +import React from 'react'; + +type ProcessState = "running" | "stop" | "error" | undefined; + +interface XrayStatusIndicatorProps { + state?: ProcessState; + version?: string; + errorMsg?: string; +} + +const XrayStatusIndicator: React.FCe.stopPropagation()}> ++++ + {error &&Xray & Geo Management
+ +{error}} + {successMessage &&{successMessage}} + ++ ++ ++ {activeTab === 'xray' && ( ++++ )} + + {activeTab === 'geo' && ( +Current Xray Version: {currentXrayVersion || 'Unknown'}
+ {isLoadingVersions &&Loading versions...
} + {!isLoadingVersions && xrayVersions.length === 0 && !error &&No versions found or failed to load.
} ++ {xrayVersions.map(version => ( +
+- + {version} + {version === currentXrayVersion ? ( + Current + ) : ( + + )} +
+ ))} +++ )} +Manage GeoIP and GeoSite files.
++ {GEO_FILES_LIST.map(fileName => ( +
+- + {fileName} + +
+ ))} ++ ++= ({ state, version, errorMsg }) => { + let color = 'bg-gray-400'; // Default for undefined or unknown state + let text = 'Unknown'; + + switch (state) { + case 'running': + color = 'bg-green-500'; + text = 'Running'; + break; + case 'stop': + color = 'bg-yellow-500'; + text = 'Stopped'; + break; + case 'error': + color = 'bg-red-500'; + text = 'Error'; + break; + } + + return ( + ++ ); +}; +export default XrayStatusIndicator; diff --git a/new-frontend/src/components/inbounds/ClientFormModal.tsx b/new-frontend/src/components/inbounds/ClientFormModal.tsx new file mode 100644 index 00000000..9ec2f182 --- /dev/null +++ b/new-frontend/src/components/inbounds/ClientFormModal.tsx @@ -0,0 +1,138 @@ +"use client"; + +import React, { useState, useEffect, FormEvent } from 'react'; +import { ClientSetting, Protocol } from '@/types/inbound'; + +// Basic UUID v4 generator +const generateUUID = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); +}); +const generateRandomPassword = (length = 12) => Math.random().toString(36).substring(2, 2 + length); + +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; +const btnPrimaryStyles = "px-4 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors"; +const btnSecondaryStyles = "px-4 py-2 bg-gray-200 text-gray-800 font-semibold rounded-lg shadow-md hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 transition-colors"; + + +interface ClientFormModalProps { + isOpen: boolean; + onClose: () => void; + onSubmit: (client: ClientSetting) => void; + protocol: Protocol; + existingClient?: ClientSetting | null; + formError?: string | null; + isLoading?: boolean; +} + +const ClientFormModal: React.FC+ + {text} ++ {version &&Version: {version}
} + {state === 'error' && errorMsg && ( ++ Error: {errorMsg.length > 100 ? errorMsg.substring(0, 97) + "..." : errorMsg} +
+ )} += ({ + isOpen, onClose, onSubmit, protocol, existingClient = null, formError, isLoading +}) => { + const isEditMode = !!existingClient; + const [email, setEmail] = useState(''); + const [identifier, setIdentifier] = useState(''); + const [flow, setFlow] = useState(''); + const [totalGB, setTotalGB] = useState (0); + const [expiryTime, setExpiryTime] = useState (0); + const [limitIp, setLimitIp] = useState (0); + + useEffect(() => { + if (isOpen) { // Only reset/populate when modal becomes visible or critical props change + if (existingClient) { + setEmail(existingClient.email || ''); + if (protocol === 'trojan') { + setIdentifier(existingClient.password || ''); + } else { // vmess, vless + setIdentifier(existingClient.id || ''); + } + setFlow(existingClient.flow || ''); + setTotalGB(existingClient.totalGB === undefined ? 0 : existingClient.totalGB); + setExpiryTime(existingClient.expiryTime === undefined ? 0 : existingClient.expiryTime); + setLimitIp(existingClient.limitIp === undefined ? 0 : existingClient.limitIp); + } else { + setEmail(''); + setIdentifier(protocol === 'trojan' ? generateRandomPassword() : generateUUID()); + setFlow(protocol === 'vless' ? 'xtls-rprx-vision' : ''); + setTotalGB(0); + setExpiryTime(0); + setLimitIp(0); + } + } + }, [isOpen, existingClient, protocol]); + + if (!isOpen) return null; + + const identifierLabel = protocol === 'trojan' ? 'Password' : 'UUID'; + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + const clientData: ClientSetting = { + email, + flow: protocol === 'vless' ? flow : undefined, + totalGB: Number(totalGB), + expiryTime: Number(expiryTime), + limitIp: Number(limitIp), + }; + if (protocol === 'trojan') { + clientData.password = identifier; + } else { // vmess, vless + clientData.id = identifier; + } + // If editing, preserve original ID if it was a UUID that shouldn't change + if (isEditMode && existingClient?.id && protocol !== 'trojan') { + clientData.id = existingClient.id; + } + onSubmit(clientData); + }; + + return ( + ++ ); +}; +export default ClientFormModal; diff --git a/new-frontend/src/components/inbounds/ClientShareModal.tsx b/new-frontend/src/components/inbounds/ClientShareModal.tsx new file mode 100644 index 00000000..243b3d8b --- /dev/null +++ b/new-frontend/src/components/inbounds/ClientShareModal.tsx @@ -0,0 +1,112 @@ +"use client"; + +import React, { useEffect, useState } from 'react'; +import { Inbound, ClientSetting } from '@/types/inbound'; +import { generateSubscriptionLink } from '@/lib/subscriptionLink'; +import { QRCodeCanvas } from 'qrcode.react'; + +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 select-all"; +const btnSecondaryStyles = "px-4 py-2 bg-gray-200 text-gray-800 font-semibold rounded-lg shadow-md hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 transition-colors text-sm"; + + +interface ClientShareModalProps { + isOpen: boolean; + onClose: () => void; + inbound: Inbound | null; + client: ClientSetting | null; // For client-specific links (vmess, vless, trojan) + // For shadowsocks, client info is mostly in inbound.settings +} + +const ClientShareModal: React.FC+++ {isEditMode ? 'Edit Client' : 'Add New Client'} +
+ {formError &&{formError}
} + += ({ isOpen, onClose, inbound, client }) => { + const [link, setLink] = useState (null); + const [copied, setCopied] = useState(false); + + useEffect(() => { + if (isOpen && inbound) { + // For Shadowsocks, the 'client' might be a conceptual representation derived from inbound settings, + // or we can pass a minimal ClientSetting object. + // The generateSubscriptionLink function expects a ClientSetting object. + // If protocol is shadowsocks and client prop is null, we might need to construct one. + let effectiveClient = client; + if (inbound.protocol === 'shadowsocks' && !client) { + // Construct a conceptual client for shadowsocks if client prop is null + // The link generator for SS primarily uses inbound.settings anyway. + effectiveClient = { email: inbound.remark || 'shadowsocks_client' }; + } + + if (effectiveClient) { + setLink(generateSubscriptionLink(inbound, effectiveClient)); + } else { + setLink(null); + } + setCopied(false); + } + }, [isOpen, inbound, client]); + + if (!isOpen || !inbound) return null; + // If client is null for protocols that require it, link generation will fail. + // This is handled by generateSubscriptionLink returning null. + + const handleCopy = () => { + if (link) { + navigator.clipboard.writeText(link) + .then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }) + .catch(err => console.error('Failed to copy link: ', err)); + } + }; + + return ( + ++ ); +}; +export default ClientShareModal; diff --git a/new-frontend/src/components/inbounds/InboundForm.tsx b/new-frontend/src/components/inbounds/InboundForm.tsx new file mode 100644 index 00000000..d7678a0a --- /dev/null +++ b/new-frontend/src/components/inbounds/InboundForm.tsx @@ -0,0 +1,239 @@ +"use client"; + +import React, { useState, useEffect, FormEvent } from 'react'; +import { Inbound, Protocol, ClientSetting } from '@/types/inbound'; +import { useRouter } from 'next/navigation'; +import ProtocolClientSettings from './ProtocolClientSettings'; +import StreamSettingsForm from './stream_settings/StreamSettingsForm'; // Import new StreamSettingsForm + +const availableProtocols: Protocol[] = ["vmess", "vless", "trojan", "shadowsocks", "dokodemo-door", "socks", "http"]; +const availableShadowsocksCiphers: string[] = [ + "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "xchacha20-poly1305", + "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "none" +]; +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; + +interface InboundFormProps { + initialData?: Partiale.stopPropagation()} // Prevent modal close when clicking inside modal + > ++++ + {link ? ( +Share Client Configuration
+ +++ ) : ( ++++ + +++ + +++ Note: The server address used ("YOUR_SERVER_IP_OR_DOMAIN") is a placeholder. + For this link to work, ensure your actual server address/domain is correctly configured in the generation logic + (
+src/lib/subscriptionLink.ts
) or, ideally, fetched from panel settings in a future update. +Could not generate subscription link for this client/protocol combination.
+ )} + ++ ++; + isEditMode?: boolean; + formLoading?: boolean; + onSubmitForm: (inboundData: Partial ) => Promise ; +} + +const InboundForm: React.FC = ({ initialData, isEditMode = false, formLoading, onSubmitForm }) => { + const router = useRouter(); + const [remark, setRemark] = useState(''); + const [listen, setListen] = useState(''); + const [port, setPort] = useState (''); + const [protocol, setProtocol] = useState (''); + const [enable, setEnable] = useState(true); + const [expiryTime, setExpiryTime] = useState (0); + const [total, setTotal] = useState (0); + + const [clientList, setClientList] = useState ([]); + const [ssMethod, setSsMethod] = useState(availableShadowsocksCiphers[0]); + const [ssPassword, setSsPassword] = useState(''); + + const [settingsJson, setSettingsJson] = useState('{}'); + const [streamSettingsJson, setStreamSettingsJson] = useState('{}'); + const [sniffingJson, setSniffingJson] = useState('{}'); + + const [formError, setFormError] = useState (null); + + useEffect(() => { + if (initialData) { + const currentProtocol = (initialData.protocol || '') as Protocol; + setRemark(initialData.remark || ''); + setListen(initialData.listen || ''); + setPort(initialData.port || ''); + setProtocol(currentProtocol); + setEnable(initialData.enable !== undefined ? initialData.enable : true); + setExpiryTime(initialData.expiryTime || 0); + setTotal(initialData.total && initialData.total > 0 ? initialData.total / (1024 * 1024 * 1024) : 0); + + setStreamSettingsJson(initialData.streamSettings || '{}'); + setSniffingJson(initialData.sniffing || '{}'); + + const initialSettings = initialData.settings || '{}'; + setSettingsJson(initialSettings); // Initialize settingsJson with all settings + + if ((currentProtocol === 'vmess' || currentProtocol === 'vless' || currentProtocol === 'trojan')) { + try { + const parsedSettings = JSON.parse(initialSettings); + setClientList(parsedSettings.clients || []); + } catch (e) { console.error(`Error parsing settings for ${currentProtocol}:`, e); setClientList([]); } + } else if (currentProtocol === 'shadowsocks') { + try { + const parsedSettings = JSON.parse(initialSettings); + setSsMethod(parsedSettings.method || availableShadowsocksCiphers[0]); + setSsPassword(parsedSettings.password || ''); + } catch (e) { console.error("Error parsing Shadowsocks settings:", e); } + } else { + // For other protocols, specific UI states are not used for settings + setClientList([]); + setSsMethod(availableShadowsocksCiphers[0]); setSsPassword(''); + } + } else { + // Reset all fields for a new form + setRemark(''); setListen(''); setPort(''); setProtocol(''); setEnable(true); + setExpiryTime(0); setTotal(0); setClientList([]); + setSsMethod(availableShadowsocksCiphers[0]); setSsPassword(''); + setSettingsJson('{}'); setStreamSettingsJson('{}'); setSniffingJson('{}'); + } + }, [initialData]); + + // This useEffect updates settingsJson based on UI changes for client lists or SS settings + useEffect(() => { + if (protocol === 'vmess' || protocol === 'vless' || protocol === 'trojan' || protocol === 'shadowsocks') { + let baseSettings: Record = {}; + try { + baseSettings = JSON.parse(settingsJson) || {}; // Preserve other settings + } catch { /* If settingsJson is invalid, it will be overwritten */ } + + const newSettingsObject = { ...baseSettings }; // Changed to const + + if (protocol === 'vmess' || protocol === 'vless' || protocol === 'trojan') { + delete newSettingsObject.method; delete newSettingsObject.password; + newSettingsObject.clients = clientList; + } else if (protocol === 'shadowsocks') { + delete newSettingsObject.clients; + newSettingsObject.method = ssMethod; + newSettingsObject.password = ssPassword; + } + + try { + const finalJson = JSON.stringify(newSettingsObject, null, 2); + if (finalJson !== settingsJson) { // Only update if there's an actual change + setSettingsJson(finalJson); + } + } catch (e) { console.error("Error stringifying settings:", e); } + } + // No 'else' needed: for other protocols, settingsJson is managed by its textarea directly. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [clientList, ssMethod, ssPassword, protocol]); // settingsJson is NOT a dependency here. + + + const handleProtocolChange = (newProtocol: Protocol) => { + setProtocol(newProtocol); + setFormError(null); + + // When protocol changes, re-initialize specific UI states from current settingsJson + let currentSettings: Record = {}; // Changed any to unknown + try { currentSettings = JSON.parse(settingsJson || '{}'); } catch {} + + if (newProtocol === 'vmess' || newProtocol === 'vless' || newProtocol === 'trojan') { + if (Array.isArray(currentSettings.clients)) { + setClientList(currentSettings.clients as ClientSetting[]); + } else { + setClientList([]); + } + setSsMethod(availableShadowsocksCiphers[0]); setSsPassword(''); + } else if (newProtocol === 'shadowsocks') { + setClientList([]); + if (typeof currentSettings.method === 'string') { + setSsMethod(currentSettings.method); + } else { + setSsMethod(availableShadowsocksCiphers[0]); + } + if (typeof currentSettings.password === 'string') { + setSsPassword(currentSettings.password); + } else { + setSsPassword(''); + } + } else { + // For "other" protocols, clear all specific UI states + setClientList([]); + setSsMethod(availableShadowsocksCiphers[0]); setSsPassword(''); + // settingsJson remains as is, for manual editing + } + }; + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); setFormError(null); + if (!protocol) { setFormError("Protocol is required."); return; } + if (port === '' || Number(port) <= 0 || Number(port) > 65535) { setFormError("Valid Port (1-65535) is required."); return; } + + // settingsJson should already be up-to-date from the useEffect hook + // for vmess/vless/trojan/shadowsocks. + // For other protocols, it's taken directly from its textarea. + if (protocol === 'shadowsocks' && !ssPassword) { + setFormError("Password is required for Shadowsocks."); return; + } + + // Validate all JSON fields before submitting + for (const [fieldName, jsonStr] of Object.entries({ settings: settingsJson, streamSettings: streamSettingsJson, sniffing: sniffingJson })) { + try { JSON.parse(jsonStr); } catch (err) { + setFormError(`Invalid JSON in ${fieldName === 'settings' ? 'protocol settings' : fieldName}: ${(err as Error).message}`); return; + } + } + + const inboundData: Partial = { + remark, listen, port: Number(port), protocol, enable, + expiryTime: Number(expiryTime), total: Number(total) * 1024 * 1024 * 1024, + settings: settingsJson, streamSettings: streamSettingsJson, sniffing: sniffingJson, + }; + + if (isEditMode && initialData?.id) { + inboundData.id = initialData.id; + inboundData.up = initialData.up; inboundData.down = initialData.down; + } + await onSubmitForm(inboundData); + }; + + return ( + + ); +}; +export default InboundForm; diff --git a/new-frontend/src/components/inbounds/ProtocolClientListItem.tsx b/new-frontend/src/components/inbounds/ProtocolClientListItem.tsx new file mode 100644 index 00000000..ca5664ec --- /dev/null +++ b/new-frontend/src/components/inbounds/ProtocolClientListItem.tsx @@ -0,0 +1,94 @@ +"use client"; + +import React, { useState, useEffect } from 'react'; +import { ClientSetting, Protocol } from '@/types/inbound'; // Assuming Protocol is also in types + +interface ProtocolClientListItemProps { + client: ClientSetting; + index: number; + onUpdateClient: (index: number, updatedClient: ClientSetting) => void; + onRemoveClient: (index: number) => void; + protocol: Protocol; // Now includes 'trojan' +} + +// Helper function to apply input styles directly +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; + +const ProtocolClientListItem: React.FC = ({ client, index, onUpdateClient, onRemoveClient, protocol }) => { + const [isEditing, setIsEditing] = useState(false); + const [editableClient, setEditableClient] = useState (client); + + useEffect(() => { + setEditableClient(client); + }, [client]); + + const handleInputChange = (e: React.ChangeEvent ) => { + const { name, value, type } = e.target; + let processedValue: string | number | boolean = value; + if (type === 'number') { + processedValue = value === '' ? '' : Number(value); + } + setEditableClient(prev => ({ ...prev, [name]: processedValue })); + }; + + const handleSave = () => { + onUpdateClient(index, editableClient); + setIsEditing(false); + }; + + const clientIdentifierField = protocol === 'trojan' ? 'password' : 'id'; + const clientIdentifierLabel = protocol === 'trojan' ? 'Password:' : 'UUID:'; + + return ( + + {isEditing ? ( + <> ++ ); +}; +export default ProtocolClientListItem; diff --git a/new-frontend/src/components/inbounds/ProtocolClientSettings.tsx b/new-frontend/src/components/inbounds/ProtocolClientSettings.tsx new file mode 100644 index 00000000..21781c51 --- /dev/null +++ b/new-frontend/src/components/inbounds/ProtocolClientSettings.tsx @@ -0,0 +1,78 @@ +"use client"; + +import React from 'react'; +import { ClientSetting, Protocol } from '@/types/inbound'; +import ProtocolClientListItem from './ProtocolClientListItem'; // Updated import + +const generateRandomId = (length = 8) => Math.random().toString(36).substring(2, 2 + length); +const generateUUID = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); + return v.toString(16); +}); + +interface ProtocolClientSettingsProps { + clients: ClientSetting[]; + onChange: (clients: ClientSetting[]) => void; + protocol: Protocol; // Now 'vmess', 'vless', or 'trojan' +} + +const ProtocolClientSettings: React.FC+ + +++ + ++ {protocol === 'vless' && ( // Only show flow for VLESS ++ + ++ )} ++ + +++ + +++ + +++ + ++ > + ) : ( + <> +Email: {client.email}
+{clientIdentifierLabel} {clientIdentifierField === 'id' ? client.id : client.password}
+ {client.flow && protocol === 'vless' &&Flow: {client.flow}
} + {client.totalGB !== undefined &&Quota: {client.totalGB > 0 ? `${client.totalGB} GB` : 'Unlimited'}
} + {client.expiryTime !== undefined &&Expiry: {client.expiryTime > 0 ? new Date(client.expiryTime).toLocaleDateString() : 'Never'}
} + {client.limitIp !== undefined &&IP Limit: {client.limitIp > 0 ? client.limitIp : 'Unlimited'}
} ++ + ++ > + )} += ({ clients, onChange, protocol }) => { + + const addClient = () => { + const newClientBase: Partial = { + email: `user${clients.length + 1}@example.com`, + totalGB: 0, + expiryTime: 0, + limitIp: 0, + }; + + let newClientSpecific: Partial = {}; + if (protocol === 'vmess' || protocol === 'vless') { + newClientSpecific = { + id: generateUUID(), + flow: protocol === 'vless' ? 'xtls-rprx-vision' : undefined, // Ensure flow is undefined for vmess + }; + } else if (protocol === 'trojan') { + newClientSpecific = { + password: generateRandomId(12), + }; + } + onChange([...clients, { ...newClientBase, ...newClientSpecific } as ClientSetting]); + }; + + const updateClient = (index: number, updatedClient: ClientSetting) => { + const newClients = [...clients]; + newClients[index] = updatedClient; + onChange(newClients); + }; + + const removeClient = (index: number) => { + const newClients = clients.filter((_, i) => i !== index); + onChange(newClients); + }; + + return ( + ++ ); +}; +export default ProtocolClientSettings; diff --git a/new-frontend/src/components/inbounds/stream_settings/StreamSettingsForm.tsx b/new-frontend/src/components/inbounds/stream_settings/StreamSettingsForm.tsx new file mode 100644 index 00000000..0af13525 --- /dev/null +++ b/new-frontend/src/components/inbounds/stream_settings/StreamSettingsForm.tsx @@ -0,0 +1,127 @@ +"use client"; + +import React, { useState, useEffect, useCallback } from 'react'; + +type NetworkType = "tcp" | "kcp" | "ws" | "http" | "grpc" | "quic" | ""; +type SecurityType = "none" | "tls" | "reality" | ""; + +interface StreamSettingsFormProps { + initialStreamSettingsJson: string; + onChange: (newJsonString: string) => void; +} + +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; + +const StreamSettingsForm: React.FCClients
+ {clients.length === 0 &&No clients configured. Click "Add Client" to begin.
} + {clients.map((client, index) => ( ++ ))} + + = ({ initialStreamSettingsJson, onChange }) => { + const [network, setNetwork] = useState (''); + const [security, setSecurity] = useState ('none'); + const [specificSettingsJson, setSpecificSettingsJson] = useState('{}'); + const [error, setError] = useState (''); + + const parseAndSetStates = useCallback((jsonString: string) => { + try { + const parsed = jsonString && jsonString.trim() !== "" ? JSON.parse(jsonString) : {}; + setNetwork(parsed.network || ''); + setSecurity(parsed.security || 'none'); + + // Destructure again to get 'rest' after 'network' and 'security' have been read + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { network: _, security: __, ...rest } = parsed; + setSpecificSettingsJson(Object.keys(rest).length > 0 ? JSON.stringify(rest, null, 2) : '{}'); + setError(''); + } catch (err) { // Use err + setError('Stream Settings JSON is invalid. Displaying raw content for correction.'); + setSpecificSettingsJson(jsonString); + console.error("Error parsing initial stream settings:", err); // Log error + } + }, []); + + useEffect(() => { + parseAndSetStates(initialStreamSettingsJson); + }, [initialStreamSettingsJson, parseAndSetStates]); + + const reconstructAndCallback = useCallback(() => { + try { + const specificParsed = JSON.parse(specificSettingsJson || '{}'); + const combined: Record = {}; // Use Record + if (network) combined.network = network; + if (security && security !== 'none') combined.security = security; + + const finalCombined = { ...specificParsed, ...combined }; + if (!finalCombined.network) delete finalCombined.network; + if (!finalCombined.security) delete finalCombined.security; + + + const finalJsonString = Object.keys(finalCombined).length === 0 ? '{}' : JSON.stringify(finalCombined, null, 2); + onChange(finalJsonString); + setError(''); + } catch (err) { // Use err + setError('Invalid JSON in specific settings details. Fix to see combined output.'); + console.error("Error reconstructing stream settings JSON:", err); // Log error + } + }, [network, security, specificSettingsJson, onChange]); + + useEffect(() => { + reconstructAndCallback(); + }, [network, security, specificSettingsJson, reconstructAndCallback]); + + const handleSpecificSettingsChange = (e: React.ChangeEvent ) => { + setSpecificSettingsJson(e.target.value); + }; + + return ( + + {error &&+ ); +}; +export default StreamSettingsForm; diff --git a/new-frontend/src/components/layout/.gitkeep b/new-frontend/src/components/layout/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/components/layout/Header.tsx b/new-frontend/src/components/layout/Header.tsx new file mode 100644 index 00000000..6f3232a8 --- /dev/null +++ b/new-frontend/src/components/layout/Header.tsx @@ -0,0 +1,36 @@ +"use client"; +import React from 'react'; + +interface HeaderProps { + toggleSidebar: () => void; + toggleTheme: () => void; + currentTheme: string; +} + +const Header: React.FC{error}
} ++++ + +++ + +++ +++ Edit the JSON details for the selected network/security type here. + The 'network' and 'security' fields above will be included in the final JSON. +
+ += ({ toggleSidebar, toggleTheme, currentTheme }) => { + return ( + + + ); +}; +export default Header; diff --git a/new-frontend/src/components/layout/MainLayout.tsx b/new-frontend/src/components/layout/MainLayout.tsx new file mode 100644 index 00000000..4b5d59fb --- /dev/null +++ b/new-frontend/src/components/layout/MainLayout.tsx @@ -0,0 +1,66 @@ +"use client"; +import React, { useState, useEffect } from 'react'; +import { usePathname } from 'next/navigation'; // Import usePathname +import Header from './Header'; +import Sidebar from './Sidebar'; + +const MainLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [sidebarOpen, setSidebarOpen] = useState(false); + const [theme, setTheme] = useState('light'); + const pathname = usePathname(); // Get current path + + // Determine if the current path is an authentication-related page + const isAuthPage = pathname.startsWith('/auth'); + + useEffect(() => { + const storedTheme = localStorage.getItem('theme'); + if (storedTheme) { + setTheme(storedTheme); + } else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + setTheme('dark'); + } + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + const handleChange = (e: MediaQueryListEvent) => { + if (!localStorage.getItem('theme')) { + setTheme(e.matches ? 'dark' : 'light'); + } + }; + mediaQuery.addEventListener('change', handleChange); + return () => mediaQuery.removeEventListener('change', handleChange); + }, []); + + useEffect(() => { + if (theme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + localStorage.setItem('theme', theme); + }, [theme]); + + const toggleSidebar = () => { + setSidebarOpen(!sidebarOpen); + }; + + const toggleTheme = () => { + setTheme(theme === 'light' ? 'dark' : 'light'); + }; + + // If it's an auth page, render children directly without main layout + if (isAuthPage) { + return <>{children}>; + } + + return ( ++ {/* Burger menu for mobile */} + ++3X-UI Panel
+ +++ ); +}; +export default MainLayout; diff --git a/new-frontend/src/components/layout/Sidebar.tsx b/new-frontend/src/components/layout/Sidebar.tsx new file mode 100644 index 00000000..cd4ef43d --- /dev/null +++ b/new-frontend/src/components/layout/Sidebar.tsx @@ -0,0 +1,69 @@ +"use client"; +import React from 'react'; +import Link from 'next/link'; +import { useAuth } from '@/context/AuthContext'; // Import useAuth + +interface SidebarProps { + isOpen: boolean; + toggleSidebar: () => void; +} + +const navItems = [ + { name: 'Dashboard', href: '/dashboard', icon: 'D' }, + { name: 'Inbounds', href: '/inbounds', icon: 'I' }, + { name: 'Settings', href: '/settings', icon: 'S' }, +]; + +const Sidebar: React.FC+ +++ + {children} + += ({ isOpen, toggleSidebar }) => { + const { logout, isLoading, user } = useAuth(); // Added user to display username + + const handleLogout = async () => { + await logout(); + }; + + return ( + <> + {isOpen && ( + + )} + + > + ); +}; +export default Sidebar; diff --git a/new-frontend/src/components/settings/OtherSettingsForm.tsx b/new-frontend/src/components/settings/OtherSettingsForm.tsx new file mode 100644 index 00000000..00f7ca33 --- /dev/null +++ b/new-frontend/src/components/settings/OtherSettingsForm.tsx @@ -0,0 +1,129 @@ +"use client"; + +import React, { useState, useEffect, FormEvent } from 'react'; +import { AllSetting } from '@/types/settings'; + +// Define styles locally +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; +const btnPrimaryStyles = "px-6 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors"; + +interface OtherSettingsFormProps { + initialSettings: Partial ; + onSave: (updatedSettings: Partial ) => Promise ; + isLoading: boolean; + formError?: string | null; +} + +const OtherSettingsForm: React.FC = ({ + initialSettings, onSave, isLoading, formError +}) => { + const [remarkModel, setRemarkModel] = useState(''); + const [expireDiff, setExpireDiff] = useState (''); + const [trafficDiff, setTrafficDiff] = useState (''); + const [externalTrafficInformEnable, setExternalTrafficInformEnable] = useState(false); + const [externalTrafficInformURI, setExternalTrafficInformURI] = useState(''); + + useEffect(() => { + setRemarkModel(initialSettings.remarkModel || ''); + setExpireDiff(initialSettings.expireDiff === undefined ? '' : initialSettings.expireDiff); + setTrafficDiff(initialSettings.trafficDiff === undefined ? '' : initialSettings.trafficDiff); + setExternalTrafficInformEnable(initialSettings.externalTrafficInformEnable || false); + setExternalTrafficInformURI(initialSettings.externalTrafficInformURI || ''); + }, [initialSettings]); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + const updatedOtherSettings: Partial = { + ...initialSettings, + remarkModel, + expireDiff: Number(expireDiff) || 0, + trafficDiff: Number(trafficDiff) || 0, + externalTrafficInformEnable, + externalTrafficInformURI, + }; + onSave(updatedOtherSettings); + }; + + return ( + + ); +}; +export default OtherSettingsForm; diff --git a/new-frontend/src/components/settings/PanelSettingsForm.tsx b/new-frontend/src/components/settings/PanelSettingsForm.tsx new file mode 100644 index 00000000..53e30716 --- /dev/null +++ b/new-frontend/src/components/settings/PanelSettingsForm.tsx @@ -0,0 +1,133 @@ +"use client"; + +import React, { useState, useEffect, FormEvent } from 'react'; +import { AllSetting } from '@/types/settings'; + +// Define inputStyles locally +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; +const btnPrimaryStyles = "px-6 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors"; + + +interface PanelSettingsFormProps { + initialSettings: Partial ; + onSave: (updatedSettings: Partial ) => Promise ; + isLoading: boolean; + formError?: string | null; +} + +const PanelSettingsForm: React.FC = ({ initialSettings, onSave, isLoading, formError }) => { + const [webListen, setWebListen] = useState(''); + const [webDomain, setWebDomain] = useState(''); + const [webPort, setWebPort] = useState (''); + const [webCertFile, setWebCertFile] = useState(''); + const [webKeyFile, setWebKeyFile] = useState(''); + const [webBasePath, setWebBasePath] = useState(''); + const [sessionMaxAge, setSessionMaxAge] = useState (''); + const [pageSize, setPageSize] = useState (''); + const [timeLocation, setTimeLocation] = useState(''); + const [datepicker, setDatepicker] = useState<'gregorian' | 'jalali' | string>('gregorian'); + + useEffect(() => { + setWebListen(initialSettings.webListen || ''); + setWebDomain(initialSettings.webDomain || ''); + setWebPort(initialSettings.webPort || ''); + setWebCertFile(initialSettings.webCertFile || ''); + setWebKeyFile(initialSettings.webKeyFile || ''); + setWebBasePath(initialSettings.webBasePath || ''); + setSessionMaxAge(initialSettings.sessionMaxAge || ''); + setPageSize(initialSettings.pageSize || 10); // Default page size + setTimeLocation(initialSettings.timeLocation || 'Asia/Tehran'); + setDatepicker(initialSettings.datepicker || 'gregorian'); + }, [initialSettings]); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + const updatedPanelSettings: Partial = { + // It's crucial to only send fields that this form is responsible for, + // or ensure the backend handles partial updates correctly without nullifying other settings. + // For /setting/update, we send the whole AllSettings object usually. + // So, merge with initialSettings to keep other tabs' data. + ...initialSettings, + webListen, + webDomain, + webPort: Number(webPort) || undefined, + webCertFile, + webKeyFile, + webBasePath, + sessionMaxAge: Number(sessionMaxAge) || undefined, + pageSize: Number(pageSize) || undefined, + timeLocation, + datepicker, + }; + onSave(updatedPanelSettings); + }; + + return ( + + ); +}; +export default PanelSettingsForm; diff --git a/new-frontend/src/components/settings/SubscriptionSettingsForm.tsx b/new-frontend/src/components/settings/SubscriptionSettingsForm.tsx new file mode 100644 index 00000000..a6ba4258 --- /dev/null +++ b/new-frontend/src/components/settings/SubscriptionSettingsForm.tsx @@ -0,0 +1,163 @@ +"use client"; + +import React, { useState, useEffect, FormEvent } from 'react'; +import { AllSetting } from '@/types/settings'; + +// Define styles locally +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; +const btnPrimaryStyles = "px-6 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors"; + +interface SubscriptionSettingsFormProps { + initialSettings: Partial ; + onSave: (updatedSettings: Partial ) => Promise ; + isLoading: boolean; + formError?: string | null; +} + +const SubscriptionSettingsForm: React.FC = ({ + initialSettings, onSave, isLoading, formError +}) => { + const [subEnable, setSubEnable] = useState(false); + const [subTitle, setSubTitle] = useState(''); + const [subListen, setSubListen] = useState(''); + const [subPort, setSubPort] = useState (''); + const [subPath, setSubPath] = useState(''); + const [subDomain, setSubDomain] = useState(''); + const [subCertFile, setSubCertFile] = useState(''); + const [subKeyFile, setSubKeyFile] = useState(''); + const [subUpdates, setSubUpdates] = useState (''); + const [subEncrypt, setSubEncrypt] = useState(false); + const [subShowInfo, setSubShowInfo] = useState(false); + + const [subURI, setSubURI] = useState(''); + const [subJsonPath, setSubJsonPath] = useState(''); + const [subJsonURI, setSubJsonURI] = useState(''); + const [subJsonFragment, setSubJsonFragment] = useState(''); + const [subJsonNoises, setSubJsonNoises] = useState(''); + const [subJsonMux, setSubJsonMux] = useState(''); + const [subJsonRules, setSubJsonRules] = useState(''); + + useEffect(() => { + setSubEnable(initialSettings.subEnable || false); + setSubTitle(initialSettings.subTitle || ''); + setSubListen(initialSettings.subListen || ''); + setSubPort(initialSettings.subPort === undefined ? '' : initialSettings.subPort); + setSubPath(initialSettings.subPath || ''); + setSubDomain(initialSettings.subDomain || ''); + setSubCertFile(initialSettings.subCertFile || ''); + setSubKeyFile(initialSettings.subKeyFile || ''); + setSubUpdates(initialSettings.subUpdates === undefined ? '' : initialSettings.subUpdates); + setSubEncrypt(initialSettings.subEncrypt || false); + setSubShowInfo(initialSettings.subShowInfo || false); + + setSubURI(initialSettings.subURI || ''); + setSubJsonPath(initialSettings.subJsonPath || ''); + setSubJsonURI(initialSettings.subJsonURI || ''); + setSubJsonFragment(initialSettings.subJsonFragment || ''); + setSubJsonNoises(initialSettings.subJsonNoises || ''); + setSubJsonMux(initialSettings.subJsonMux || ''); + setSubJsonRules(initialSettings.subJsonRules || ''); + }, [initialSettings]); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + const updatedSubSettings: Partial = { + ...initialSettings, + subEnable, subTitle, subListen, + subPort: Number(subPort) || undefined, + subPath, subDomain, subCertFile, subKeyFile, + subUpdates: Number(subUpdates) || undefined, + subEncrypt, subShowInfo, + subURI, subJsonPath, subJsonURI, subJsonFragment, + subJsonNoises, subJsonMux, subJsonRules, + }; + onSave(updatedSubSettings); + }; + + return ( + + ); +}; +export default SubscriptionSettingsForm; diff --git a/new-frontend/src/components/settings/TelegramSettingsForm.tsx b/new-frontend/src/components/settings/TelegramSettingsForm.tsx new file mode 100644 index 00000000..c815d9f4 --- /dev/null +++ b/new-frontend/src/components/settings/TelegramSettingsForm.tsx @@ -0,0 +1,136 @@ +"use client"; + +import React, { useState, useEffect, FormEvent } from 'react'; +import { AllSetting } from '@/types/settings'; + +// Define styles locally +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; +const btnPrimaryStyles = "px-6 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors"; + +interface TelegramSettingsFormProps { + initialSettings: Partial ; + onSave: (updatedSettings: Partial ) => Promise ; + isLoading: boolean; + formError?: string | null; +} + +const availableTgLangs = ["en", "fa", "ru", "zh-cn"]; // Example languages + +const TelegramSettingsForm: React.FC = ({ + initialSettings, onSave, isLoading, formError +}) => { + const [tgBotEnable, setTgBotEnable] = useState(false); + const [tgBotToken, setTgBotToken] = useState(''); + const [tgBotProxy, setTgBotProxy] = useState(''); + const [tgBotAPIServer, setTgBotAPIServer] = useState(''); + const [tgBotChatId, setTgBotChatId] = useState(''); + const [tgRunTime, setTgRunTime] = useState(''); + const [tgBotBackup, setTgBotBackup] = useState(false); + const [tgBotLoginNotify, setTgBotLoginNotify] = useState(false); + const [tgCpu, setTgCpu] = useState (''); + const [tgLang, setTgLang] = useState('en'); + + useEffect(() => { + setTgBotEnable(initialSettings.tgBotEnable || false); + setTgBotToken(initialSettings.tgBotToken || ''); + setTgBotProxy(initialSettings.tgBotProxy || ''); + setTgBotAPIServer(initialSettings.tgBotAPIServer || ''); + setTgBotChatId(initialSettings.tgBotChatId || ''); + setTgRunTime(initialSettings.tgRunTime || ''); + setTgBotBackup(initialSettings.tgBotBackup || false); + setTgBotLoginNotify(initialSettings.tgBotLoginNotify || false); + setTgCpu(initialSettings.tgCpu === undefined ? '' : initialSettings.tgCpu); + setTgLang(initialSettings.tgLang || 'en'); + }, [initialSettings]); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + const updatedTgSettings: Partial = { + ...initialSettings, + tgBotEnable, + tgBotToken, + tgBotProxy, + tgBotAPIServer, + tgBotChatId, + tgRunTime, + tgBotBackup, + tgBotLoginNotify, + tgCpu: Number(tgCpu) || 0, + tgLang, + }; + onSave(updatedTgSettings); + }; + + return ( + + ); +}; +export default TelegramSettingsForm; diff --git a/new-frontend/src/components/settings/UserAccountSettingsForm.tsx b/new-frontend/src/components/settings/UserAccountSettingsForm.tsx new file mode 100644 index 00000000..5b9efa1f --- /dev/null +++ b/new-frontend/src/components/settings/UserAccountSettingsForm.tsx @@ -0,0 +1,190 @@ +"use client"; + +import React, { useState, useEffect, FormEvent } from 'react'; +import { AllSetting, UpdateUserPayload } from '@/types/settings'; +import { QRCodeCanvas } from 'qrcode.react'; + +// Define styles locally +const inputStyles = "mt-1 block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; +const btnPrimaryStyles = "px-4 py-2 bg-primary-500 text-white font-semibold rounded-lg shadow-md hover:bg-primary-600 disabled:opacity-50 transition-colors"; + +interface UserAccountSettingsFormProps { + initialSettings: Partial ; + onUpdateUser: (payload: UpdateUserPayload) => Promise ; + onUpdateTwoFactor: (twoFactorEnabled: boolean) => Promise ; + isSavingUser: boolean; + isSavingSettings: boolean; + formError?: string | null; + successMessage?: string | null; +} + +const UserAccountSettingsForm: React.FC = ({ + initialSettings, onUpdateUser, onUpdateTwoFactor, isSavingUser, isSavingSettings, formError, successMessage +}) => { + const [oldUsername, setOldUsername] = useState(''); + const [oldPassword, setOldPassword] = useState(''); + const [newUsername, setNewUsername] = useState(''); + const [newPassword, setNewPassword] = useState(''); + const [confirmNewPassword, setConfirmNewPassword] = useState(''); + const [twoFactorEnable, setTwoFactorEnable] = useState(false); + const [twoFactorToken, setTwoFactorToken] = useState(''); + const [userFormError, setUserFormError] = useState (null); + const [twoFaFormError, setTwoFaFormError] = useState (null); + + useEffect(() => { + // Assuming username might come from a global auth context if it's the logged-in user's username + // For now, if panel settings have a way to store current admin username (they don't directly), use that. + // Otherwise, user has to type it. For simplicity, let's leave oldUsername blank initially or use a placeholder. + // In a real app, this would ideally be pre-filled if known (e.g. from auth context). + setOldUsername(''); // Or prefill if available from auth context + setTwoFactorEnable(initialSettings.twoFactorEnable || false); + setTwoFactorToken(initialSettings.twoFactorToken || ''); + setOldPassword(''); + setNewPassword(''); + setConfirmNewPassword(''); + }, [initialSettings]); + + const handleUserUpdateSubmit = async (e: FormEvent) => { + e.preventDefault(); + setUserFormError(null); + setTwoFaFormError(null); // Clear other form error + if (newPassword !== confirmNewPassword) { + setUserFormError("New passwords do not match."); + return; + } + if (!newUsername.trim() && !newPassword.trim() && !oldUsername.trim() && !oldPassword.trim()){ + // If all fields are empty, do nothing to prevent accidental submission of empty form + setUserFormError("Please fill in the fields to update credentials."); + return; + } + if ((newUsername.trim() || newPassword.trim()) && (!oldUsername.trim() || !oldPassword.trim())){ + setUserFormError("Current username and password are required to change credentials."); + return; + } + if (!newPassword.trim() && newUsername.trim() && oldUsername.trim() && oldPassword.trim()){ + // Allow changing only username if new password is not set (but current credentials must be provided) + } else if (newPassword.trim() && !newUsername.trim() && oldUsername.trim() && oldPassword.trim()){ + // Allow changing only password if new username is not set + setNewUsername(oldUsername); // Use old username if only password is changing + } else if (!newUsername.trim() || !newPassword.trim()){ + setUserFormError("New username and password cannot be empty if you intend to change them."); + return; + } + + + const success = await onUpdateUser({ oldUsername, oldPassword, newUsername: newUsername.trim() || oldUsername, newPassword }); + if (success) { + setOldPassword(''); + setNewPassword(''); + setConfirmNewPassword(''); + // Old username might need to be updated if it was changed + setOldUsername(newUsername.trim() || oldUsername); + } + }; + + const handleTwoFactorToggle = async () => { + setUserFormError(null); // Clear other form error + setTwoFaFormError(null); + const new2FAStatus = !twoFactorEnable; + const success = await onUpdateTwoFactor(new2FAStatus); + // Parent (SettingsPage) will re-fetch settings which should update initialSettings + // causing this component to re-render with new twoFactorEnable and twoFactorToken + if (success && new2FAStatus && !initialSettings.twoFactorToken) { + setTwoFaFormError("2FA enabled. Refreshing to get QR code/token..."); + } else if (success && !new2FAStatus) { + setTwoFactorToken(''); // Clear token display immediately on disable + } + }; + + const getOtpAuthUrl = () => { + if (!twoFactorToken) return null; + const label = `XUI-Panel:${initialSettings.webDomain || oldUsername || 'user'}`; + const issuer = "XUI-Panel"; + return `otpauth://totp/${encodeURIComponent(label)}?secret=${twoFactorToken}&issuer=${encodeURIComponent(issuer)}`; + }; + const otpUrl = getOtpAuthUrl(); + + return ( + {/* Added padding for consistency if this form is shown alone */} + + ++ ); +}; +export default UserAccountSettingsForm; diff --git a/new-frontend/src/components/shared/LogsModal.tsx b/new-frontend/src/components/shared/LogsModal.tsx new file mode 100644 index 00000000..37a43a3a --- /dev/null +++ b/new-frontend/src/components/shared/LogsModal.tsx @@ -0,0 +1,118 @@ +"use client"; + +import React, { useState, useEffect, useCallback } from 'react'; +import { post } from '@/services/api'; + +// Define styles locally +const inputStyles = "mt-1 block w-full px-3 py-1.5 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"; +const btnSecondaryStyles = "px-3 py-1.5 text-sm bg-gray-200 text-gray-800 font-semibold rounded-lg shadow-md hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 transition-colors"; + +interface LogsModalProps { + isOpen: boolean; + onClose: () => void; +} + +type LogLevel = "debug" | "info" | "notice" | "warning" | "error"; + +const LogLevels: LogLevel[] = ["debug", "info", "notice", "warning", "error"]; +const LogCounts: number[] = [20, 50, 100, 200, 500]; + +const LogsModal: React.FC++Two-Factor Authentication (2FA)
+ {twoFaFormError &&{twoFaFormError}} + {formError && formError.toLowerCase().includes("2fa") &&{formError}} + {successMessage && successMessage.toLowerCase().includes("2fa") &&{successMessage}} + ++ + {twoFactorEnable ? '2FA Enabled' : '2FA Disabled'} +++ Click the toggle to change 2FA status. This change requires saving all settings. + If enabling for the first time, save settings, then the QR code and token will appear. +
+ + {twoFactorEnable && twoFactorToken && otpUrl && ( +++ )} + {twoFactorEnable && !twoFactorToken && ( +Scan this QR code with your authenticator app:
++++ Or manually enter this token:
+{twoFactorToken}
++ Important: Store this token securely. If you lose access to your authenticator app, you may lose access to your account. +
++ 2FA is marked as enabled, but no token is available. Please save settings. + The panel may need a restart for the token to be generated if this is the first time enabling. +
+ )} += ({ isOpen, onClose }) => { + const [logs, setLogs] = useState ([]); + const [count, setCount] = useState (100); + const [level, setLevel] = useState ('info'); + const [syslog, setSyslog] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState (null); + + const fetchLogs = useCallback(async () => { + if (!isOpen) return; // Should not fetch if modal is not open + setIsLoading(true); + setError(null); + try { + const apiLevel = level === 'error' ? 'err' : level; + const response = await post (`/server/logs/${count}`, { level: apiLevel, syslog: syslog.toString() }); + if (response.success && Array.isArray(response.data)) { + setLogs(response.data); + } else { + setError(response.message || 'Failed to fetch logs.'); + setLogs([]); + } + } catch (err) { + setError(err instanceof Error ? err.message : 'An unknown error occurred.'); + setLogs([]); + } finally { + setIsLoading(false); + } + }, [isOpen, count, level, syslog]); // Removed fetchLogs from its own dep array + + useEffect(() => { + if (isOpen) { + fetchLogs(); + } + }, [isOpen, fetchLogs]); + + const handleDownload = () => { + if (logs.length === 0) return; + const blob = new Blob([logs.join('\n')], { type: 'text/plain;charset=utf-8' }); + const link = document.createElement('a'); + link.href = URL.createObjectURL(blob); + link.download = `xray_logs_${new Date().toISOString().split('T')[0]}.txt`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(link.href); + }; + + if (!isOpen) return null; + + return ( + ++ ); +}; +export default LogsModal; diff --git a/new-frontend/src/components/ui/.gitkeep b/new-frontend/src/components/ui/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/components/ui/ProgressBar.tsx b/new-frontend/src/components/ui/ProgressBar.tsx new file mode 100644 index 00000000..4c3889cd --- /dev/null +++ b/new-frontend/src/components/ui/ProgressBar.tsx @@ -0,0 +1,19 @@ +import React from 'react'; + +interface ProgressBarProps { + percentage: number; + color?: string; // Tailwind color class e.g., 'bg-blue-500' +} + +const ProgressBar: React.FCe.stopPropagation()}> ++++ +Xray Logs
+ +++ + {isLoading &&+ + +++ + +++ setSyslog(e.target.checked)} className="h-4 w-4 text-primary-600 border-gray-300 dark:border-gray-600 rounded focus:ring-primary-500 bg-white dark:bg-gray-700" /> + ++ + +Loading logs...
} + {error &&{error}
} + + {!isLoading && !error && logs.length === 0 &&No logs to display with current filters.
} + + {!isLoading && logs.length > 0 && ( ++ {logs.map((log, index) => ( ++ )} +{log}+ ))} += ({ percentage, color = 'bg-primary-500' }) => { + const safePercentage = Math.max(0, Math.min(100, percentage)); + return ( + + ++ ); +}; +export default ProgressBar; diff --git a/new-frontend/src/context/AuthContext.tsx b/new-frontend/src/context/AuthContext.tsx new file mode 100644 index 00000000..d297d267 --- /dev/null +++ b/new-frontend/src/context/AuthContext.tsx @@ -0,0 +1,127 @@ +"use client"; + +import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'; +import { useRouter, usePathname } from 'next/navigation'; +import { post, get, ApiResponse } from '@/services/api'; + +interface AuthUser { + // Define based on what your backend session stores or what /api/me might return + username: string; + // Add other user properties if available +} + +interface AuthContextType { + isAuthenticated: boolean; + user: AuthUser | null; + isLoading: boolean; + login: (username: string, password: string, twoFactorCode?: string) => Promise>; + logout: () => Promise ; + checkAuthState: () => Promise ; +} + +const AuthContext = createContext (undefined); + +export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => { + const [user, setUser] = useState (null); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [isLoading, setIsLoading] = useState(true); // Start true for initial auth check + const router = useRouter(); + const pathname = usePathname(); + + const checkAuthState = async () => { + setIsLoading(true); + try { + // A common pattern is to have a '/api/me' or '/server/me' endpoint + // that returns user info if authenticated, or 401 if not. + // For now, we'll assume if we can access a protected route like '/server/status' (even if it fails for other reasons) + // it implies a session might be active. This is not ideal. + // A dedicated "me" endpoint is better. + // Let's try to fetch /server/status as a proxy for being logged in. + // The actual data isn't used here, just the success of the call. + const response = await post ('/server/status', {}); // This endpoint requires login + if (response.success) { + // Ideally, this response would contain user details. + // For now, we'll mock a user object if the call succeeds. + // This needs to be improved with a proper /api/me endpoint. + // The current /server/status doesn't return user info, just system status. + // So, if it succeeds, we know a session is active. + // We can't get the username from this though. + // This is a placeholder until a proper "me" endpoint is available. + setUser({ username: "Authenticated User" }); // Placeholder + setIsAuthenticated(true); + } else { + setUser(null); + setIsAuthenticated(false); + // Do not redirect here, let protected route logic handle it + } + } catch (error) { + console.error("Error checking auth state:", error); + setUser(null); + setIsAuthenticated(false); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + checkAuthState(); + }, []); // Run once on mount + + const login = async (username: string, password: string, twoFactorCode?: string) => { + setIsLoading(true); + const payload: Record = { username, password }; + if (twoFactorCode) { + payload.twoFactorCode = twoFactorCode; + } + const response = await post('/login', payload); + if (response.success) { + // Again, ideally fetch user data from a /me endpoint after login + setUser({ username }); // Placeholder + setIsAuthenticated(true); + router.push('/dashboard'); + } else { + setUser(null); + setIsAuthenticated(false); + } + setIsLoading(false); + return response; // Return the full response for the login page to handle messages + }; + + const logout = async () => { + setIsLoading(true); + try { + await get('/logout'); // Call backend logout + } catch (error) { + console.error("Logout API call failed:", error); + // Still proceed with client-side logout + } finally { + setUser(null); + setIsAuthenticated(false); + localStorage.removeItem('theme'); // Also clear theme preference on logout + router.push('/auth/login'); + setIsLoading(false); + } + }; + + // Effect to redirect if not authenticated and trying to access a protected page + useEffect(() => { + if (!isLoading && !isAuthenticated && !pathname.startsWith('/auth')) { + router.push('/auth/login'); + } + }, [isLoading, isAuthenticated, pathname, router]); + + + return ( + + {children} + + ); +}; + +export const useAuth = (): AuthContextType => { + const context = useContext(AuthContext); + if (context === undefined) { + throw new Error('useAuth must be used within an AuthProvider'); + } + return context; +}; diff --git a/new-frontend/src/hooks/.gitkeep b/new-frontend/src/hooks/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/lib/.gitkeep b/new-frontend/src/lib/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/lib/formatters.ts b/new-frontend/src/lib/formatters.ts new file mode 100644 index 00000000..e1871cec --- /dev/null +++ b/new-frontend/src/lib/formatters.ts @@ -0,0 +1,33 @@ +export function formatBytes(bytes: number, decimals = 2): string { + if (bytes === 0) return '0 Bytes'; + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; +} + +export function formatUptime(seconds: number): string { + if (seconds <= 0) return 'N/A'; + const d = Math.floor(seconds / (3600 * 24)); + const h = Math.floor((seconds % (3600 * 24)) / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = Math.floor(seconds % 60); + + let result = ''; + if (d > 0) result += `${d}d `; + if (h > 0) result += `${h}h `; + if (m > 0) result += `${m}m `; + if (s > 0 || result === '') result += `${s}s`; // show seconds if other units are zero or if it's the only unit + return result.trim(); +} + +export function formatPercentage(value: number, total: number): number { + if (total === 0) return 0; + return parseFloat(((value / total) * 100).toFixed(2)); +} + +export function toFixedIfNecessary( value: number | undefined, fractionDigits: number ): string { + if (value === undefined) return 'N/A'; + return value.toFixed(fractionDigits); +} diff --git a/new-frontend/src/lib/subscriptionLink.ts b/new-frontend/src/lib/subscriptionLink.ts new file mode 100644 index 00000000..8f25a951 --- /dev/null +++ b/new-frontend/src/lib/subscriptionLink.ts @@ -0,0 +1,134 @@ +import { Inbound, ClientSetting } from '@/types/inbound'; + +const SERVER_ADDRESS = 'YOUR_SERVER_IP_OR_DOMAIN'; +const encode = encodeURIComponent; + +export function generateSubscriptionLink(inbound: Inbound, client: ClientSetting): string | null { + if (!inbound || !client) return null; + + const protocol = inbound.protocol; + const port = inbound.port; + let remark = client.email || client.id || client.password || 'client'; + if (protocol === 'shadowsocks') { + remark = inbound.remark || 'shadowsocks_client'; + } + + let streamSettings: Record= {}; + try { + streamSettings = inbound.streamSettings ? JSON.parse(inbound.streamSettings) : {}; + } catch (e) { console.error("Error parsing streamSettings for link:", e); } + + const network = (streamSettings.network as string) || 'tcp'; + const security = (streamSettings.security as string) || 'none'; + + let tlsSettings: Record = {}; + if (security === 'tls' && typeof streamSettings.tlsSettings === 'object' && streamSettings.tlsSettings !== null) { + tlsSettings = streamSettings.tlsSettings as Record ; + } + let realitySettings: Record = {}; + if (security === 'reality' && typeof streamSettings.realitySettings === 'object' && streamSettings.realitySettings !== null) { + realitySettings = streamSettings.realitySettings as Record ; + } + + switch (protocol) { + case 'vmess': { + const vmessConfig: Record = { + v: "2", ps: remark, add: SERVER_ADDRESS, port: port.toString(), id: client.id, + aid: "0", scy: "auto", net: network, + type: ((streamSettings.tcpSettings as Record )?.header as Record )?.type === 'http' ? 'http' : 'none', + host: ((streamSettings.wsSettings as Record )?.headers as Record )?.Host || (network === 'h2' ? tlsSettings.serverName as string : undefined) || '', + path: (streamSettings.wsSettings as Record )?.path as string || (network === 'grpc' ? (streamSettings.grpcSettings as Record )?.serviceName as string : undefined) || '', + tls: security === 'tls' ? "tls" : "", + sni: tlsSettings.serverName as string || '', + }; + const alpnArray = tlsSettings.alpn as string[]; + if (alpnArray && Array.isArray(alpnArray) && alpnArray.length > 0) { + vmessConfig.alpn = alpnArray.join(','); + } + if (security === 'tls' && tlsSettings.fingerprint) { + vmessConfig.fp = tlsSettings.fingerprint as string; + } + const jsonString = JSON.stringify(vmessConfig); + return `vmess://${btoa(jsonString)}`; + } + case 'vless': { + let link = `vless://${client.id}@${SERVER_ADDRESS}:${port}`; + const params = new URLSearchParams(); + params.append('type', network); + + if (security === 'tls' || security === 'reality') { + params.append('security', security); + if (tlsSettings.serverName) params.append('sni', tlsSettings.serverName as string); + if (tlsSettings.fingerprint) params.append('fp', tlsSettings.fingerprint as string); + if (security === 'reality') { + if (realitySettings.publicKey) params.append('pbk', realitySettings.publicKey as string); + if (realitySettings.shortId) params.append('sid', realitySettings.shortId as string); + } + } + if (client.flow) params.append('flow', client.flow); + + if (network === 'ws' && streamSettings.wsSettings) { + const wsOpts = streamSettings.wsSettings as Record ; + params.append('path', encode(wsOpts.path as string || '/')); + if (wsOpts.headers && typeof (wsOpts.headers as Record ).Host === 'string') { + params.append('host', encode((wsOpts.headers as Record ).Host as string)); + } + } else if (network === 'grpc' && streamSettings.grpcSettings) { + const grpcOpts = streamSettings.grpcSettings as Record ; + params.append('serviceName', encode(grpcOpts.serviceName as string || '')); + if (grpcOpts.multiMode) params.append('mode', 'multi'); + } + + const query = params.toString(); + if (query) link += `?${query}`; + link += `#${encode(remark)}`; + return link; + } + case 'trojan': { + let link = `trojan://${client.password}@${SERVER_ADDRESS}:${port}`; + const params = new URLSearchParams(); + if (security === 'tls' || security === 'reality') { + if (tlsSettings.serverName) params.append('sni', tlsSettings.serverName as string); + if (security === 'reality') params.append('security', 'reality'); + } + + if (network !== 'tcp') params.append('type', network); + if (network === 'ws' && streamSettings.wsSettings) { + const wsOpts = streamSettings.wsSettings as Record ; + params.append('path', encode(wsOpts.path as string || '/')); + if (wsOpts.headers && typeof (wsOpts.headers as Record ).Host === 'string') { + params.append('host', encode((wsOpts.headers as Record ).Host as string)); + } + } + // For Trojan, client.flow is not typically added to the URL query parameters in standard formats. + // If a specific Trojan variant uses it, it would be a custom addition. + // The VLESS case already handles client.flow correctly. + + const query = params.toString(); + if (query) link += `?${query}`; + link += `#${encode(remark)}`; + return link; + } + case 'shadowsocks': { + let ssSettings: Record = {}; + try { + const parsed = inbound.settings ? JSON.parse(inbound.settings) : {}; + if (typeof parsed.method === 'string' && typeof parsed.password === 'string') { + ssSettings = parsed as Record ; + } + } catch (e) { console.error("Error parsing SS settings for link:", e); } + const method = ssSettings.method as string || client.encryption; + const password = ssSettings.password as string; + + if (!method || !password) { + console.warn("Shadowsocks method or password not found in inbound settings for link generation."); + return null; + } + + const encodedPart = btoa(`${method}:${password}`); + return `ss://${encodedPart}@${SERVER_ADDRESS}:${port}#${encode(remark)}`; + } + default: + return null; + } +} diff --git a/new-frontend/src/services/.gitkeep b/new-frontend/src/services/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/services/api.ts b/new-frontend/src/services/api.ts new file mode 100644 index 00000000..fd2280d4 --- /dev/null +++ b/new-frontend/src/services/api.ts @@ -0,0 +1,66 @@ +// Basic API client setup +// In a real app, this would be more robust, possibly using axios +// and handling base URLs, interceptors for auth tokens, etc. + +export interface ApiResponse { + success: boolean; + message?: string; + data?: T; + obj?: T; // Based on existing backend responses +} + +async function handleResponse (response: Response): Promise > { + if (!response.ok) { + // Try to parse error from backend if available + try { + const errorData = await response.json(); + return { success: false, message: errorData.message || 'An unknown error occurred', data: errorData }; + } catch (parseError) { + console.error('Error parsing JSON error response:', parseError); + return { success: false, message: `HTTP error! status: ${response.status}. Failed to parse error response.` }; + } + } + // The backend sometimes returns data in 'obj' and sometimes directly, + // and sometimes just a message. + // For login, it seems to return { success: true, message: "...", obj: null } + // For getTwoFactorEnable, it returns { success: true, obj: boolean } + const contentType = response.headers.get("content-type"); + if (contentType && contentType.indexOf("application/json") !== -1) { + const jsonData = await response.json(); + // Adapt to existing backend structure which might use 'obj' for data + return { success: jsonData.success !== undefined ? jsonData.success : true, message: jsonData.message, data: jsonData.obj !== undefined ? jsonData.obj : jsonData }; + } + return { success: true, message: 'Operation successful but no JSON response.' }; +} + + +export async function post (url: string, body: Record ): Promise > { + try { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + credentials: 'include', // Important for sending cookies + }); + return handleResponse (response); + } catch (error) { + console.error('API POST error:', error); + return { success: false, message: error instanceof Error ? error.message : 'Network error' }; + } +} + +// GET request for logout, could be added here too if needed for consistency +export async function get (url: string): Promise > { + try { + const response = await fetch(url, { + method: 'GET', + credentials: 'include', + }); + return handleResponse (response); + } catch (error) { + console.error('API GET error:', error); + return { success: false, message: error instanceof Error ? error.message : 'Network error' }; + } +} diff --git a/new-frontend/src/styles/.gitkeep b/new-frontend/src/styles/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/new-frontend/src/types/inbound.ts b/new-frontend/src/types/inbound.ts new file mode 100644 index 00000000..13e075a7 --- /dev/null +++ b/new-frontend/src/types/inbound.ts @@ -0,0 +1,62 @@ +// Based on database/model/model.go and xray/traffic.go + +export interface ClientTraffic { + id: number; + inboundId: number; + enable: boolean; + email: string; + up: number; + down: number; + expiryTime: number; + total: number; + reset?: number; // Optional, as it might not always be present +} + +export type Protocol = "vmess" | "vless" | "trojan" | "shadowsocks" | "dokodemo-door" | "socks" | "http" | "wireguard"; + +export interface Inbound { + id: number; + userId: number; // Assuming not directly used in UI but good to have + up: number; + down: number; + total: number; // Overall total for the inbound itself + remark: string; + enable: boolean; + expiryTime: number; // Overall expiry for the inbound itself + clientStats: ClientTraffic[]; // For clients directly associated with this inbound's settings + + // Config part + listen: string; + port: number; + protocol: Protocol; + settings: string; // JSON string, to be parsed for client details if needed + streamSettings: string; // JSON string + tag: string; + sniffing: string; // JSON string + // allocate: string; // JSON string - allocate seems to be missing in controller/model for direct form binding, might be part of settings +} + +// For the list API, it seems clientStats are eagerly loaded. +export type InboundFromList = Inbound; // Alias for clarity + +export interface InboundClientIP { // From model.InboundClientIps + id: number; + clientEmail: string; + ips: string; +} + +// For client details within Inbound.settings JSON string +export interface ClientSetting { + id?: string; // UUID for vmess/vless + password?: string; // for trojan + email: string; + flow?: string; + encryption?: string; // for shadowsocks method + totalGB?: number; // quota in GB for client + expiryTime?: number; // client-specific expiry + limitIp?: number; + subId?: string; + tgId?: string; + enable?: boolean; // Client specific enable toggle + comment?: string; +} diff --git a/new-frontend/src/types/settings.ts b/new-frontend/src/types/settings.ts new file mode 100644 index 00000000..89bc7619 --- /dev/null +++ b/new-frontend/src/types/settings.ts @@ -0,0 +1,56 @@ +// Based on web/entity/entity.go AllSetting struct +export interface AllSetting { + webListen?: string; + webDomain?: string; + webPort?: number; + webCertFile?: string; + webKeyFile?: string; + webBasePath?: string; + sessionMaxAge?: number; + pageSize?: number; + expireDiff?: number; + trafficDiff?: number; + remarkModel?: string; + tgBotEnable?: boolean; + tgBotToken?: string; + tgBotProxy?: string; + tgBotAPIServer?: string; + tgBotChatId?: string; + tgRunTime?: string; + tgBotBackup?: boolean; + tgBotLoginNotify?: boolean; + tgCpu?: number; + tgLang?: string; + timeLocation?: string; + twoFactorEnable?: boolean; + twoFactorToken?: string; + subEnable?: boolean; + subTitle?: string; + subListen?: string; + subPort?: number; + subPath?: string; + subDomain?: string; + subCertFile?: string; + subKeyFile?: string; + subUpdates?: number; + externalTrafficInformEnable?: boolean; + externalTrafficInformURI?: string; + subEncrypt?: boolean; + subShowInfo?: boolean; + subURI?: string; + subJsonPath?: string; + subJsonURI?: string; + subJsonFragment?: string; + subJsonNoises?: string; + subJsonMux?: string; + subJsonRules?: string; + datepicker?: string; +} + +// For updating username/password +export interface UpdateUserPayload { + oldUsername?: string; + oldPassword?: string; + newUsername?: string; + newPassword?: string; +} diff --git a/new-frontend/tailwind.config.ts b/new-frontend/tailwind.config.ts new file mode 100644 index 00000000..47a4ecda --- /dev/null +++ b/new-frontend/tailwind.config.ts @@ -0,0 +1,49 @@ +import type { Config } from "tailwindcss"; + +const config: Config = { + content: [ + "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", + "./src/components/**/*.{js,ts,jsx,tsx,mdx}", + "./src/app/**/*.{js,ts,jsx,tsx,mdx}", + ], + darkMode: 'class', // Enable class-based dark mode + theme: { + extend: { + colors: { + primary: { + '50': '#eff6ff', + '100': '#dbeafe', + '200': '#bfdbfe', + '300': '#93c5fd', + '400': '#60a5fa', + '500': '#3b82f6', // Our chosen primary blue + '600': '#2563eb', + '700': '#1d4ed8', + '800': '#1e40af', + '900': '#1e3a8a', + '950': '#172554', + }, + accent: { // Our chosen accent green + '50': '#f0fdf4', + '100': '#dcfce7', + '200': '#bbf7d0', + '300': '#86efac', + '400': '#4ade80', + '500': '#22c55e', + '600': '#16a34a', + '700': '#15803d', + '800': '#166534', + '900': '#14532d', + '950': '#052e16', + } + }, + backgroundImage: { + "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", + "gradient-conic": + "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", + }, + }, + }, + plugins: [], +}; +export default config; diff --git a/new-frontend/tsconfig.json b/new-frontend/tsconfig.json new file mode 100644 index 00000000..c1334095 --- /dev/null +++ b/new-frontend/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/new-frontend/yarn.lock b/new-frontend/yarn.lock new file mode 100644 index 00000000..ce19c2cf --- /dev/null +++ b/new-frontend/yarn.lock @@ -0,0 +1,3028 @@ +# 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== + +"@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@emnapi/core@^1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.3.tgz#9ac52d2d5aea958f67e52c40a065f51de59b77d6" + integrity sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g== + dependencies: + "@emnapi/wasi-threads" "1.0.2" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.3.tgz#c0564665c80dc81c448adac23f9dfbed6c838f7d" + integrity sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.0.2", "@emnapi/wasi-threads@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz#977f44f844eac7d6c138a415a123818c655f874c" + integrity sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA== + dependencies: + tslib "^2.4.0" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/config-array@^0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.20.0.tgz#7a1232e82376712d3340012a2f561a2764d1988f" + integrity sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-helpers@^0.2.1": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.2.2.tgz#3779f76b894de3a8ec4763b79660e6d54d5b1010" + integrity sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg== + +"@eslint/core@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.14.0.tgz#326289380968eaf7e96f364e1e4cf8f3adf2d003" + integrity sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3", "@eslint/eslintrc@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964" + integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.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@9.28.0": + version "9.28.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.28.0.tgz#7822ccc2f8cae7c3cd4f902377d520e9ae03f844" + integrity sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz#b71b037b2d4d68396df04a8c35a49481e5593067" + integrity sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w== + dependencies: + "@eslint/core" "^0.14.0" + levn "^0.4.1" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@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/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== + +"@img/sharp-darwin-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz#65049ef7c6be7857da742cd028f97602ce209635" + integrity sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.1.0" + +"@img/sharp-darwin-x64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz#d37ff7c75c46d5a68a3756e3f1924ef7ca7b285e" + integrity sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.1.0" + +"@img/sharp-libvips-darwin-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz#843f7c09c7245dc0d3cfec2b3c83bb08799a704f" + integrity sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA== + +"@img/sharp-libvips-darwin-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz#1239c24426c06a8e833815562f78047a3bfbaaf8" + integrity sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ== + +"@img/sharp-libvips-linux-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz#20d276cefd903ee483f0441ba35961679c286315" + integrity sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew== + +"@img/sharp-libvips-linux-arm@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz#067c0b566eae8063738cf1b1db8f8a8573b5465c" + integrity sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA== + +"@img/sharp-libvips-linux-ppc64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz#682334595f2ca00e0a07a675ba170af165162802" + integrity sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ== + +"@img/sharp-libvips-linux-s390x@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz#82fcd68444b3666384235279c145c2b28d8ee302" + integrity sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA== + +"@img/sharp-libvips-linux-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz#65b2b908bf47156b0724fde9095676c83a18cf5a" + integrity sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q== + +"@img/sharp-libvips-linuxmusl-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz#72accf924e80b081c8db83b900b444a67c203f01" + integrity sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w== + +"@img/sharp-libvips-linuxmusl-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz#1fa052737e203f46bf44192acd01f9faf11522d7" + integrity sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A== + +"@img/sharp-linux-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz#c9690fac5f3137eaab3f7ad6065390d10f66f1fa" + integrity sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.1.0" + +"@img/sharp-linux-arm@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz#771dd2ec645f85f98441359bfc118afaf38cbd8b" + integrity sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.1.0" + +"@img/sharp-linux-s390x@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz#82132d158abff57bd90b53574f2865f72f94e6c8" + integrity sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.1.0" + +"@img/sharp-linux-x64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz#d815fb87899d462b28b62a9252ad127f02fe0740" + integrity sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.1.0" + +"@img/sharp-linuxmusl-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz#cfac45b2abbc04628f676e123bfe3aeb300266c7" + integrity sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.1.0" + +"@img/sharp-linuxmusl-x64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz#b876c23ff51d0fb6d9f3b0a07e2f4d1436c203ad" + integrity sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.1.0" + +"@img/sharp-wasm32@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz#b1dd0bab547dccf517586eb1fa5852160bba3b82" + integrity sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ== + dependencies: + "@emnapi/runtime" "^1.4.3" + +"@img/sharp-win32-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz#f37bee0f60c167f825a09d2b8de6849b823e8b30" + integrity sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ== + +"@img/sharp-win32-ia32@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz#8fc30b6655bc6ff8910344a2020d334aa6361672" + integrity sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw== + +"@img/sharp-win32-x64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz#ecf19250f8fe35de684aa2b0ec6f773b3447247b" + integrity sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw== + +"@isaacs/fs-minipass@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" + integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== + dependencies: + minipass "^7.0.4" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + 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", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@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" + +"@napi-rs/wasm-runtime@^0.2.10": + version "0.2.10" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz#f3b7109419c6670000b2401e0c778b98afc25f84" + integrity sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.9.0" + +"@next/env@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.3.3.tgz#8c5548756df93efff1bf4bb4e9e430a763978155" + integrity sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw== + +"@next/eslint-plugin-next@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.3.3.tgz#04a378b405f65f61165085f84971ccb4bbcf2f0a" + integrity sha512-VKZJEiEdpKkfBmcokGjHu0vGDG+8CehGs90tBEy/IDoDDKGngeyIStt2MmE5FYNyU9BhgR7tybNWTAJY/30u+Q== + dependencies: + fast-glob "3.3.1" + +"@next/swc-darwin-arm64@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.3.tgz#994de8515cdfb74d337bdad645c33605de44c68b" + integrity sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg== + +"@next/swc-darwin-x64@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.3.tgz#71588bad245180ffd1af1e1f894477287e739eb0" + integrity sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw== + +"@next/swc-linux-arm64-gnu@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.3.tgz#66a15f749c14f04a89f8c7e21c7a8d343fc34e6e" + integrity sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw== + +"@next/swc-linux-arm64-musl@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.3.tgz#14bd66213f7f33d6909574750bcb05037221a2ac" + integrity sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA== + +"@next/swc-linux-x64-gnu@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz#4a19434545e5e752d9a3ed71f9b34982725f6293" + integrity sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw== + +"@next/swc-linux-x64-musl@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz#41ab140dd0a04ab7291adbec5836c1ce251a588c" + integrity sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw== + +"@next/swc-win32-arm64-msvc@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.3.tgz#fcd1d7e0007b7b73d1acdbf0ad6d91f7aa2deb15" + integrity sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ== + +"@next/swc-win32-x64-msvc@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.3.tgz#c0e33e069d7922dd0546cac77a0247ad81d4a1aa" + integrity sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw== + +"@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": + 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" + +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + +"@rushstack/eslint-patch@^1.10.3": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz#75dce8e972f90bba488e2b0cc677fb233aa357ab" + integrity sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ== + +"@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.15": + version "0.5.15" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7" + integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g== + dependencies: + tslib "^2.8.0" + +"@tailwindcss/node@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.8.tgz#e29187abec6194ce1e9f072208c62116a79a129b" + integrity sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q== + dependencies: + "@ampproject/remapping" "^2.3.0" + enhanced-resolve "^5.18.1" + jiti "^2.4.2" + lightningcss "1.30.1" + magic-string "^0.30.17" + source-map-js "^1.2.1" + tailwindcss "4.1.8" + +"@tailwindcss/oxide-android-arm64@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.8.tgz#4cb4b464636fc7e3154a1bb7df38a828291b3e9a" + integrity sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg== + +"@tailwindcss/oxide-darwin-arm64@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.8.tgz#b0b8c02745f76aea683c30818e249d62821864b8" + integrity sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A== + +"@tailwindcss/oxide-darwin-x64@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.8.tgz#d0f3fa4c3bde21a772e29e31c9739d91db79de12" + integrity sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw== + +"@tailwindcss/oxide-freebsd-x64@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.8.tgz#545c94c941007ed1aa2e449465501b70d59cb3da" + integrity sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.8.tgz#e1bdbf63a179081669b8cd1c9523889774760eb9" + integrity sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.8.tgz#8d28093bbd43bdae771a2dcca720e926baa57093" + integrity sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.8.tgz#cc6cece814d813885ead9cd8b9d55aeb3db56c97" + integrity sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.8.tgz#4cac14fa71382574773fb7986d9f0681ad89e3de" + integrity sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g== + +"@tailwindcss/oxide-linux-x64-musl@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.8.tgz#e085f1ccbc8f97625773a6a3afc2a6f88edf59da" + integrity sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg== + +"@tailwindcss/oxide-wasm32-wasi@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.8.tgz#c5e19fffe67f25cabf12a357bba4e87128151ea0" + integrity sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@emnapi/wasi-threads" "^1.0.2" + "@napi-rs/wasm-runtime" "^0.2.10" + "@tybys/wasm-util" "^0.9.0" + tslib "^2.8.0" + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.8.tgz#77521f23f91604c587736927fd2cb526667b7344" + integrity sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA== + +"@tailwindcss/oxide-win32-x64-msvc@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.8.tgz#55c876ab35f8779d1dceec61483cd9834d7365ac" + integrity sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ== + +"@tailwindcss/oxide@4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.1.8.tgz#b7a3df10c6c47ac5a3ac9976ad334732c4870d16" + integrity sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A== + dependencies: + detect-libc "^2.0.4" + tar "^7.4.3" + optionalDependencies: + "@tailwindcss/oxide-android-arm64" "4.1.8" + "@tailwindcss/oxide-darwin-arm64" "4.1.8" + "@tailwindcss/oxide-darwin-x64" "4.1.8" + "@tailwindcss/oxide-freebsd-x64" "4.1.8" + "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.8" + "@tailwindcss/oxide-linux-arm64-gnu" "4.1.8" + "@tailwindcss/oxide-linux-arm64-musl" "4.1.8" + "@tailwindcss/oxide-linux-x64-gnu" "4.1.8" + "@tailwindcss/oxide-linux-x64-musl" "4.1.8" + "@tailwindcss/oxide-wasm32-wasi" "4.1.8" + "@tailwindcss/oxide-win32-arm64-msvc" "4.1.8" + "@tailwindcss/oxide-win32-x64-msvc" "4.1.8" + +"@tailwindcss/postcss@^4": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@tailwindcss/postcss/-/postcss-4.1.8.tgz#b12374b49f3accd9bd902a4324d124e67803350f" + integrity sha512-vB/vlf7rIky+w94aWMw34bWW1ka6g6C3xIOdICKX2GC0VcLtL6fhlLiafF0DVIwa9V6EHz8kbWMkS2s2QvvNlw== + dependencies: + "@alloc/quick-lru" "^5.2.0" + "@tailwindcss/node" "4.1.8" + "@tailwindcss/oxide" "4.1.8" + postcss "^8.4.41" + tailwindcss "4.1.8" + +"@tybys/wasm-util@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355" + integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== + dependencies: + tslib "^2.4.0" + +"@types/estree@^1.0.6": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" + integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@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": + version "20.17.57" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.57.tgz#f807455e3303ba8ba08fcb1db90619356abfaa99" + integrity sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ== + dependencies: + undici-types "~6.19.2" + +"@types/qrcode.react@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/qrcode.react/-/qrcode.react-3.0.0.tgz#af45507c1b37989a22e15f98ed112b5c2eda95d2" + integrity sha512-VPHYhnDfvt4LjlWajpYWRBVqmftEEza3GJVhe8sS5Wew0n4nTkg3+2MYunAiU6t04AZt0s/hkkMovefWeENjAQ== + dependencies: + qrcode.react "*" + +"@types/react-dom@^19": + version "19.1.5" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.1.5.tgz#cdfe2c663742887372f54804b16e8dbc26bd794a" + integrity sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg== + +"@types/react@^19": + version "19.1.6" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.1.6.tgz#dee39f3e1e9a7d693f156a5840570b6d57f325ea" + integrity sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q== + dependencies: + csstype "^3.0.2" + +"@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz#532641b416ed2afd5be893cddb2a58e9cd1f7a3e" + integrity sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.33.1" + "@typescript-eslint/type-utils" "8.33.1" + "@typescript-eslint/utils" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + graphemer "^1.4.0" + ignore "^7.0.0" + natural-compare "^1.4.0" + ts-api-utils "^2.1.0" + +"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.33.1.tgz#ef9a5ee6aa37a6b4f46cc36d08a14f828238afe2" + integrity sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA== + dependencies: + "@typescript-eslint/scope-manager" "8.33.1" + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/typescript-estree" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + debug "^4.3.4" + +"@typescript-eslint/project-service@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.33.1.tgz#c85e7d9a44d6a11fe64e73ac1ed47de55dc2bf9f" + integrity sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.33.1" + "@typescript-eslint/types" "^8.33.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz#d1e0efb296da5097d054bc9972e69878a2afea73" + integrity sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA== + dependencies: + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + +"@typescript-eslint/tsconfig-utils@8.33.1", "@typescript-eslint/tsconfig-utils@^8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz#7836afcc097a4657a5ed56670851a450d8b70ab8" + integrity sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g== + +"@typescript-eslint/type-utils@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz#d73ee1a29d8a0abe60d4abbff4f1d040f0de15fa" + integrity sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww== + dependencies: + "@typescript-eslint/typescript-estree" "8.33.1" + "@typescript-eslint/utils" "8.33.1" + debug "^4.3.4" + ts-api-utils "^2.1.0" + +"@typescript-eslint/types@8.33.1", "@typescript-eslint/types@^8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.33.1.tgz#b693111bc2180f8098b68e9958cf63761657a55f" + integrity sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg== + +"@typescript-eslint/typescript-estree@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz#d271beed470bc915b8764e22365d4925c2ea265d" + integrity sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA== + dependencies: + "@typescript-eslint/project-service" "8.33.1" + "@typescript-eslint/tsconfig-utils" "8.33.1" + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.1.0" + +"@typescript-eslint/utils@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.33.1.tgz#ea22f40d3553da090f928cf17907e963643d4b96" + integrity sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/scope-manager" "8.33.1" + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/typescript-estree" "8.33.1" + +"@typescript-eslint/visitor-keys@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz#6c6e002c24d13211df3df851767f24dfdb4f42bc" + integrity sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ== + dependencies: + "@typescript-eslint/types" "8.33.1" + eslint-visitor-keys "^4.2.0" + +"@unrs/resolver-binding-darwin-arm64@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.9.tgz#8bced7ea01572da44bbb1ca0caf85afdb9d1320b" + integrity sha512-hWbcVTcNqgUirY5DC3heOLrz35D926r2izfxveBmuIgDwx9KkUHfqd93g8PtROJX01lvhmyAc3E09/ma6jhyqQ== + +"@unrs/resolver-binding-darwin-x64@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.9.tgz#f7ac117b7fd8bc06faa0f46b9b85601503e8cec5" + integrity sha512-NCZb/oaXELjt8jtm6ztlNPpAxKZsKIxsGYPSxkwQdQ/zl7X2PfyCpWqwoGE4A9vCP6gAgJnvH3e22nE0qk9ieA== + +"@unrs/resolver-binding-freebsd-x64@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.9.tgz#3ba701885a5fa01404dbba009ae8396309dec56c" + integrity sha512-/AYheGgFn9Pw3X3pYFCohznydaUA9980/wlwgbgCsVxnY4IbqVoZhTLQZ4JWKKaOWBwwmM8FseHf5h5OawyOQQ== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.9.tgz#cbdd0a89f2ad0c9c8168c606f3c8c5bd23ad1a17" + integrity sha512-RYV9sEH3o6SZum5wGb9evXlgibsVfluuiyi09hXVD+qPRrCSB45h3z1HjZpe9+c25GiN53CEy149fYS0fLVBtw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.9.tgz#d109d6075080447dd4d7f4d8997963e8d0594676" + integrity sha512-0ishMZMCYNJd4SNjHnjByHWh6ia7EDVZrOVAW8wf9Vz2PTZ0pLrFwu5c9voHouGKg7s2cnzPz87c0OK7dwimUQ== + +"@unrs/resolver-binding-linux-arm64-gnu@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.9.tgz#3099c9a476ded3af74e7d02592f88e3e0031d0ee" + integrity sha512-FOspRldYylONzWCkF5n/B1MMYKXXlg2bzgcgESEVcP4LFh0eom/0XsWvfy+dlfBJ+FkYfJjvBJeje14xOBOa6g== + +"@unrs/resolver-binding-linux-arm64-musl@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.9.tgz#178aeb3d813f21614011f3b39fe209390ece01de" + integrity sha512-P1S5jTht888/1mZVrBZx8IOxpikRDPoECxod1CcAHYUZGUNr+PNp1m5eB9FWMK2zRCJ8HgHNZfdRyDf9pNCrlQ== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.9.tgz#3deb6e460114161905c407ce1466cb55d47c1f0c" + integrity sha512-cD9+BPxlFSiIkGWknSgKdTMGZIzCtSIg/O7GJ1LoC+jGtUOBNBJYMn6FyEPRvdpphewYzaCuPsikrMkpdX303Q== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.9.tgz#bc60e4376fbe98631c01e63bc9ed0e039bffff5b" + integrity sha512-Z6IuWg9u0257dCVgc/x/zIKamqJhrmaOFuq3AYsSt6ZtyEHoyD5kxdXQUvEgBAd/Fn1b8tsX+VD9mB9al5306Q== + +"@unrs/resolver-binding-linux-riscv64-musl@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.9.tgz#dbd7bfb66e94ee733a30aa8969a90ed5e378dfaa" + integrity sha512-HpINrXLJVEpvkHHIla6pqhMAKbQBrY+2946i6rF6OlByONLTuObg65bcv3A38qV9yqJ7vtE0FyfNn68k0uQKbg== + +"@unrs/resolver-binding-linux-s390x-gnu@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.9.tgz#68fc7c5588804b45de2ee5e1c2c8603e80f0f81d" + integrity sha512-ZXZFfaPFXnrDIPpkFoAZmxzXwqqfCHfnFdZhrEd+mrc/hHTQyxINyzrFMFCqtAa5eIjD7vgzNIXsMFU2QBnCPw== + +"@unrs/resolver-binding-linux-x64-gnu@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.9.tgz#4d7570f04a4d4092b0bbcc2ee17b697fb99a5f88" + integrity sha512-EzeeaZnuQOa93ox08oa9DqgQc8sK59jfs+apOUrZZSJCDG1ZbtJINPc8uRqE7p3Z66FPAe/uO3+7jZTkWbVDfg== + +"@unrs/resolver-binding-linux-x64-musl@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.9.tgz#0efe3c2b2aad1036c2c2ba24071164f40b58b452" + integrity sha512-a07ezNt0OY8Vv/iDreJo7ZkKtwRb6UCYaCcMY2nm3ext7rTtDFS7X1GePqrbByvIbRFd6E5q1CKBPzJk6M360Q== + +"@unrs/resolver-binding-wasm32-wasi@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.9.tgz#dd321437716f11153cd7ed1e247ea87a608a60fd" + integrity sha512-d0fHnxgtrv75Po6LKJLjo1LFC5S0E8vv86H/5wGDFLG0AvS/0k+SghgUW6zAzjM2XRAic/qcy9+O7n/5JOjxFA== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.10" + +"@unrs/resolver-binding-win32-arm64-msvc@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.9.tgz#4777619b508e0c6949a5ef19b83d0457c18a7ef1" + integrity sha512-0MFcaQDsUYxNqRxjPdsMKg1OGtmsqLzPY2Nwiiyalx6HFvkcHxgRCAOppgeUuDucpUEf76k/4tBzfzPxjYkFUg== + +"@unrs/resolver-binding-win32-ia32-msvc@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.9.tgz#d3242799b0843f3f0e92af178345bb8bd8714a5d" + integrity sha512-SiewmebiN32RpzrV1Dvbw7kdDCRuPThdgEWKJvDNcEGnVEV3ScYGuk5smJjKHXszqNX3mIXG/PcCXqHsE/7XGA== + +"@unrs/resolver-binding-win32-x64-msvc@1.7.9": + version "1.7.9" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.9.tgz#d0eccd6808a5414d22fdcc8c6342887867e823c4" + integrity sha512-hORofIRZCm85+TUZ9OmHQJNlgtOmK/TPfvYeSplKAl+zQvAwMGyy6DZcSbrF+KdB1EDoGISwU7dX7PE92haOXg== + +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.14.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +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-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" + +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.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + +array-includes@^3.1.6, array-includes@^3.1.8: + version "3.1.9" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.9.tgz#1f0ccaa08e90cdbc3eb433210f903ad0f17c3f3a" + integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.0" + es-object-atoms "^1.1.1" + get-intrinsic "^1.3.0" + is-string "^1.1.1" + math-intrinsics "^1.1.0" + +array.prototype.findlast@^1.2.5: + 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.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz#cfa1065c81dcb64e34557c9b81d012f6a421c564" + integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-shim-unscopables "^1.1.0" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.flatmap@^1.3.2, array.prototype.flatmap@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + +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== + +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== + +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.10.0: + version "4.10.3" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.3.tgz#04145965ac7894faddbac30861e5d8f11bfd14fc" + integrity sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg== + +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + +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== + +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.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +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-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +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== + +caniuse-lite@^1.0.30001579: + version "1.0.30001720" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz#c138cb6026d362be9d8d7b0e4bcd0183a850edfd" + integrity sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g== + +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" + +chownr@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" + integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== + +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== + +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.0.0, 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== + +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + +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== + +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +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.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +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" + +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +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.1.3, 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" + +detect-libc@^2.0.3, detect-libc@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" + integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== + +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" + +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +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.18.1: + version "5.18.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" + integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0: + version "1.24.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328" + integrity sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.3.0" + get-proto "^1.0.1" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-negative-zero "^2.0.3" + is-regex "^1.2.1" + is-set "^2.0.3" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.1" + math-intrinsics "^1.1.0" + object-inspect "^1.13.4" + object-keys "^1.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.4" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + stop-iteration-iterator "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.19" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +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.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz#d1dd0f58129054c0ad922e6a9a1e65eef435fe75" + integrity sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.6" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + iterator.prototype "^1.1.4" + safe-array-concat "^1.1.3" + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3, es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" + integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== + dependencies: + hasown "^2.0.2" + +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" + +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@15.3.3: + version "15.3.3" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.3.3.tgz#356ca4b8647a6024c332260addcd261d3b4b6c6d" + integrity sha512-QJLv/Ouk2vZnxL4b67njJwTLjTf7uZRltI0LL4GERYR4qMF5z08+gxkfODAeaK7TiC6o+cER91bDaEnwrTWV6Q== + dependencies: + "@next/eslint-plugin-next" "15.3.3" + "@rushstack/eslint-patch" "^1.10.3" + "@typescript-eslint/eslint-plugin" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.31.0" + eslint-plugin-jsx-a11y "^6.10.0" + eslint-plugin-react "^7.37.0" + eslint-plugin-react-hooks "^5.0.0" + +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.10.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz#23dac32efa86a88e2b8232eb244ac499ad636db2" + integrity sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ== + dependencies: + "@nolyfill/is-core-module" "1.0.39" + debug "^4.4.0" + get-tsconfig "^4.10.0" + is-bun-module "^2.0.0" + stable-hash "^0.0.5" + tinyglobby "^0.2.13" + unrs-resolver "^1.6.2" + +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + 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.12.0" + hasown "^2.0.2" + is-core-module "^2.15.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + string.prototype.trimend "^1.0.8" + tsconfig-paths "^3.15.0" + +eslint-plugin-jsx-a11y@^6.10.0: + version "6.10.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483" + integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q== + dependencies: + aria-query "^5.3.2" + array-includes "^3.1.8" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "^4.10.0" + axobject-query "^4.1.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + hasown "^2.0.2" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.1" + +eslint-plugin-react-hooks@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3" + integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg== + +eslint-plugin-react@^7.37.0: + version "7.37.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" + integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.3" + array.prototype.tosorted "^1.1.4" + doctrine "^2.1.0" + es-iterator-helpers "^1.2.1" + estraverse "^5.3.0" + hasown "^2.0.2" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.9" + object.fromentries "^2.0.8" + object.values "^1.2.1" + prop-types "^15.8.1" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.12" + string.prototype.repeat "^1.0.0" + +eslint-scope@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.3.0.tgz#10cd3a918ffdd722f5f3f7b5b83db9b23c87340d" + integrity sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +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-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@^9: + version "9.28.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.28.0.tgz#b0bcbe82a16945a40906924bea75e8b4980ced7d" + integrity sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.20.0" + "@eslint/config-helpers" "^0.2.1" + "@eslint/core" "^0.14.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.28.0" + "@eslint/plugin-kit" "^0.3.1" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.3.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== + dependencies: + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + 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== + +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.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + 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-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + 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.8" + +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.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fdir@^6.4.4: + version "6.4.5" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.5.tgz#328e280f3a23699362f95f2e82acf978a0c0cb49" + integrity sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +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@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +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.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +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== + +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + +get-tsconfig@^4.10.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.10.1.tgz#d34c1c01f47d65a606c37aa7a177bc3e56ab4b2e" + integrity sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ== + dependencies: + resolve-pkg-maps "^1.0.0" + +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" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globalthis@^1.0.4: + 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" + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +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.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== + +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.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +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.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" + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +ignore@^7.0.0: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + 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== + +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-async-function@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== + dependencies: + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + +is-boolean-object@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" + integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-bun-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-2.0.0.tgz#4d7859a87c0fcac950c95e666730e745eae8bddd" + integrity sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ== + dependencies: + semver "^7.7.1" + +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.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +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.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + +is-generator-function@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== + dependencies: + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + 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.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +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-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +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.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== + dependencies: + call-bound "^1.0.3" + +is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +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, is-weakref@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" + integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== + dependencies: + call-bound "^1.0.3" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +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.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39" + integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== + dependencies: + define-data-property "^1.1.4" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + get-proto "^1.0.0" + has-symbols "^1.1.0" + set-function-name "^2.0.2" + +jiti@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + +"js-tokens@^3.0.0 || ^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" + +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-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.4: + 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.23" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" + integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== + +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" + +lightningcss-darwin-arm64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae" + integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ== + +lightningcss-darwin-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22" + integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA== + +lightningcss-freebsd-x64@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4" + integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig== + +lightningcss-linux-arm-gnueabihf@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908" + integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q== + +lightningcss-linux-arm64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009" + integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw== + +lightningcss-linux-arm64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe" + integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ== + +lightningcss-linux-x64-gnu@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157" + integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw== + +lightningcss-linux-x64-musl@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26" + integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ== + +lightningcss-win32-arm64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039" + integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA== + +lightningcss-win32-x64-msvc@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352" + integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg== + +lightningcss@1.30.1: + version "1.30.1" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.30.1.tgz#78e979c2d595bfcb90d2a8c0eb632fe6c5bfed5d" + integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg== + dependencies: + detect-libc "^2.0.3" + optionalDependencies: + lightningcss-darwin-arm64 "1.30.1" + lightningcss-darwin-x64 "1.30.1" + lightningcss-freebsd-x64 "1.30.1" + lightningcss-linux-arm-gnueabihf "1.30.1" + lightningcss-linux-arm64-gnu "1.30.1" + lightningcss-linux-arm64-musl "1.30.1" + lightningcss-linux-x64-gnu "1.30.1" + lightningcss-linux-x64-musl "1.30.1" + lightningcss-win32-arm64-msvc "1.30.1" + lightningcss-win32-x64-msvc "1.30.1" + +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.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== + +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" + +magic-string@^0.30.17: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +merge2@^1.3.0: + 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.4, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.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.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + 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@^7.0.4, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +minizlib@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.2.tgz#f33d638eb279f664439aa38dc5f91607468cb574" + integrity sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA== + dependencies: + minipass "^7.1.2" + +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.11, nanoid@^3.3.6: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +napi-postinstall@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.2.4.tgz#419697d0288cb524623e422f919624f22a5e4028" + integrity sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg== + +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@15.3.3: + version "15.3.3" + resolved "https://registry.yarnpkg.com/next/-/next-15.3.3.tgz#90ee73600af106796989136827a7a40f61dadd1f" + integrity sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw== + dependencies: + "@next/env" "15.3.3" + "@swc/counter" "0.1.3" + "@swc/helpers" "0.5.15" + busboy "1.6.0" + caniuse-lite "^1.0.30001579" + postcss "8.4.31" + styled-jsx "5.1.6" + optionalDependencies: + "@next/swc-darwin-arm64" "15.3.3" + "@next/swc-darwin-x64" "15.3.3" + "@next/swc-linux-arm64-gnu" "15.3.3" + "@next/swc-linux-arm64-musl" "15.3.3" + "@next/swc-linux-x64-gnu" "15.3.3" + "@next/swc-linux-x64-musl" "15.3.3" + "@next/swc-win32-arm64-msvc" "15.3.3" + "@next/swc-win32-x64-msvc" "15.3.3" + sharp "^0.34.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-inspect@^1.13.3, object-inspect@^1.13.4: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +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.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +object.entries@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.9.tgz#e4770a6a1444afb61bd39f984018b5bede25f8b3" + integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-object-atoms "^1.1.1" + +object.fromentries@^2.0.8: + 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.3: + 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.values@^1.1.6, object.values@^1.2.0, object.values@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.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" + +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + dependencies: + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.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@^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" + +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" + +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-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-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== + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + +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.41: + version "8.5.4" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.4.tgz#d61014ac00e11d5f58458ed7247d899bd65f99c0" + integrity sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +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== + +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" + +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== + +qrcode.react@*, qrcode.react@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-4.2.0.tgz#1bce8363f348197d145c0da640929a24c83cbca3" + integrity sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA== + +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@^19.0.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.1.0.tgz#133558deca37fa1d682708df8904b25186793623" + integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== + dependencies: + scheduler "^0.26.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@^19.0.0: + version "19.1.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.1.0.tgz#926864b6c48da7627f004795d6cce50e90793b75" + integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== + +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" + +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.22.4: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.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" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +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.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" + +safe-push-apply@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== + dependencies: + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +scheduler@^0.26.0: + version "0.26.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.26.0.tgz#4ce8a8c2a2095f13ea11bf9a445be50c555d6337" + integrity sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA== + +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.6.0, semver@^7.7.1, semver@^7.7.2: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + +set-function-length@^1.2.2: + 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.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" + +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== + dependencies: + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + +sharp@^0.34.1: + version "0.34.2" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.2.tgz#648bd639854dbe48047b0b420213c186d036b32d" + integrity sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg== + dependencies: + color "^4.2.3" + detect-libc "^2.0.4" + semver "^7.7.2" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.2" + "@img/sharp-darwin-x64" "0.34.2" + "@img/sharp-libvips-darwin-arm64" "1.1.0" + "@img/sharp-libvips-darwin-x64" "1.1.0" + "@img/sharp-libvips-linux-arm" "1.1.0" + "@img/sharp-libvips-linux-arm64" "1.1.0" + "@img/sharp-libvips-linux-ppc64" "1.1.0" + "@img/sharp-libvips-linux-s390x" "1.1.0" + "@img/sharp-libvips-linux-x64" "1.1.0" + "@img/sharp-libvips-linuxmusl-arm64" "1.1.0" + "@img/sharp-libvips-linuxmusl-x64" "1.1.0" + "@img/sharp-linux-arm" "0.34.2" + "@img/sharp-linux-arm64" "0.34.2" + "@img/sharp-linux-s390x" "0.34.2" + "@img/sharp-linux-x64" "0.34.2" + "@img/sharp-linuxmusl-arm64" "0.34.2" + "@img/sharp-linuxmusl-x64" "0.34.2" + "@img/sharp-wasm32" "0.34.2" + "@img/sharp-win32-arm64" "0.34.2" + "@img/sharp-win32-ia32" "0.34.2" + "@img/sharp-win32-x64" "0.34.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-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +source-map-js@^1.0.2, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +stable-hash@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.5.tgz#94e8837aaeac5b4d0f631d2972adef2924b40269" + integrity sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA== + +stop-iteration-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== + dependencies: + es-errors "^1.3.0" + internal-slot "^1.1.0" + +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.prototype.includes@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92" + integrity sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + +string.prototype.matchall@^4.0.12: + version "4.0.12" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" + integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + gopd "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + regexp.prototype.flags "^1.5.3" + set-function-name "^2.0.2" + side-channel "^1.1.0" + +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + 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-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-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.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499" + integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA== + dependencies: + client-only "0.0.1" + +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@4.1.8, tailwindcss@^4: + version "4.1.8" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.8.tgz#5d66d095ee7d82f03d6dbc6158bc248e064a5c05" + integrity sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og== + +tapable@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.2.tgz#ab4984340d30cb9989a490032f086dbb8b56d872" + integrity sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== + +tar@^7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" + integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== + dependencies: + "@isaacs/fs-minipass" "^4.0.0" + chownr "^3.0.0" + minipass "^7.1.2" + minizlib "^3.0.1" + mkdirp "^3.0.1" + yallist "^5.0.0" + +tinyglobby@^0.2.13: + version "0.2.14" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" + integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" + +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@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" + integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== + +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, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +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" + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + +typescript@^5: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unrs-resolver@^1.6.2: + version "1.7.9" + resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.7.9.tgz#13b0201b9dc501724793467ff529a6a8068b3efa" + integrity sha512-hhFtY782YKwpz54G1db49YYS1RuMn8mBylIrCldrjb9BxZKnQ2xHw7+2zcl7H6fnUlTHGWv23/+677cpufhfxQ== + dependencies: + napi-postinstall "^0.2.2" + optionalDependencies: + "@unrs/resolver-binding-darwin-arm64" "1.7.9" + "@unrs/resolver-binding-darwin-x64" "1.7.9" + "@unrs/resolver-binding-freebsd-x64" "1.7.9" + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.7.9" + "@unrs/resolver-binding-linux-arm-musleabihf" "1.7.9" + "@unrs/resolver-binding-linux-arm64-gnu" "1.7.9" + "@unrs/resolver-binding-linux-arm64-musl" "1.7.9" + "@unrs/resolver-binding-linux-ppc64-gnu" "1.7.9" + "@unrs/resolver-binding-linux-riscv64-gnu" "1.7.9" + "@unrs/resolver-binding-linux-riscv64-musl" "1.7.9" + "@unrs/resolver-binding-linux-s390x-gnu" "1.7.9" + "@unrs/resolver-binding-linux-x64-gnu" "1.7.9" + "@unrs/resolver-binding-linux-x64-musl" "1.7.9" + "@unrs/resolver-binding-wasm32-wasi" "1.7.9" + "@unrs/resolver-binding-win32-arm64-msvc" "1.7.9" + "@unrs/resolver-binding-win32-ia32-msvc" "1.7.9" + "@unrs/resolver-binding-win32-x64-msvc" "1.7.9" + +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" + +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + 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.16, which-typed-array@^1.1.19: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + 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== + +yallist@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" + integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== + +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==